pax_global_header00006660000000000000000000000064147475175760014541gustar00rootroot0000000000000052 comment=4dda702cb81cf96155e614299aab6180ff09740e liquid-dsp-1.7.0/000077500000000000000000000000001474751757600136215ustar00rootroot00000000000000liquid-dsp-1.7.0/.codecov.yml000066400000000000000000000011661474751757600160500ustar00rootroot00000000000000# For more configuration details: # https://docs.codecov.io/docs/codecov-yaml # Check if this file is valid by running in bash: # curl -X POST --data-binary @.codecov.yml https://codecov.io/validate # coverage configuration coverage: range: 70..90 round: down precision: 3 status: project: default: target: 75 threshold: 5 ignore: - "**/autotest/*" - "**/examples/*" - "**/sandbox/*" - "**/scripts/*" - "**/src/*/bench/*" - "**/src/*/tests/*" # parse coverage reports parsers: gcov: branch_detection: conditional: yes loop: yes method: no macro: no liquid-dsp-1.7.0/.github/000077500000000000000000000000001474751757600151615ustar00rootroot00000000000000liquid-dsp-1.7.0/.github/workflows/000077500000000000000000000000001474751757600172165ustar00rootroot00000000000000liquid-dsp-1.7.0/.github/workflows/core.yml000066400000000000000000000025771474751757600207040ustar00rootroot00000000000000name: Core C CI on: workflow_dispatch: pull_request: push: jobs: standard: strategy: fail-fast: false matrix: runs-on: [ubuntu-latest, macos-latest] name: "💦 ${{ matrix.runs-on }}" runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v4 - name: setup (macos) if: runner.os == 'macos' run: | brew update brew install cmake - name: setup (linux) if: runner.os == 'Linux' run: | sudo apt-get update --fix-missing sudo apt-get install -y --no-install-recommends cmake valgrind time curl #- name: Setup libfec # run: git clone https://github.com/jgaeddert/libfec.git && cd libfec && ./configure && make && sudo make install - name: build run: | mkdir build cd build cmake .. make -j2 - name: check run: | cd build ./xautotest -v -o autotest.json - name: install run: | cd build sudo make install - name: check installation (macos) if: runner.os == 'macos' run: | gcc -Wall -O2 -rpath /usr/local/lib -o liquid_linker_test scripts/liquid_linker_test.c -lm -lc -lliquid ./liquid_linker_test - name: check installation (linux) if: runner.os == 'Linux' run: | sudo ldconfig make -f scripts/liquid_linker_test.mk liquid-dsp-1.7.0/.github/workflows/coverage.yml000066400000000000000000000024631474751757600215410ustar00rootroot00000000000000name: Code Coverage CI on: workflow_dispatch: pull_request: push: branches: - master - cmake-dev - coverage-dev - release-dev jobs: standard: strategy: fail-fast: false matrix: runs-on: [ubuntu-latest] name: "💦 ${{ matrix.runs-on }}" runs-on: ${{ matrix.runs-on }} steps: - uses: actions/checkout@v2 - name: Setup environment (macOS) if: runner.os == 'macos' run: | brew update brew install cmake virtualenv - name: Setup environment (Linux) if: runner.os == 'Linux' run: | sudo apt-get install -y --no-install-recommends build-essential virtualenv #- name: Setup libfec # run: git clone https://github.com/jgaeddert/libfec.git && cd libfec && ./configure && make && sudo make install - name: build run: | mkdir build cd build cmake -DBUILD_AUTOTESTS=ON -DCOVERAGE=ON -DBUILD_BENCHMARKS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_SANDBOX=OFF .. make -j4 - name: check run: | cd build ./xautotest -q -o autotest.json - name: upload report to codecov with github action uses: codecov/codecov-action@v4 with: fail_ci_if_error: true verbose: true token: ${{ secrets.CODECOV_TOKEN }} liquid-dsp-1.7.0/.github/workflows/platformio.yml000066400000000000000000000011271474751757600221160ustar00rootroot00000000000000name: PlatformIO CI on: [push] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] #, macos-latest] #, windows-latest] example: [examples/platformio_example.c] steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 - name: Install PlatformIO run: | python3 -m pip install --upgrade pip python3 -m pip install --upgrade platformio - name: Run PlatformIO run: pio ci --lib="." --board=pico env: PLATFORMIO_CI_SRC: ${{ matrix.example }} liquid-dsp-1.7.0/.gitignore000066400000000000000000000013121474751757600156060ustar00rootroot00000000000000# ignore all object files *.a *.ar *.d *.dylib *.dSYM *.gcda *.gcno *.o *.so *~ build # ignore swap files for vim editing *.swp # build objects autom4te.cache aclocal.m4 # ignore all auto-generated targets autotest_include.h benchmark benchmark_include.h bench/fftbench configure config.h config.h.in config.h.in~ config.log config.status makefile xautotest *.m autotest.json autotest/logs/*.bin autotest/logs/*.gnu readme.* liquid_linker_test # miscellany octave-core *.tar *.gz .DS_Store # gentab programs src/fec/gentab/*_gentab src/utility/gentab/*_gentab # gentab output sources src/fec/gentab/reverse_byte.c src/utility/gentab/count_ones.c # sandbox sandbox/*_test sandbox/*_example sandbox/*_gentab liquid-dsp-1.7.0/.gitlab-ci.yml000066400000000000000000000054621474751757600162640ustar00rootroot00000000000000# gitlab ci/cd pipeline configuration image: debian stages: - build - test variables: DEBIAN_FRONTEND: noninteractive before_script: - apt-get -qq update - apt-get -qq install -y --no-install-recommends build-essential cmake valgrind time curl # build main library and run test programs build: stage: build script: - rm -rf build - mkdir build - cd build - cmake -DBUILD_AUTOTESTS=ON -DBUILD_BENCHMARKS=ON -DBUILD_EXAMPLES=ON -DBUILD_SANDBOX=ON -DCOVERAGE=OFF .. - make -j4 - ./benchmark -q -o benchmark.json -f - ./xautotest -q -o autotest.json #- make check-doc # compile and run documenation checks (e.g. example code in README) - make install - ldconfig - cd .. - make -f scripts/liquid_linker_test.mk artifacts: paths: - build/benchmark.json - build/autotest.json # generate coverage report and push to codecov.io coverage: stage: test script: - rm -rf build - mkdir build - cd build - cmake -DBUILD_AUTOTESTS=ON -DCOVERAGE=ON -DBUILD_BENCHMARKS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_SANDBOX=OFF .. - make -j4 - ./xautotest -q -o autotest.json - cd .. - apt-get -qq install -y --no-install-recommends virtualenv - virtualenv coverage - source coverage/bin/activate - pip install codecov-cli gcovr==7.0 - gcovr --version - gcovr --filter="src/.*/src/.*.c" --print-summary | tee coverage.out - codecovcli --version - codecovcli upload-process -t $CODECOV_TOKEN --git-service gitlab --slug jgaeddert/liquid-dsp coverage: '/lines: \d+\.\d+%/' artifacts: paths: - coverage.out - build/autotest.json # test building using legacy environment legacy: stage: test script: - apt-get -qq install -y --no-install-recommends automake autoconf - ./bootstrap.sh - ./configure - make -j4 - make check-doc - make install - ldconfig - make -f scripts/liquid_linker_test.mk # test cross-compiling with platformio platformio: stage: test script: - apt-get -qq install -y --no-install-recommends virtualenv - virtualenv platformio - source platformio/bin/activate - pip install platformio - pio ci --lib="." --board=pico examples/platformio_example.c # compile and run all example programs, timing how long each takes to run .examples: stage: test script: - make -j4 examples - echo '' > time.txt - ls examples/*_example | sed -E "s#(.*)#echo '\1' >> time.txt; { time -p ./\1 ; } 2>> time.txt#g" > run_examples.sh - /bin/sh run_examples.sh artifacts: paths: [run_examples.sh, time.txt] # compile and run all autotest programs with valgrind .autotest-memcheck: stage: test script: - make -j4 xautotest - mkdir valgrind - ./scripts/valgrind_eval.py -output valgrind -test 881 artifacts: paths: [valgrind/*] liquid-dsp-1.7.0/.travis.yml000066400000000000000000000013521474751757600157330ustar00rootroot00000000000000language: C matrix: include: - os: linux compiler: gcc env: BUILD_CXX=off - os: osx compiler: clang env: BUILD_CXX=off script: - git clone https://github.com/quiet/libcorrect.git - cd libcorrect - mkdir build - cd build - set -e - cmake -DCMAKE_BUILD_TYPE=Release .. && make && make shim - sudo make install - set +e - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo ldconfig; fi - cd ../.. - set -e - ./bootstrap.sh - ./configure - make - make examples - make benchmark - make xautotest - ./xautotest -R 0 # execute with a specific random seed - ./xautotest # execute with a random seed based on time liquid-dsp-1.7.0/CHANGELOG.md000066400000000000000000000457771474751757600154560ustar00rootroot00000000000000# Changelog ## 1.7.0 - 2025-02-01 Version 1.7.0 includes support for the [CMake](https://cmake.org) build system. While the existing autotools environment will be supported for a time, this will be removed in a future release. This version also includes many changes to improve [testing coverage](https://app.codecov.io/gh/jgaeddert/liquid-dsp/) across all interfaces, and make the interfaces across objects consistent. * build - migrated to the [CMake](https://cmake.org) build system, including building examples, sandbox programs, benchmarks, autotests, and detecting SIMD instruction extensions. - increased testing across the board including automated memory validation with [valgrind](https://valgrind.org) - detected and fixed memory leaks for numerous methods and testing harnesses including `bessel_azpdf` (thanks, @andreasbombe), `ofdmflexframesync`, `qdsync`, `qs1dsearch` (thanks, @nowls), `framesync64`, `eqrls`, and `fskdem` - added new `LIQUID_ENOCONV` error type to identify errors where algorithms did not converge - added new `LIQUID_ENOIMP` error type to identify methods that are not yet implemented - replaced warnings with internal error handling for many existing object methods - fixed SONAME not set in shared library (thanks again, @andreasbombe) - migrated README from markdown to re-structured text * framing - added more description to method definitions such as qpacketmodem and qdetector - dsssframe64: extended functionality to use qdsync, added standard methods such as copy(), added interfaces for specifying thresholds, reduced default spreading gain * filter - firinterp: added flush() method to run zeros through filter - rresamp: allow for default bandwidth with an input of -1 * nco - fixed issue where frequency was being set improperly, added more extensive testing - improved the NCO object with VCO precision (thanks, @ArtemPisarenko) * random - added more extensive testing for various distributions to ensure values are generated properly ## 1.6.0 - 2023-06-19 Version 1.6.0 includes a new qdsync object to greatly simplify the frame synchronization process in liquid, allowing for both detection and channel impairment correction with a simplified interface. Additionally, code coverage has been increased to 85% across the entire project, with numerous bug fixes, stability improvements, and massive testing enhancements. From an "architectural" standpoint, objects have been migrated to use standard methods for consistency. * build - increased code coverage to 85% globally across entire project. This is the single largest effort included in this version and touches most modules in some way, most particularly the framing objects - cleaning build to remove compiler warnings (e.g. unused variables) - stripped version number off archive * dotprod - added support for AVX512-F (thanks, @vankxr!) * framing - added numerous tests to increase coverage to 84% - framesync64: using new qdsync object for simplified operation - qdsync: new frame detector and synchronizer to much more easily support frame processing. The object not only detects the frame, but also provides an initial carrier frequency, phase, and timign offset, and also corrects for these impairments, passing the results to the user in a clean callback function. * modem - cpfskmod: increasing phase stability for long runs * multichannel - added numerous tests to increase coverage to 88% * optim - added numerous tests to increase coverage to 92% * sequence - msequence: extended support for state variables up to m=31, reversed order for generator polynomial and internal state definition to be more consistent with literature and readily-available genpolys ## 1.5.0 - 2022-11-20 This release includes substantially improved testing coverage, deep copy() methods for nearly all objects, improved speed, and resolves a number of issues and pull requests. * build - added support for PlatformIO (https://platformio.org) for embeedded development (thanks, @jcw!) - incorporated recursive copy() methods to objects to facilitate c++ copy constructors for bindings; now all objects can be deep copied to a new object with their entire memory and state preserved - added convenience method to malloc and copy memory arrays - improved support for error codes across objects and methods - cleaned up spelling errors across project (thanks, @nowls!) - scrubbed function argument variable names to avoid underscore followed by a capital letter, causing trouble with pre-compiler processing - added basic test to check linking to installed library, incorporating into CI/CD pipelines - added more example programs * autotest - increased coverage testing (81% across entire project) - added the ability to "hammer" a particular test by running repeatedly on incremental seeds to assess specific edge cases (e.g. with random data) - added timer to show execution time for each test and identify areas for speed improvements - added methods for testing spectral response of various fields - added special directory for storing output logs: autotest/logs/ * benchmark - replacing old C-based benchmark comparison with simpler python version * dotprod - added support for AVX SIMD in vector dot products (thanks, @vankxr!) * fft - adding macro to allow for aligned memory allocation if FFTW is used (thanks, @nowls!) * filter - added new halfband filter design using Parks-McClellan algorithm and qs1dsearch method to provide as exact a specification as possible - added method to retrieve filter response from coefficients array - dds: adding methods to get/set scale - firhilb, iirhilb: added block processing method - msresamp, resamp: adding method to provide the exact number of output samples with provided input size - msresamp2, resamp2: using better halfband filter design for exact user specifications - resamp: adding methods to get/set scale, fixing filter bank resolution (was hard-coded, now respects user configuration) * framing - framesync64: added methods to set callback and userdata (context) fields, adding support for exporting debugging files for post-analysis as well as python script for processing, adding better estimate of error vector magnitude - msource: added convenience method to recall number of samples generated by each source - ofdmflexframesync: added methods to set callback and userdata (context) fields - qpacketmodem: returning much better estimate of error vector magnitude - qsource: fixed issue with carrier frequency adjustment * optim - added qs1dsearch object to perform quad-section 1-dimensional search: similar to bisection search, but to find potentially non-continuous minimum/maximum of function ## 1.4.0 - 2022-02-03 * autotest - automated code coverage testing (72%) * build - incorporated error handling in most methods with integer-based return value * agc - added interface to check if AGC is locked or not * buffer - cbuffer: added method to check if buffer is empty * dotprod - included methods to create/recreate object in reverse order * equalization - eqlms: added convenience methods for copying coefficients and running as a decimator * fft - spgram: adding convenience methods for getting/setting properties - spwaterfall: adding convenience methods for getting/setting properties * filter - new direct digital synthesis (DDS) family of objects which allows cascaded half-band interpolation/decimation with arbitrary frequency translation - new fractional delay (fdelay) family of objects which allow for adjustable large fractional delays - firdecim: adding convenience method to get decimation rate - firfilt: adding convenience methods to get/copy coefficients as well as create object using firdespm algorithm - firinterp: adding convenience methods for new ways to create object as well as getting object properties - firpfb: adding convenience methods to create default object, write samples - resamp2: adding methods to get/set output scale - rresamp: adding methods to operate with block execution * framing - new arbitrary rate symstreamr object (derived from symstream family) - framesync64: adding methods for getting/resetting frame data statistics as well as getting/setting detection threshold - gmskframegen/gmskframesync: extending methods to support easier operation, getting/resetting frame data statistics, more control over parameters in create methods - ofdmflexframesync: adding methods to get/reset frame data statistics - qdetector: adding method to get threshold - qpilotsync: adding method to get error vector magnitude - symstream: adding convenience methods for getting properties - symtrack: adding convenience methods for getting/setting properties * math - adding `liquid_` prefix to winodowing functions while supporting backwards compatibility with older methods - adding `liquid_` prefix to internal polynomial functions, using common double-precision method for finding polynomial roots * multichannel - firpfbch2: adding convenience methods to get object properties * modem - modem: adding type extension for more consistency: `modem` -> `modemcf`, supporting backwards compatibility with API shim ## 1.3.1 - 2019-07-28 * autotest - runs with random seeds (based on time) for diveristy - output .json file for post-analysis * build - cleaned up compiler warnings across most platforms - incorporated continuous integration script - compact header APIs across all interfaces in liquid.h - consistent build across Linux and macOS * agc - added more convenience methods, improved autotest stability * fft - spwaterfall less verbose with more convenience methods * filter - new rresamp family of objects to implement rational rate resampling; very useful for fixed buffer sizes - resamp now uses fixed-point phase for faster computation - fixed issues with msresamp2 ordering to have expected roll-off performance - added notch filter design option for firfilt (with autotest) * framing - completely reworked msource family of objects to use firpfbch2 family of objects for computationally efficient - added preliminary fskframe generator and synchronizer objects * math - improved functions for speed, is_prime() - improved stability and consistency of root-finding algorithms * multichannel - added new firpfbchr family of objects for arbitrarily setting number of channels and down-sampling rates * modem - refactored objects for amplitude modulation/demodulation to use Hilbert transform, added autotest scripts * nco - improving consistency across platforms ## 1.3.1 - 2017-10-23 * improved selection of SSE/MMX extension flags for gcc * agc - adding squelch functionality back into gain control object * filter - adding callback function for Parks-McClellan algorithm to allow generic filter prototyping - fixed double-free bug in iirfilt * fft - adding new spwaterfall family of objects for generating waterfall plot and automatically down-size as input sample size grows * sequence - fixed issue with order of operations causing inconsistent behavior across different platforms ## 1.3.0 - 2016-12-30 * New MIT/X11 license (https://opensource.org/licenses/MIT) * agc (automatic gain control) - major code scrub, improved reliability, simplified interface - block-level operation * buffer - new cbuffer objects for dynamic-sized circular buffering * channel - new module to define certain channel emulation objects - new functionality includes carrier frequency/phase offsets, (time-varying) multi-path, shadowing, and additive noise * dotprod - adding method to compute x^T * x of a vector (sum of squares) * equalization - improved interface for LMS and RLS equalizers - simplified methods to support blind operation * fec (forward error correctino) - interleaver and packetizer moved from the framing to the fec module - packetizer now includes data whitening * fft (fast Fourier transform) - general speed improvements for one-dimensional FFTs - completely reimplemented spgram (spectral periodogram) objects to include both complex and real-values amples with simpler interface - reimplemented asgram (ASCII spectral periodogram) objects * filter - additional prototype create methods, block execution - added new fftfilt family of objects to realize linear filter with fast Fourier transforms - interp family renamed to firinterp, new iirinterp family - decim family renamed to firdecim, new iirdecim family - add linear interpolation for arbitrary resamp output - new multi-stage half-band resampler family - symsync: improved stability, added rate adjustment to help pull in sample rate offsets - added autotests for validating performance of both the resamp and msresamp objects * framing - added `framedatastats` object for counting statistics across different framing objects (e.g. number of total bytes received) - adding generic callback function definition for all framing structures - qpacketmodem: new object to easily combine modulating and encoding; buffer of data in, modulated and encoded samples out - qpilotgen/qpilotsync: new objects to add and synchronize pilot symbols to modulated symbols to recover carrier frequency/phase, and gain - framing objects: frame64, flexframe now use qpacketmodem, qpilotgen, and qpilotsync objects for unified interface and vastly improved performance - flexframe: vastly simplified interface - qdetector: new family for pre-demodulator synchronizion and detection - moved interleaver and packetizer objects to `fec` module - symstream: new family for generating random stream of modulated samples - msource: new family for generating multiple signals for a single source, including tones, noise, modulated symbols - symtrack: new family for tracking a stream of symbols and recovering signal level, timing, carrier frequency/phase without pilots * math - new windowing methods (e.g. 7-term Blackman-harris window) * matrix - adding smatrix family of objects (sparse matrices) - improving linear solver methods (roughly doubled speed) * modem - re-organizing internal linear modem code (no interface change) - freqmod/freqdem: new interface, block-level execution for analog FM - cpfskmod/cpfskdem: new family for generic non-linear continuous-phase frequency-shift modulation (e.g. minimum-shift keying) - fskmod/fskdem: new family for non-coherent frequency-shift keying modulation, often with many samples per symbol (e.g. 256-FSK) * multicarrier - adding OFDM framing option for window tapering - simplfying OFDM framing for generating preamble symbols (all generated OFDM symbols are the same length) - adding run-time option for debugging ofdmframesync - adding method for initializing subcarriers with frequency range * nco (numerically-controlled oscillator) - general performance improvements, adding block-level execution * optim - gradsearch (gradient search) uses internal linesearch for significant speed increase and better reliability - gradsearch interface greatly simplified * utility - build no longer auto-generates tables at compile time (helps with cross compilation) * vector - new module to simplify basic vector operations * miscellany - documentation moved from core repository to website - global header file (`liquid.h`) include more structured source - consistent naming of reset() methods for most objects ## 1.2.0 - 2012-04-26 * dotprod - leveraging SIMD extensions for vector operations (SSE2, SSE3) * fft - completely re-structured internal transform strategy including Cooley-Tukey mixed-radix algorithm, Rader algorithm for FFTs of prime length, and specific codelets for small-size transforms. * math - new modular arithmetic methods (prime factor, totient, etc.) * modem - new API creates linear modem objects with one argument, e.g. LIQUID_MODEM_QAM16 - new type definitions for analog modems ## 1.1.0 - 2011-12-23 * build - simplifying build environment by explicitly defining object dependencies (no longer auto-generated; much faster now) * documentation - new tutorials (ofdmflexframe) - sections on new objects/methods (msresamp, gmsk filter design, soft-decision demodulation) - adding useful figures (polyfit-lagrange, symsync) - adding BER performance plots for new FEC schemes - adding BER performance plots for sqam32 and sqam128 * agc - fixing scaling issues - improving computation speed - simplifying interface with a single, unified design model * equalization - adding support for decision-directed equalizers * fec - adding soft decoding (when available) for forward error-correction schemes; generally improves performance by about 2 dB Eb/N0 - adding half-rate Golay(24,12) code - adding SEC-DED codes: (22,16), (39,32), (72,64) * filter - firdes: adding Nyquist prototyping design method - firdes: adding new GMSK receive filter design method - interp: porting to efficient polyphase filterbank implementation, adding prototype create() method - adding multi-stage resampler for efficient decimation and interpolation * framing - adding ofdmflexframe family of objects capable of defining which subcarriers are nulls/pilots/data, and easily loading data into frames. Very similar to 'flexframe' in usage. - supporting soft packet decoding (interleaving, etc.) - adding gmskframe generator and synchronizer object; simple, reliable * matrix - adding Cholesky factorization A = R^T * R (for positive definite matrices) - adding conjugate gradient solver (for positive definite matrices) * modem - adding simple on/off keying (OOK) type - adding 256-APSK type (6,18,32,36,46,54,64) - adding 'square' (cross) 32-, 128-QAM types - adding 'optimal' 64-, 128-, and 256-QAM constellations - improved speed of most schemes' modulate/demodulate implementations - adding soft-decision (log-likelihood ratio) demodulation - adding GMSK modulation/demodulation with improved filter design * multicarrier - ofdmframe: improving synchronization and reliability in interference environments, enabling squelch, improving equalization * optim - simplified interface to gradient search ## [1.0.0] - 2011-04-29 _First release._ liquid-dsp-1.7.0/CMakeLists.txt000066400000000000000000001146221474751757600163670ustar00rootroot00000000000000# cmake build file for liquid-dsp cmake_minimum_required(VERSION 3.10) # run custom command to parse version number from include/liquid.h execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/version.sh WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE LIQUID_VERSION) # project definition project(liquid VERSION ${LIQUID_VERSION} LANGUAGES C CXX) # ---------------------------------------- options ---------------------------------------- option(BUILD_EXAMPLES "Set to ON to build examples" ON) option(BUILD_AUTOTESTS "Set to ON to build autotest program" ON) option(BUILD_BENCHMARKS "Set to ON to build benchmark program" ON) option(ENABLE_SIMD "Set to ON to build SIMD extensions" ON) option(BUILD_SANDBOX "Set to ON to build sandbox programs" OFF) option(BUILD_DOC "Set to ON to build documentation" OFF) option(COVERAGE "Set to ON to build with code coverage" OFF) #option(PROFILE "Set to ON to build with profiling" OFF) if(COVERAGE) set(CMAKE_BUILD_TYPE "Debug") endif(COVERAGE) # target_sources() command converts relative paths to absolute. cmake_policy(SET CMP0076 NEW) set(LIBNAME liquid) # require a C99 compiler for all targets set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ version selection") # or 11, 14, 17, 20 set(CMAKE_CXX_STANDARD_REQUIRED ON) # optional, ensure standard is supported #set(CMAKE_CXX_EXTENSIONS OFF) # optional, keep compiler extensions off include (CheckIncludeFile) include (CheckFunctionExists) include (CheckLibraryExists) include (CheckSymbolExists) # check for hardware acceleration include(cmake/FindSIMD.cmake) # TODO: check for FFTW # global flags if (MSVC) # warning level 4 add_compile_options(/W4) else() # additional warnings add_compile_options(-Wall -fPIC -O3 -Wno-deprecated -Wno-deprecated-declarations) endif() include (CheckTypeSize) check_type_size(int SIZEOF_INT LANGUAGE C) configure_file(cmake/config.h.cmake config.h) # this file can only use the @VARIABLE@ syntax #configure_file(cmake/version.c.in ${PROJECT_BINARY_DIR}/src/version.c @ONLY) #target_include_directories(test PRIVATE include) include_directories(include .) # ---------------------------------------- main sources ---------------------------------------- add_library(agc OBJECT src/agc/src/agc_crcf.c src/agc/src/agc_rrrf.c) add_library(audio OBJECT src/audio/src/cvsd.c) add_library(buffer OBJECT src/buffer/src/bufferf.c src/buffer/src/buffercf.c) add_library(channel OBJECT src/channel/src/channel_cccf.c) add_library(dotprod OBJECT) add_library(equalization OBJECT src/equalization/src/equalizer_cccf.c src/equalization/src/equalizer_rrrf.c) add_library(fec OBJECT src/fec/src/crc.c src/fec/src/fec.c src/fec/src/fec_conv.c src/fec/src/fec_conv_poly.c src/fec/src/fec_conv_pmatrix.c src/fec/src/fec_conv_punctured.c src/fec/src/fec_golay2412.c src/fec/src/fec_hamming74.c src/fec/src/fec_hamming84.c src/fec/src/fec_hamming128.c src/fec/src/fec_hamming1511.c src/fec/src/fec_hamming3126.c src/fec/src/fec_hamming128_gentab.c src/fec/src/fec_pass.c src/fec/src/fec_rep3.c src/fec/src/fec_rep5.c src/fec/src/fec_rs.c src/fec/src/fec_secded2216.c src/fec/src/fec_secded3932.c src/fec/src/fec_secded7264.c src/fec/src/interleaver.c src/fec/src/packetizer.c src/fec/src/sumproduct.c) add_library(fft OBJECT src/fft/src/fftf.c src/fft/src/spgramcf.c src/fft/src/spgramf.c src/fft/src/fft_utilities.c) add_library(filter OBJECT src/filter/src/bessel.c src/filter/src/butter.c src/filter/src/cheby1.c src/filter/src/cheby2.c src/filter/src/ellip.c src/filter/src/filter_rrrf.c src/filter/src/filter_crcf.c src/filter/src/filter_cccf.c src/filter/src/firdes.c src/filter/src/firdespm.c src/filter/src/firdespm_halfband.c src/filter/src/fnyquist.c src/filter/src/gmsk.c src/filter/src/group_delay.c src/filter/src/hM3.c src/filter/src/iirdes.pll.c src/filter/src/iirdes.c src/filter/src/lpc.c src/filter/src/rcos.c src/filter/src/rkaiser.c src/filter/src/rrcos.c) add_library(framing OBJECT src/framing/src/bpacketgen.c src/framing/src/bpacketsync.c src/framing/src/detector_cccf.c src/framing/src/dsssframe64gen.c src/framing/src/dsssframe64sync.c src/framing/src/dsssframegen.c src/framing/src/dsssframesync.c src/framing/src/framedatastats.c src/framing/src/framesyncstats.c src/framing/src/framegen64.c src/framing/src/framesync64.c src/framing/src/framingcf.c src/framing/src/framing_rrrf.c src/framing/src/framing_crcf.c src/framing/src/framing_cccf.c src/framing/src/flexframegen.c src/framing/src/flexframesync.c src/framing/src/fskframegen.c src/framing/src/fskframesync.c src/framing/src/gmskframegen.c src/framing/src/gmskframesync.c src/framing/src/ofdmflexframegen.c src/framing/src/ofdmflexframesync.c src/framing/src/qpilotgen.c src/framing/src/qpilotsync.c) add_library(math OBJECT src/math/src/poly.c src/math/src/polyc.c src/math/src/polyf.c src/math/src/polycf.c src/math/src/math.c src/math/src/math.bessel.c src/math/src/math.gamma.c src/math/src/math.complex.c src/math/src/math.trig.c src/math/src/modular_arithmetic.c src/math/src/poly.findroots.c src/math/src/windows.c) add_library(matrix OBJECT src/matrix/src/matrix.c src/matrix/src/matrixf.c src/matrix/src/matrixc.c src/matrix/src/matrixcf.c src/matrix/src/smatrix.common.c src/matrix/src/smatrixb.c src/matrix/src/smatrixf.c src/matrix/src/smatrixi.c) add_library(modem OBJECT src/modem/src/ampmodem.c src/modem/src/fskdem.c src/modem/src/fskmod.c src/modem/src/gmskdem.c src/modem/src/gmskmod.c src/modem/src/modem.shim.c src/modem/src/modemcf.c src/modem/src/modem_utilities.c src/modem/src/modem_apsk_const.c src/modem/src/modem_arb_const.c) add_library(multichannel OBJECT src/multichannel/src/firpfbch_crcf.c src/multichannel/src/firpfbch_cccf.c src/multichannel/src/ofdmframe.common.c src/multichannel/src/ofdmframegen.c src/multichannel/src/ofdmframesync.c) add_library(nco OBJECT src/nco/src/nco_crcf.c src/nco/src/nco.utilities.c) add_library(optim OBJECT src/optim/src/chromosome.c src/optim/src/gasearch.c src/optim/src/gradsearch.c src/optim/src/optim.common.c src/optim/src/qnsearch.c src/optim/src/qs1dsearch.c src/optim/src/utilities.c) add_library(quantization OBJECT src/quantization/src/compand.c src/quantization/src/quantizercf.c src/quantization/src/quantizerf.c src/quantization/src/quantizer.inline.c) add_library(random OBJECT src/random/src/rand.c src/random/src/randn.c src/random/src/randexp.c src/random/src/randweib.c src/random/src/randgamma.c src/random/src/randnakm.c src/random/src/randricek.c src/random/src/scramble.c) add_library(sequence OBJECT src/sequence/src/bsequence.c src/sequence/src/msequence.c) add_library(utility OBJECT src/utility/src/bshift_array.c src/utility/src/byte_utilities.c src/utility/src/memory.c src/utility/src/msb_index.c src/utility/src/pack_bytes.c src/utility/src/shift_array.c src/utility/src/utility.c) add_library(vector OBJECT src/vector/src/vectorf_add.port.c src/vector/src/vectorf_norm.port.c src/vector/src/vectorf_mul.port.c src/vector/src/vectorf_trig.port.c src/vector/src/vectorcf_add.port.c src/vector/src/vectorcf_norm.port.c src/vector/src/vectorcf_mul.port.c src/vector/src/vectorcf_trig.port.c) # ---------------------------------------- SIMD extensions ---------------------------------------- if (C_NEON_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.neon.c src/dotprod/src/dotprod_crcf.neon.c src/dotprod/src/dotprod_rrrf.neon.c src/dotprod/src/sumsq.c) target_compile_options(dotprod PUBLIC ${C_NEON_FLAGS}) elseif (C_AVX512_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.avx512f.c src/dotprod/src/dotprod_crcf.avx512f.c src/dotprod/src/dotprod_rrrf.avx512f.c src/dotprod/src/sumsq.avx512f.c) target_compile_options(dotprod PUBLIC ${C_AVX512_FLAGS}) elseif (C_AVX2_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.avx.c src/dotprod/src/dotprod_crcf.avx.c src/dotprod/src/dotprod_rrrf.avx.c src/dotprod/src/sumsq.avx.c) target_compile_options(dotprod PUBLIC ${C_AVX2_FLAGS}) elseif (C_AVX_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.avx.c src/dotprod/src/dotprod_crcf.avx.c src/dotprod/src/dotprod_rrrf.avx.c src/dotprod/src/sumsq.avx.c) target_compile_options(dotprod PUBLIC ${C_AVX_FLAGS}) elseif (C_SSE4_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.sse.c src/dotprod/src/dotprod_crcf.sse.c src/dotprod/src/dotprod_rrrf.sse.c src/dotprod/src/sumsq.sse.c) target_compile_options(dotprod PUBLIC ${C_SSE4_FLAGS}) elseif (C_ALTIVEC_FOUND AND ENABLE_SIMD) target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.c src/dotprod/src/dotprod_crcf.av.c src/dotprod/src/dotprod_rrrf.av.c src/dotprod/src/sumsq.c) else() # portable C version target_sources(dotprod PUBLIC src/dotprod/src/dotprod_cccf.c src/dotprod/src/dotprod_crcf.c src/dotprod/src/dotprod_rrrf.c src/dotprod/src/sumsq.c) endif() # ---------------------------------------- main library ---------------------------------------- # necessary to include this for the generated "config.h" header include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(${LIBNAME} SHARED src/libliquid.c $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $) target_include_directories(${LIBNAME} PRIVATE ${INCLUDE}) #target_sources(${LIBNAME} PUBLIC FILE_SET HEADERS FILES include/liquid.h) if(COVERAGE) target_compile_options(agc PRIVATE -coverage -O0 -g) target_compile_options(audio PRIVATE -coverage -O0 -g) target_compile_options(buffer PRIVATE -coverage -O0 -g) target_compile_options(channel PRIVATE -coverage -O0 -g) target_compile_options(dotprod PRIVATE -coverage -O0 -g) target_compile_options(equalization PRIVATE -coverage -O0 -g) target_compile_options(fec PRIVATE -coverage -O0 -g) target_compile_options(fft PRIVATE -coverage -O0 -g) target_compile_options(filter PRIVATE -coverage -O0 -g) target_compile_options(framing PRIVATE -coverage -O0 -g) target_compile_options(math PRIVATE -coverage -O0 -g) target_compile_options(matrix PRIVATE -coverage -O0 -g) target_compile_options(modem PRIVATE -coverage -O0 -g) target_compile_options(multichannel PRIVATE -coverage -O0 -g) target_compile_options(nco PRIVATE -coverage -O0 -g) target_compile_options(optim PRIVATE -coverage -O0 -g) target_compile_options(quantization PRIVATE -coverage -O0 -g) target_compile_options(random PRIVATE -coverage -O0 -g) target_compile_options(sequence PRIVATE -coverage -O0 -g) target_compile_options(utility PRIVATE -coverage -O0 -g) target_compile_options(vector PRIVATE -coverage -O0 -g) target_compile_options(${LIBNAME} PRIVATE -coverage -O0 -g) target_link_options(${LIBNAME} PRIVATE -coverage) endif(COVERAGE) target_link_libraries(${LIBNAME} c m) set_target_properties(${LIBNAME} PROPERTIES VERSION ${LIQUID_VERSION} SOVERSION 1) # see: https://cmake.org/cmake/help/latest/command/install.html#examples # TODO: uninstall? install(TARGETS ${LIBNAME} RUNTIME # Following options apply to runtime artifacts. COMPONENT Runtime LIBRARY # Following options apply to library artifacts. COMPONENT Runtime NAMELINK_COMPONENT Development ARCHIVE # Following options apply to archive artifacts. COMPONENT Development DESTINATION lib/static #FILE_SET HEADERS # Following options apply to file set HEADERS. #COMPONENT Development ) install(FILES include/liquid.h DESTINATION include/liquid) # ---------------------------------------- examples ---------------------------------------- # enable examples if(BUILD_EXAMPLES) add_subdirectory(examples) endif(BUILD_EXAMPLES) # ---------------------------------------- sandbox ---------------------------------------- # enable sandbox if(BUILD_SANDBOX) add_subdirectory(sandbox) endif(BUILD_SANDBOX) # ---------------------------------------- autotest ---------------------------------------- set(AUTOTESTS ${PROJECT_SOURCE_DIR}/autotest/null_autotest.c ${PROJECT_SOURCE_DIR}/src/agc/tests/agc_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/audio/tests/cvsd_autotest.c ${PROJECT_SOURCE_DIR}/src/buffer/tests/cbuffer_autotest.c ${PROJECT_SOURCE_DIR}/src/buffer/tests/wdelay_autotest.c ${PROJECT_SOURCE_DIR}/src/buffer/tests/buffer_window_autotest.c ${PROJECT_SOURCE_DIR}/src/channel/tests/channel_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/channel/tests/tvmpch_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/dotprod/tests/dotprod_rrrf_autotest.c ${PROJECT_SOURCE_DIR}/src/dotprod/tests/dotprod_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/dotprod/tests/dotprod_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/dotprod/tests/sumsqf_autotest.c ${PROJECT_SOURCE_DIR}/src/dotprod/tests/sumsqcf_autotest.c ${PROJECT_SOURCE_DIR}/src/equalization/tests/eqlms_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/equalization/tests/eqrls_rrrf_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/crc_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_config_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_soft_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_golay2412_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_hamming74_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_hamming84_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_hamming128_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_hamming1511_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_hamming3126_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_reedsolomon_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_rep3_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_rep5_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_secded2216_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_secded3932_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/fec_secded7264_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/interleaver_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/packetizer_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/fec/tests/packetizer_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/asgram_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_small_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_radix2_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_composite_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_prime_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_r2r_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_shift_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/spgram_autotest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/spwaterfall_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/dds_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/fdelay_rrrf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/fftfilt_xxxf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/filter_crosscorr_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firdecim_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firdecim_xxxf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firdes_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firdespm_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_cccf_notch_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_coefficients_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_rnyquist_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_xxxf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firhilb_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firinterp_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firpfb_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/groupdelay_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirdecim_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirdes_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirdes_support_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirfilt_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirfilt_xxxf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirfiltsos_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirhilb_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirinterp_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/lpc_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/msresamp_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/msresamp2_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/ordfilt_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/rresamp_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/rresamp_crcf_partition_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/resamp_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/resamp2_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/rkaiser_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/symsync_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/symsync_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/symsync_rrrf_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/bpacketsync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/bsync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/detector_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/dsssframe64_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/dsssframesync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/flexframesync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/framesync64_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/fskframesync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/gmskframe_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/msource_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/ofdmflexframe_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qdetector_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qdetector_cccf_copy_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qdsync_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qpacketmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qpilotsync_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/qsource_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/symstreamcf_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/symstreamcf_delay_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/symstreamrcf_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/symstreamrcf_delay_autotest.c ${PROJECT_SOURCE_DIR}/src/framing/tests/symtrack_cccf_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/gcd_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/math_window_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/math_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/math_bessel_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/math_gamma_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/math_complex_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/polynomial_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/polynomial_findroots_autotest.c ${PROJECT_SOURCE_DIR}/src/math/tests/prime_autotest.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/matrixcf_autotest.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/matrixf_autotest.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/smatrixb_autotest.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/smatrixf_autotest.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/smatrixi_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/ampmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/cpfskmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/freqmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/fskmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/gmskmodem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/modem_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/modem_config_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/modem_demodsoft_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/modem_demodstats_autotest.c ${PROJECT_SOURCE_DIR}/src/modem/tests/modem_utilities_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/firpfbch_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/firpfbch2_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/firpfbchr_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/multichannel/tests/ofdmframe_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_frequency_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_mix_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_phase_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_pll_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/nco_crcf_spectrum_autotest.c ${PROJECT_SOURCE_DIR}/src/nco/tests/unwrap_phase_autotest.c ${PROJECT_SOURCE_DIR}/src/optim/tests/gasearch_autotest.c ${PROJECT_SOURCE_DIR}/src/optim/tests/gradsearch_autotest.c ${PROJECT_SOURCE_DIR}/src/optim/tests/qnsearch_autotest.c ${PROJECT_SOURCE_DIR}/src/optim/tests/qs1dsearch_autotest.c ${PROJECT_SOURCE_DIR}/src/optim/tests/utility_autotest.c ${PROJECT_SOURCE_DIR}/src/quantization/tests/compand_autotest.c ${PROJECT_SOURCE_DIR}/src/quantization/tests/quantize_autotest.c ${PROJECT_SOURCE_DIR}/src/random/tests/scramble_autotest.c ${PROJECT_SOURCE_DIR}/src/random/tests/random_autotest.c ${PROJECT_SOURCE_DIR}/src/random/tests/random_distributions_autotest.c ${PROJECT_SOURCE_DIR}/src/sequence/tests/bsequence_autotest.c ${PROJECT_SOURCE_DIR}/src/sequence/tests/complementary_codes_autotest.c ${PROJECT_SOURCE_DIR}/src/sequence/tests/msequence_autotest.c ${PROJECT_SOURCE_DIR}/src/utility/tests/bshift_array_autotest.c ${PROJECT_SOURCE_DIR}/src/utility/tests/count_bits_autotest.c ${PROJECT_SOURCE_DIR}/src/utility/tests/pack_bytes_autotest.c ${PROJECT_SOURCE_DIR}/src/utility/tests/shift_array_autotest.c ) set(AUTOTEST_EXTRA ${PROJECT_SOURCE_DIR}/src/fft/tests/fft_runtest.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_2.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_3.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_4.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_5.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_6.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_7.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_8.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_9.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_10.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_16.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_17.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_20.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_21.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_22.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_24.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_26.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_30.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_32.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_35.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_36.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_43.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_48.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_63.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_64.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_79.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_92.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_96.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_120.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_130.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_157.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_192.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_317.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_data_509.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_r2rdata_8.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_r2rdata_27.c ${PROJECT_SOURCE_DIR}/src/fft/tests/data/fft_r2rdata_32.c ${PROJECT_SOURCE_DIR}/src/filter/tests/fftfilt_runtest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_rrrf_data_h4x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_crcf_data_h4x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_cccf_data_h4x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_rrrf_data_h7x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_crcf_data_h7x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_cccf_data_h7x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_rrrf_data_h13x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_crcf_data_h13x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_cccf_data_h13x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_rrrf_data_h23x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_crcf_data_h23x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/fftfilt_cccf_data_h23x256.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firdecim_runtest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_rrrf_data_M2h4x20.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_crcf_data_M2h4x20.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_cccf_data_M2h4x20.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_rrrf_data_M3h7x30.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_crcf_data_M3h7x30.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_cccf_data_M3h7x30.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_rrrf_data_M4h13x40.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_crcf_data_M4h13x40.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_cccf_data_M4h13x40.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_rrrf_data_M5h23x50.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_crcf_data_M5h23x50.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firdecim_cccf_data_M5h23x50.c ${PROJECT_SOURCE_DIR}/src/filter/tests/firfilt_runtest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_rrrf_data_h4x8.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_crcf_data_h4x8.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_cccf_data_h4x8.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_rrrf_data_h7x16.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_crcf_data_h7x16.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_cccf_data_h7x16.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_rrrf_data_h13x32.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_crcf_data_h13x32.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_cccf_data_h13x32.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_rrrf_data_h23x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_crcf_data_h23x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/firfilt_cccf_data_h23x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/iirfilt_runtest.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_rrrf_data_h3x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_crcf_data_h3x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_cccf_data_h3x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_rrrf_data_h5x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_crcf_data_h5x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_cccf_data_h5x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_rrrf_data_h7x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_crcf_data_h7x64.c ${PROJECT_SOURCE_DIR}/src/filter/tests/data/iirfilt_cccf_data_h7x64.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_add.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_aug.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_cgsolve.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_chol.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_gramschmidt.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_inv.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_linsolve.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_ludecomp.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_mul.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_qrdecomp.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixf_data_transmul.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_add.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_aug.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_chol.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_inv.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_linsolve.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_ludecomp.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_mul.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_qrdecomp.c ${PROJECT_SOURCE_DIR}/src/matrix/tests/data/matrixcf_data_transmul.c ${PROJECT_SOURCE_DIR}/src/nco/tests/data/nco_sincos_fsqrt1_2.c ${PROJECT_SOURCE_DIR}/src/nco/tests/data/nco_sincos_fsqrt1_3.c ${PROJECT_SOURCE_DIR}/src/nco/tests/data/nco_sincos_fsqrt1_5.c ${PROJECT_SOURCE_DIR}/src/nco/tests/data/nco_sincos_fsqrt1_7.c ) if(BUILD_AUTOTESTS) add_executable(autoscript scripts/autoscript.c scripts/main.c scripts/autoscript.h) add_custom_command( OUTPUT autotest_include.h DEPENDS ${PROJECT_BINARY_DIR}/autoscript ${AUTOTESTS} COMMAND ${PROJECT_BINARY_DIR}/autoscript / autotest ${AUTOTESTS} > autotest_include.h ) # create output logging directory add_custom_command( OUTPUT autotest/logs COMMAND mkdir -p autotest/logs ) add_executable(xautotest autotest/xautotest.c ${PROJECT_BINARY_DIR}/autotest_include.h autotest/autotest.h autotest/autotest.c autotest/libliquid_autotest.c autotest/logs ${AUTOTESTS} ${AUTOTEST_EXTRA} ) target_include_directories(xautotest PRIVATE ${INCLUDE}) target_link_libraries(xautotest ${LIBNAME}) if(COVERAGE) target_compile_options(xautotest PRIVATE -coverage -O0 -g) target_link_options(xautotest PRIVATE -coverage) endif(COVERAGE) # enable testing; might consider splitting these up for parallel execution enable_testing() add_test(NAME test COMMAND xautotest) endif(BUILD_AUTOTESTS) # ---------------------------------------- benchmarks ---------------------------------------- set(BENCHMARKS ${PROJECT_SOURCE_DIR}/bench/null_benchmark.c ${PROJECT_SOURCE_DIR}/src/agc/bench/agc_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/audio/bench/cvsd_benchmark.c ${PROJECT_SOURCE_DIR}/src/buffer/bench/cbuffercf_benchmark.c ${PROJECT_SOURCE_DIR}/src/buffer/bench/window_push_benchmark.c ${PROJECT_SOURCE_DIR}/src/buffer/bench/window_read_benchmark.c ${PROJECT_SOURCE_DIR}/src/dotprod/bench/dotprod_cccf_benchmark.c ${PROJECT_SOURCE_DIR}/src/dotprod/bench/dotprod_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/dotprod/bench/dotprod_rrrf_benchmark.c ${PROJECT_SOURCE_DIR}/src/dotprod/bench/sumsqf_benchmark.c ${PROJECT_SOURCE_DIR}/src/dotprod/bench/sumsqcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/equalization/bench/eqlms_cccf_benchmark.c ${PROJECT_SOURCE_DIR}/src/equalization/bench/eqrls_cccf_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/crc_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/fec_encode_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/fec_decode_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/fecsoft_decode_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/sumproduct_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/interleaver_benchmark.c ${PROJECT_SOURCE_DIR}/src/fec/bench/packetizer_decode_benchmark.c ${PROJECT_SOURCE_DIR}/src/fft/bench/fft_composite_benchmark.c ${PROJECT_SOURCE_DIR}/src/fft/bench/fft_prime_benchmark.c ${PROJECT_SOURCE_DIR}/src/fft/bench/fft_radix2_benchmark.c ${PROJECT_SOURCE_DIR}/src/fft/bench/fft_r2r_benchmark.c ${PROJECT_SOURCE_DIR}/src/fft/bench/spgramcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/fftfilt_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/firdecim_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/firhilb_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/firinterp_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/firfilt_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/iirdecim_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/iirfilt_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/iirinterp_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/rresamp_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/resamp_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/resamp2_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/filter/bench/symsync_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/presync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/bpacketsync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/bpresync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/bsync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/detector_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/flexframesync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/framesync64_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/gmskframesync_benchmark.c ${PROJECT_SOURCE_DIR}/src/framing/bench/qdetector_benchmark.c ${PROJECT_SOURCE_DIR}/src/math/bench/polyfit_benchmark.c ${PROJECT_SOURCE_DIR}/src/matrix/bench/matrixf_inv_benchmark.c ${PROJECT_SOURCE_DIR}/src/matrix/bench/matrixf_linsolve_benchmark.c ${PROJECT_SOURCE_DIR}/src/matrix/bench/matrixf_mul_benchmark.c ${PROJECT_SOURCE_DIR}/src/matrix/bench/smatrixf_mul_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/freqdem_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/freqmod_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/fskdem_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/fskmod_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/gmskmodem_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/modem_modulate_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/modem_demodulate_benchmark.c ${PROJECT_SOURCE_DIR}/src/modem/bench/modem_demodsoft_benchmark.c ${PROJECT_SOURCE_DIR}/src/multichannel/bench/firpfbch_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/multichannel/bench/firpfbch2_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/multichannel/bench/firpfbchr_crcf_benchmark.c ${PROJECT_SOURCE_DIR}/src/multichannel/bench/ofdmframesync_acquire_benchmark.c ${PROJECT_SOURCE_DIR}/src/multichannel/bench/ofdmframesync_rxsymbol_benchmark.c ${PROJECT_SOURCE_DIR}/src/nco/bench/nco_benchmark.c ${PROJECT_SOURCE_DIR}/src/nco/bench/vco_benchmark.c ${PROJECT_SOURCE_DIR}/src/quantization/bench/quantizer_benchmark.c ${PROJECT_SOURCE_DIR}/src/quantization/bench/compander_benchmark.c ${PROJECT_SOURCE_DIR}/src/random/bench/random_benchmark.c ${PROJECT_SOURCE_DIR}/src/sequence/bench/bsequence_benchmark.c ${PROJECT_SOURCE_DIR}/src/utility/bench/byte_utilities_benchmark.c ) set(BENCHMARKS_EXTRA ${PROJECT_SOURCE_DIR}/src/fft/bench/fft_runbench.c ) if(BUILD_BENCHMARKS) add_custom_command( OUTPUT benchmark_include.h DEPENDS ${PROJECT_BINARY_DIR}/autoscript ${BENCHMARKS} COMMAND ${PROJECT_BINARY_DIR}/autoscript / benchmark ${BENCHMARKS} > benchmark_include.h ) # create output logging directory #add_custom_command( # OUTPUT benchmark/logs # COMMAND mkdir -p benchmark/logs # ) #benchmark/logs add_executable(benchmark bench/bench.c ${PROJECT_BINARY_DIR}/benchmark_include.h ${BENCHMARKS} ${BENCHMARKS_EXTRA} ) target_include_directories(benchmark PRIVATE ${INCLUDE}) target_link_libraries(benchmark ${LIBNAME}) endif(BUILD_BENCHMARKS) # ---------------------------------------- documentation ---------------------------------------- # enable examples if(BUILD_DOC) add_subdirectory(doc) endif(BUILD_DOC) # ---------------------------------------- packaging ---------------------------------------- set(CPACK_PACKAGE_NAME liquid) set(CPACK_PACKAGE_VENDOR "Joseph D. Gaeddert") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Software-Defined Radio Digital Signal Processing Library") set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) set(CPACK_VERBATIM_VARIABLES TRUE) include(CPack) # ---------------------------------------- summary ---------------------------------------- # debug cmake variables #include(cmake/debug.cmake) # cmake config summary include(cmake/summary.cmake) liquid_print_config_summary() liquid-dsp-1.7.0/LICENSE000066400000000000000000000020531474751757600146260ustar00rootroot00000000000000Copyright (c) 2007 - 2016 Joseph Gaeddert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. liquid-dsp-1.7.0/README.rst000066400000000000000000000342531474751757600153170ustar00rootroot00000000000000 liquid-dsp documentation ======================== Software-Defined Radio Digital Signal Processing Library - `https://liquidsdr.org `_ liquid-dsp is a free and open-source digital signal processing (DSP) library designed specifically for software-defined radios on embedded platforms. The aim is to provide a lightweight DSP library that does not rely on a myriad of external dependencies or proprietary and otherwise cumbersome frameworks. All signal processing elements are designed to be flexible, scalable, and dynamic, including filters, filter design, oscillators, modems, synchronizers, complex mathematical operations, and much more. .. code-block:: c // get in, process data, get out #include int main() { unsigned int M = 4; // interpolation factor unsigned int m = 12; // filter delay [symbols] float As = 60.0f; // filter stop-band attenuation [dB] // create interpolator from prototype firinterp_crcf interp = firinterp_crcf_create_kaiser(M,m,As); float complex x = 1.0f; // input sample float complex y[M]; // interpolated output buffer // repeat on input sample data as needed { firinterp_crcf_execute(interp, x, y); } // destroy interpolator object firinterp_crcf_destroy(interp); return 0; } For more information, please refer to the `documentation `_ online. Installation and Dependencies ============================= liquid-dsp only relies on ``libc`` and ``libm`` (standard C and math) libraries to run; however liquid will take advantage of other libraries (such as `FFTW `_ if they are available. Starting with version 1.7.0, liquid-dsp has moved to the `CMake ` build system which can be installed with ``brew install cmake`` on macOS, ``sudo apt-get install cmake`` on Debian variants. Installation ------------ The recommended way to obtain the source code is to clone the entire `repository `_ from `GitHub `_: .. code-block:: bash git clone git://github.com/jgaeddert/liquid-dsp.git Building and installing the main library is a simple as .. code-block:: bash mkdir build cd build cmake .. make sudo make install If you are installing on Linux for the first time, you will also need to rebind your dynamic libraries with ``sudo ldconfig`` to make the shared object available. This is not necessary on macOS. Run all test scripts -------------------- Source code validation is a critical step in any software library, particularly for verifying the portability of code to different processors and platforms. Packaged with liquid-dsp are a number of automatic test scripts to validate the correctness of the source code. The test scripts are located under each module's ``tests/`` directory and take the form of a C source file. When configured with ``BUILD_AUTOTESTS`` enabled, these tests are parsed, compliled, and linked into an executable which will run the tests. .. code-block:: bash ./xautotest # ... # autotest seed: 1738416409 # ================================== # PASSED ALL 716450 CHECKS # ================================== There are currently more than 700,000 checks across 1,316 tests to verify functional correctness. Drop me a line if these aren't running on your platform. Testing Code Coverage --------------------- In addition to the full test suite, you can configure ``gcc`` to export symbol files to check for code coverage and then use ``gcovr`` to generate a full report of precisely which lines are covered in the autotests. These symbol files aren't generated by default and need to be enabled at compile-time through a CMake option: .. code-block:: bash cmake -DBUILD_AUTOTESTS=ON -DCOVERAGE=ON .. A coverage report can be generated by running the autotests and running `gcovr `_: .. code-block:: bash make -j4 xautotest ./xautotest -q -o autotest.json cd .. gcovr --filter="src/.*/src/.*.c" --print-summary # ... # ------------------------------------------------------------------------------ # TOTAL 20730 17014 82% # ------------------------------------------------------------------------------ # lines: 82.1% (17014 out of 20730) # functions: 62.9% (1742 out of 2770) # branches: 64.0% (5676 out of 8874) Examples -------- Nearly all signal processing elements have a corresponding example in the ``examples/`` directory. Most example scripts generate an output ``.m`` file for plotting with `GNU octave `_ All examples are built as stand-alone programs and can be compiled with the ``BUILD_EXAMPLES`` CMake flag: .. code-block:: bash cmake -DBUILD_EXAMPLES=ON .. make ./examples/modem_example -m qpsk # # 0 : 0.70710677 + j* 0.70710677 # 1 : -0.70710677 + j* 0.70710677 # 2 : 0.70710677 + j* -0.70710677 # 3 : -0.70710677 + j* -0.70710677 # num sym errors: 0 / 4 # num bit errors: 0 / 8 # results written to modem_example.m. Sometimes, however, it is useful to build one example individually. This can be accomplished by directly targeting its binary (e.g. ``make examples/modem_example``). The example then can be run at the command line, viz. ``./examples/modem_example``. Benchmarking Tool ----------------- Packaged with liquid are benchmarks to determine the speed each signal processing element can run on your machine. Initially the tool provides an estimate of the processor's clock frequency and will then estimate the number of trials so that each benchmark will take between 50 and 500 ms to run. You can build and run the benchmark program with the following command: .. code-block:: bash make bench Linking from C++ ---------------- Compiling and linking to C++ programs is straightforward. Just include ```` before ```` and use ``std::complex`` in favor of ``float complex``. Here is the same example as the one above but in C++ instead of C: .. code-block:: c++ // get in, process data, get out #include #include int main() { unsigned int M = 4; // interpolation factor unsigned int m = 12; // filter delay [symbols] float As = 60.0f; // filter stop-band attenuation [dB] // create interpolator from prototype firinterp_crcf interp = firinterp_crcf_create_kaiser(M,m,As); std::complex x = 1.0f; // input sample std::complex y[M]; // interpolated output buffer // repeat on input sample data as needed { firinterp_crcf_execute(interp, x, y); } // destroy interpolator object firinterp_crcf_destroy(interp); return 0; } PlatformIO ---------- Cross-compling for embedded platforms is most easily achieved with `platformio `_. Just add ``liquid-dsp`` to your ``platform.io`` list of dependencies: .. code-block:: ini [env:native] platform = native lib_deps = https://github.com/jgaeddert/liquid-dsp.git To test this, compile the example program for a `Raspberry Pi Pico microcontroller `_: .. code-block:: bash # create a virtual environment, install platformio, and compile an example virtualenv pio source pio/bin/activate pip install platformio pio ci --lib="." --board=pico examples/platformio_example.c # ... # Generating UF2 image # elf2uf2 ".pio/build/pico/firmware.elf" ".pio/build/pico/firmware.uf2" # Checking size .pio/build/pico/firmware.elf # Advanced Memory Usage is available via "PlatformIO Home > Project Inspect" # RAM: [== ] 15.5% (used 41820 bytes from 270336 bytes) # Flash: [ ] 0.2% (used 5196 bytes from 2097152 bytes) # Building .pio/build/pico/firmware.bin # ===================== [SUCCESS] Took 23.63 seconds ===================== Build ----- Here is a table of CMake options available for configuring liquid: +------------------------+---------+--------------------------------------------------------------------+ | Option | Default | Description | +========================+=========+====================================================================+ | ``BUILD_EXAMPLES`` | ON | Compile example programs | +------------------------+---------+--------------------------------------------------------------------+ | ``BUILD_AUTOTESTS`` | ON | Parse and compile autotests into executable binary | +------------------------+---------+--------------------------------------------------------------------+ | ``BUILD_BENCHMARKS`` | ON | Parse and compile benchmarks into executable binary | +------------------------+---------+--------------------------------------------------------------------+ | ``ENABLE_SIMD`` | ON | Enable use of single instruction, multiple data (SIMD) extensions | +------------------------+---------+--------------------------------------------------------------------+ | ``BUILD_SANDBOX`` | ON | Compile sandbox (testing) programs | +------------------------+---------+--------------------------------------------------------------------+ | ``BUILD_DOC`` | OFF | Generate documentation | +------------------------+---------+--------------------------------------------------------------------+ | ``COVERAGE`` | OFF | Set flags to enable code coverage testing | +------------------------+---------+--------------------------------------------------------------------+ For example, if you want to benchmark how fast a vector dot product runs without SIMD extensions, you could run the following: .. code-block:: bash cmake -DENABLE_SIMD=OFF -DBUILD_BENCHMARKS=ON .. make ./benchmark -s dotprod_rrrf Available Modules ----------------- * **agc**: automatic gain control, received signal strength * **audio**: source audio encoders/decoders: cvsd, filterbanks * **buffer**: internal buffering, circular/static, ports (threaded) * **channel**: additive noise, multi-path fading, carrier phase/frequency offsets, timing phase/rate offsets * **dotprod**: inner dot products (real, complex), vector sum of squares * **equalization**: adaptive equalizers: least mean-squares, recursive least squares, semi-blind * **fec**: basic forward error correction codes including several Hamming codes, single error correction/double error detection, Golay block code, as well as several checksums and cyclic redundancy checks, interleaving, soft decoding * **fft**: fast Fourier transforms (arbitrary length), discrete sin/cos transforms * **filter**: finite/infinite impulse response, polyphase, hilbert, interpolation, decimation, filter design, resampling, symbol timing recovery * **framing**: flexible framing structures for amazingly easy packet software radio; dynamically adjust modulation and coding on the fly with single- and multi-carrier framing structures * **math**: transcendental functions not in the C standard library (gamma, besseli, etc.), polynomial operations (curve-fitting, root-finding, etc.) * **matrix**: basic math, LU/QR/Cholesky factorization, inversion, Gauss elimination, Gram-Schmidt decomposition, linear solver, sparse matrix representation * **modem**: modulate, demodulate, PSK, differential PSK, QAM, optimal QAM, as well as analog and non-linear digital modulations GMSK) * **multichannel**: filterbank channelizers, OFDM * **nco**: numerically-controlled oscillator: mixing, frequency synthesis, phase-locked loops * **optim**: (non-linear optimization) Newton-Raphson, evoluationary algorithms, gradient descent, line search * **quantization**: analog/digital converters, compression/expansion * **random**: (random number generators) uniform, exponential, gamma, Nakagami-m, Gauss, Rice-K, Weibull * **sequence**: linear feedback shift registers, complementary codes, maximal-length sequences * **utility**: useful miscellany, mostly bit manipulation (shifting, packing, and unpacking of arrays) * **vector**: generic vector operations License ------- liquid projects are released under the X11/MIT license. By default, this project will try to link to `FFTW`_ if it is available on your build platform. Because FFTW starting with version 1.3 is `licensed `_ under the `GNU General Public License v2 `_ this unfortunately means that (and I'm clearly not a lawyer, here) you cannot distribute ``liquid-dsp`` without also distributing the source code if you link to FFTW. This is a similar situation with the classic `libfec `_ which uses the `GNU Lesser GPL `_. Finally, ``liquid-dsp`` makes extensive use of GNU `autoconf `_, `automake `_, and related tools. These are fantastic libraires with amazing functionality and their authors should be lauded for their efforts. In a similar vain, much the software I write for a living I give away for free; however I believe in more permissive licenses to allow individuals the flexibility to use software with fewer limitations. If these restrictions are not acceptible, ``liquid-dsp`` can be compiled and run without use of these external libraries, albeit a bit slower and with limited functionality. Short version: this code is copyrighted to me (Joseph D. Gaeddert), I give you full permission to do whatever you want with it except remove my name from the credits. Seriously, go nuts! but take caution when linking to other libraries with different licenses. See the `license `_ for specific terms. liquid-dsp-1.7.0/autotest/000077500000000000000000000000001474751757600154715ustar00rootroot00000000000000liquid-dsp-1.7.0/autotest/autotest.c000066400000000000000000000340161474751757600175110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotestlib.c // // default include headers #include #include #include "autotest/autotest.h" // total number of checks invoked unsigned long int liquid_autotest_num_checks=0; // total number of checks which passed unsigned long int liquid_autotest_num_passed=0; // total number of checks which failed unsigned long int liquid_autotest_num_failed=0; // total number of warnings unsigned long int liquid_autotest_num_warnings=0; // verbosity flag int liquid_autotest_verbose = 1; // fail test // increment liquid_autotest_num_checks // increment liquid_autotest_num_failed void liquid_autotest_failed() { liquid_autotest_num_checks++; liquid_autotest_num_failed++; } // pass test // increment liquid_autotest_num_checks // increment liquid_autotest_num_passed void liquid_autotest_passed() { liquid_autotest_num_checks++; liquid_autotest_num_passed++; } // fail test, given expression // _file : filename (string) // _line : line number of test // _exprL : left side of expression (string) // _valueL : left side of expression (value) // _qualifier : expression qualifier // _exprR : right side of expression (string) // _valueR : right side of expression (value) void liquid_autotest_failed_expr(const char * _file, unsigned int _line, const char * _exprL, double _valueL, const char * _qualifier, const char * _exprR, double _valueR) { if (liquid_autotest_verbose) { printf(" TEST FAILED: %s line %u : expected %s (%0.2E) %s %s (%0.2E)\n", _file, _line, _exprL, _valueL, _qualifier, _exprR, _valueR); } liquid_autotest_failed(); } // fail test, given true/false value // _file : filename (string) // _line : line number of test // _exprL : left side of expression (string) // _valueL : left side of expression (value) // _qualifier : expression qualifier void liquid_autotest_failed_bool(const char * _file, unsigned int _line, const char * _exprL, double _valueL, int _qualifier) { if (liquid_autotest_verbose) { printf(" TEST FAILED: %s line %u : expected \"%s\" (%g) is %s\n", _file, _line, _exprL, _valueL, _qualifier ? "true" : "false"); } liquid_autotest_failed(); } // _file : filename (string) // _line : line number of test // _message : message string void liquid_autotest_failed_msg(const char * _file, unsigned int _line, const char * _message) { if (liquid_autotest_verbose) printf(" TEST FAILED: %s line %u : %s\n", _file, _line, _message); liquid_autotest_failed(); } // print basic autotest results to stdout void autotest_print_results(void) { if (liquid_autotest_num_warnings > 0) { printf("==================================\n"); printf(" WARNINGS : %-lu\n", liquid_autotest_num_warnings); } printf("==================================\n"); if (liquid_autotest_num_checks==0) { printf(" NO CHECKS RUN\n"); } else if (liquid_autotest_num_failed==0) { printf(" PASSED ALL %lu CHECKS\n", liquid_autotest_num_passed); } else { // compute and print percentage of failed tests double percent_failed = (double) liquid_autotest_num_failed / (double) liquid_autotest_num_checks; printf(" FAILED %lu / %lu CHECKS (%7.2f%%)\n", liquid_autotest_num_failed, liquid_autotest_num_checks, 100.0*percent_failed); } printf("==================================\n"); } // print warning to stderr // increment liquid_autotest_num_warnings // _file : filename (string) // _line : line number of test // _message : message string void liquid_autotest_warn(const char * _file, unsigned int _line, const char * _message) { if (liquid_autotest_verbose) fprintf(stderr," WARNING: %s line %u : %s\n", _file, _line, _message); liquid_autotest_num_warnings++; } // contend that data in two arrays are identical // _x : input array [size: _n x 1] // _y : input array [size: _n x 1] // _n : input array size int liquid_autotest_same_data(unsigned char * _x, unsigned char * _y, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { if (_x[i] != _y[i]) return 0; } return 1; } // print array to standard out // _x : input array [size: _n x 1] // _n : input array size void liquid_autotest_print_array(unsigned char * _x, unsigned int _n) { unsigned int i; printf(" {"); for (i=0; i<_n; i++) { printf("%.2x, ", (unsigned int)(_x[i])); if ( ((i+1)%16 == 0) && (i != (_n-1)) ) printf("\n "); } printf("}\n"); } // validate spectral content int liquid_autotest_validate_spectrum(float * _psd, unsigned int _nfft, autotest_psd_s * _regions, unsigned int _num_regions, const char * _debug_filename) { unsigned int i, j; int fail[_nfft]; for (j=0; j<_nfft; j++) fail[j] = 0; for (i=0; i<_num_regions; i++) { autotest_psd_s r = _regions[i]; if (liquid_autotest_verbose) { printf(" region[%2u]: f=(%6.3f,%6.3f), (", i, r.fmin, r.fmax); if (r.test_lo) { printf("%7.2f,", r.pmin); } else { printf(" * ,"); } if (r.test_hi) { printf("%7.2f)", r.pmax); } else { printf(" * )"); } printf("\n"); } if (r.fmin < -0.5 || r.fmax > 0.5 || r.fmin > r.fmax) { AUTOTEST_FAIL("invalid frequency range"); return -1; } for (j=0; j<_nfft; j++) { // compute frequency value and check region float f = (float)j / (float)_nfft - 0.5f; if (f < r.fmin || f > r.fmax) continue; // test lower bound if (r.test_lo && _psd[j] < r.pmin) { //AUTOTEST_FAIL("region[%3u], %8.2f exceed minimum (%8.2f)", i, _psd[j], r.pmin); AUTOTEST_FAIL("minimum value exceeded"); fail[j] = 1; } else { AUTOTEST_PASS(); } // test upper bound if (r.test_hi && _psd[j] > r.pmax) { AUTOTEST_FAIL("maximum value exceeded"); fail[j] = 1; } else { AUTOTEST_PASS(); } } } // export debug file if requested if (_debug_filename != NULL) { FILE * fid = fopen(_debug_filename,"w"); if (fid == NULL) { fprintf(stderr,"could not open '%s' for writing\n", _debug_filename); return -1; } fprintf(fid,"clear all; close all; nfft=%u; f=[0:(nfft-1)]/nfft-0.5; psd=zeros(1,nfft);\n", _nfft); fprintf(fid,"idx = ["); for (i=0; i<_nfft; i++) { if (fail[i]) fprintf(fid,"%d,",i+1); } fprintf(fid,"];\n"); for (i=0; i<_nfft; i++) { fprintf(fid,"psd(%6u) = %12.6f;\n", i+1, _psd[i]); } fprintf(fid,"figure; xlabel('f/F_s'); ylabel('PSD [dB]'); hold on;\n"); // add target regions for (i=0; i<_num_regions; i++) { if (_regions[i].test_lo) fprintf(fid," plot([%f,%f],[%f,%f],'Color',[0.5 0 0]);\n",_regions[i].fmin,_regions[i].fmax,_regions[i].pmin,_regions[i].pmin); if (_regions[i].test_hi) fprintf(fid," plot([%f,%f],[%f,%f],'Color',[0 0.5 0]);\n",_regions[i].fmin,_regions[i].fmax,_regions[i].pmax,_regions[i].pmax); } // plot spectrum fprintf(fid," plot(f,psd,'LineWidth',2,'Color',[0 0.3 0.5]);\n"); fprintf(fid," plot(f(idx),psd(idx),'xr');\n"); // identifying errors fprintf(fid,"hold off; grid on; xlim([-0.5 0.5]);\n"); fclose(fid); printf("debug file written to %s\n", _debug_filename); } return 0; } // validate spectral content of a signal (complex) int liquid_autotest_validate_psd_signal(float complex * _buf, unsigned int _buf_len, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename) { // compute signal's power spectral density unsigned int nfft = 4 << liquid_nextpow2(_buf_len < 64 ? 64 : _buf_len); float complex * buf_time = (float complex*) malloc(nfft*sizeof(float complex)); float complex * buf_freq = (float complex*) malloc(nfft*sizeof(float complex)); float * buf_psd = (float * ) malloc(nfft*sizeof(float )); if (buf_time == NULL || buf_freq == NULL || buf_psd == NULL) { AUTOTEST_FAIL("liquid_autotest_validate_psd_signal(), could not allocate appropriate memory for validating psd"); return -1; } unsigned int i; for (i=0; i #include #include #include "liquid.h" // total number of checks invoked extern unsigned long int liquid_autotest_num_checks; // total number of checks which passed extern unsigned long int liquid_autotest_num_passed; // total number of checks which failed extern unsigned long int liquid_autotest_num_failed; // total number of warnings extern unsigned long int liquid_autotest_num_warnings; // verbosity flag extern int liquid_autotest_verbose; // fail test // increment liquid_autotest_num_checks // increment liquid_autotest_num_failed void liquid_autotest_failed(); // pass test // increment liquid_autotest_num_checks // increment liquid_autotest_num_passed void liquid_autotest_passed(); // fail test, given expression // _file : filename (string) // _line : line number of test // _exprL : left side of expression (string) // _valueL : left side of expression (value) // _qualifier : expression qualifier // _exprR : right side of expression (string) // _valueR : right side of expression (value) void liquid_autotest_failed_expr(const char * _file, unsigned int _line, const char * _exprL, double _valueL, const char * _qualifier, const char * _exprR, double _valueR); // fail test, given true/false value // _file : filename (string) // _line : line number of test // _exprL : left side of expression (string) // _valueL : left side of expression (value) // _qualifier : expression qualifier void liquid_autotest_failed_bool(const char * _file, unsigned int _line, const char * _exprL, double _valueL, int _qualifier); // fail test with message // _file : filename (string) // _line : line number of test // _message : message string void liquid_autotest_failed_msg(const char * _file, unsigned int _line, const char * _message); // print basic autotest results to stdout void autotest_print_results(void); // export results to .json file int autotest_export_results(char * _filename); // print warning to stderr // increment liquid_autotest_num_warnings // _file : filename (string) // _line : line number of test // _message : message string void liquid_autotest_warn(const char * _file, unsigned int _line, const char * _message); // contend that data in two arrays are identical // _x : input array [size: _n x 1] // _y : input array [size: _n x 1] // _n : input array size int liquid_autotest_same_data(unsigned char * _x, unsigned char * _y, unsigned int _n); // print array to standard out // _x : input array [size: _n x 1] // _n : input array size void liquid_autotest_print_array(unsigned char * _x, unsigned int _n); // Compute magnitude of (possibly) complex number #define LIQUID_AUTOTEST_VMAG(V) (sqrt(creal(V)*creal(V)+cimag(V)*cimag(V))) // Compute isnan on (possibly) complex number #define LIQUID_AUTOTEST_ISNAN(V) (isnan(crealf(V)) || isnan(cimagf(V))) // CONTEND_TRUE #define TEST_TRUE(F,L,EX,X) \ { \ if (!(X)) \ { \ liquid_autotest_failed_bool(F,L,EX,X,1); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_TRUE_FL(F,L,X) TEST_TRUE(F,L,#X,(X)) #define CONTEND_TRUE(X) CONTEND_TRUE_FL(__FILE__,__LINE__,X) // CONTEND_FALSE #define TEST_FALSE(F,L,EX,X) \ { \ if ((X)) \ { \ liquid_autotest_failed_bool(F,L,EX,X,0); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_FALSE_FL(F,L,X) TEST_FALSE(F,L,#X,(X)) #define CONTEND_FALSE(X) CONTEND_FALSE_FL(__FILE__,__LINE__,X) // CONTEND_EQUALITY #define TEST_EQUALITY(F,L,EX,X,EY,Y) \ { \ if ((X)!=(Y)) \ { \ liquid_autotest_failed_expr(F,L,EX,X,"==",EY,Y); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_EQUALITY_FL(F,L,X,Y) TEST_EQUALITY(F,L,#X,(X),#Y,(Y)) #define CONTEND_EQUALITY(X,Y) CONTEND_EQUALITY_FL(__FILE__,__LINE__,X,Y) // CONTEND_INEQUALITY #define TEST_INEQUALITY(F,L,EX,X,EY,Y) \ { \ if ((X)==(Y)) \ { \ liquid_autotest_failed_expr(F,L,EX,X,"!=",EY,Y); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_INEQUALITY_FL(F,L,X,Y) TEST_INEQUALITY(F,L,#X,(X),#Y,(Y)) #define CONTEND_INEQUALITY(X,Y) CONTEND_INEQUALITY_FL(__FILE__,__LINE__,X,Y) // CONTEND_GREATER_THAN #define TEST_GREATER_THAN(F,L,EX,X,EY,Y) \ { \ if ((X)<=(Y)) \ { \ liquid_autotest_failed_expr(F,L,EX,X,">",EY,Y); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_GREATER_THAN_FL(F,L,X,Y) TEST_GREATER_THAN(F,L,#X,(X),#Y,(Y)) #define CONTEND_GREATER_THAN(X,Y) CONTEND_GREATER_THAN_FL(__FILE__,__LINE__,X,Y) // CONTEND_LESS_THAN #define TEST_LESS_THAN(F,L,EX,X,EY,Y) \ { \ if ((X)>=(Y)) \ { \ liquid_autotest_failed_expr(F,L,EX,X,"<",EY,Y); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_LESS_THAN_FL(F,L,X,Y) TEST_LESS_THAN(F,L,#X,(X),#Y,(Y)) #define CONTEND_LESS_THAN(X,Y) CONTEND_LESS_THAN_FL(__FILE__,__LINE__,X,Y) // CONTEND_DELTA // Test delta between two (possibly complex numbers) is within tolerance. Use the // expanded macro for computing magnitude of difference to account for both real // as well as complex numbers #define TEST_DELTA(F,L,EX,X,EY,Y,ED,D) \ { \ if (LIQUID_AUTOTEST_VMAG((X)-(Y)) > (D) || \ LIQUID_AUTOTEST_ISNAN((X)) || LIQUID_AUTOTEST_ISNAN((Y)) ) \ { \ liquid_autotest_failed_expr(F,L,"abs(" #X "-" #Y ")", \ LIQUID_AUTOTEST_VMAG((X)-(Y)),"<",ED,D); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_DELTA_FL(F,L,X,Y,D) TEST_DELTA(F,L,#X,(X),#Y,(Y),#D,(D)) #define CONTEND_DELTA(X,Y,D) CONTEND_DELTA_FL(__FILE__,__LINE__,X,Y,D) // CONTEND_EXPRESSION #define TEST_EXPRESSION(F,L,EX,X) \ { \ if (!X) \ { \ liquid_autotest_failed_expr(F,L,#X,(X),"is","1",1); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_EXPRESSION_FL(F,L,X) TEST_EXPRESSION(F,L,#X,(X)) #define CONTEND_EXPRESSION(X) CONTEND_EXPRESSION_FL(__FILE__,__LINE__,X) // CONTEND_ISNULL #define TEST_ISNULL(F,L,EX,X) \ { \ if ((void*)(X)!=(NULL)) \ { \ liquid_autotest_failed_expr(F,L,EX,(long)X,"==","NULL",1); \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_ISNULL_FL(F,L,X) TEST_ISNULL(F,L,#X,(X)) #define CONTEND_ISNULL(X) CONTEND_ISNULL_FL(__FILE__,__LINE__,X) // CONTEND_SAME_DATA #define TEST_SAME_DATA(F,L,EX,X,EY,Y,EN,N) \ { \ if (!liquid_autotest_same_data((uint8_t*)(X),(uint8_t*)(Y),(N))) \ { \ liquid_autotest_failed_msg(F,L,EX "[] != " EY "[] for " EN " bytes"); \ if (liquid_autotest_verbose) \ { \ liquid_autotest_print_array((uint8_t*)(X),N); \ liquid_autotest_print_array((uint8_t*)(Y),N); \ } \ } else { \ liquid_autotest_passed(); \ } \ } #define CONTEND_SAME_DATA_FL(F,L,X,Y,N) TEST_SAME_DATA(F,L,#X,(X),#Y,(Y),#N,(N)) #define CONTEND_SAME_DATA(X,Y,N) CONTEND_SAME_DATA_FL(__FILE__,__LINE__,X,Y,N) // AUTOTEST WARN #define AUTOTEST_WARN_FL(F,L,MSG) liquid_autotest_warn(F,L,#MSG) #define AUTOTEST_WARN(MSG) AUTOTEST_WARN_FL(__FILE__,__LINE__,MSG) // AUTOTEST PASS #define AUTOTEST_PASS_FL(F,L) liquid_autotest_passed() #define AUTOTEST_PASS() AUTOTEST_PASS_FL(__FILE__,__LINE__) // AUTOTEST FAIL #define AUTOTEST_FAIL_FL(F,L,MSG) liquid_autotest_failed_msg(F,L,MSG) #define AUTOTEST_FAIL(MSG) AUTOTEST_FAIL_FL(__FILE__,__LINE__,MSG) // supporting methods typedef struct { float fmin, fmax; float pmin, pmax; int test_lo, test_hi; } autotest_psd_s; // validate spectral content int liquid_autotest_validate_spectrum(float * _psd, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of a signal (complex) int liquid_autotest_validate_psd_signal(float complex * _buf, unsigned int _buf_len, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of a signal (real) int liquid_autotest_validate_psd_signalf(float * _buf, unsigned int _buf_len, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of a filter (real coefficients) int liquid_autotest_validate_psd_firfilt_crcf(firfilt_crcf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of a filter (complex coefficients) int liquid_autotest_validate_psd_firfilt_cccf(firfilt_cccf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of an iir filter (real coefficients, input) int liquid_autotest_validate_psd_iirfilt_rrrf(iirfilt_rrrf _q, unsigned int _nfft, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // validate spectral content of a spectral periodogram object int liquid_autotest_validate_psd_spgramcf(spgramcf _q, autotest_psd_s * _regions, unsigned int num_regions, const char * debug_filename); // callback function to simplify testing for framing objects #define FRAMING_AUTOTEST_SECRET 0x01234567 int framing_autotest_callback( unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _context); #endif // __LIQUID_AUTOTEST_H__ liquid-dsp-1.7.0/autotest/libliquid_autotest.c000066400000000000000000000026301474751757600215440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest.h" #include "liquid.h" void autotest_libliquid() { // test liquid string version CONTEND_EQUALITY(strcmp(LIQUID_VERSION,liquid_libversion()),0) // test liquid integer version CONTEND_EQUALITY(LIQUID_VERSION_NUMBER, liquid_libversion_number()); } liquid-dsp-1.7.0/autotest/logs/000077500000000000000000000000001474751757600164355ustar00rootroot00000000000000liquid-dsp-1.7.0/autotest/logs/.gitignore000066400000000000000000000000131474751757600204170ustar00rootroot00000000000000*.m *.dat liquid-dsp-1.7.0/autotest/null_autotest.c000066400000000000000000000023121474751757600205350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest.h" void autotest_null() { // pass unconditionally AUTOTEST_PASS(); } liquid-dsp-1.7.0/autotest/xautotest.c000066400000000000000000000425571474751757600177120ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // autotest.c // // This file is used in conjunction with autotest_include.h (generated with // autotest_gen.py) to produce an executable for automatically testing the // various signal processing algorithms in liquid. // default include headers #include #include #include #include #include #include #include "liquid.internal.h" #include "autotest/autotest.h" void usage() { // help printf("Usage: xautotest [OPTION]\n"); printf("Execute autotest scripts for liquid-dsp library.\n"); printf(" -h display this help and exit\n"); printf(" -t run specific test\n"); printf(" -H hammer on a specific test\n"); printf(" -c number of time to run hammer test\n"); printf(" -p run specific package\n"); printf(" -r run all tests, random order\n"); printf(" -R specify random seed value\n"); printf(" -L lists all scripts\n"); printf(" -l lists all packages\n"); printf(" -x stop on fail\n"); printf(" -s run all tests matching search string\n"); printf(" -v verbose\n"); printf(" -q quiet\n"); printf(" -o output file (json)\n"); } // define autotest function pointer typedef void(autotest_function_t) (void); // define autotest_t typedef struct { unsigned int id; // test identification autotest_function_t * api; // test function, e.g. autotest_modem() const char* name; // test name long unsigned int num_checks; // number of checks that were run for this test long unsigned int num_passed; // number of checks that passed long unsigned int num_failed; // number of checks that failed long unsigned int num_warnings; // number of warnings float percent_passed; // percent of checks that passed int executed; // was the test executed? int pass; // did the test pass? (i.e. no failures) double extime; // execution time (seconds) } autotest_t; // define package_t typedef struct { unsigned int id; // package identification unsigned int index; // index of first autotest unsigned int num_scripts; // number of tests in package const char* name; // package name int executed; // were any tests executed? } package_t; // include auto-generated autotest header // // defines the following symbols: // #define AUTOSCRIPT_VERSION // #define NUM_AUTOSCRIPTS // autotest_t scripts[NUM_AUTOSCRIPTS] // #define NUM_PACKAGES // struct package_t packages[NUM_PACKAGES] #include "autotest_include.h" // // helper functions: // // execute a specific test void execute_autotest(autotest_t * _test, int _verbose); // execute a specific package void execute_package(package_t * _p, int _verbose); // execute a specific package if string matches void execute_package_search(package_t * _p, char * _str, int _verbose); // print all autotest results void print_autotest_results(autotest_t * _test); // calculate execution time (delta between two values) double calculate_execution_time(struct rusage _tic, struct rusage _toc); // print the results of a particular package void print_package_results(package_t * _p); // print all unstable tests (those which failed or gave warnings) void print_unstable_tests(void); // print list of tests void print_test_list(void); // print list of packages void print_package_list(void); // main function int main(int argc, char *argv[]) { // options enum {RUN_ALL, // run all tests RUN_ALL_RANDOM, // run all tests (random order) RUN_SINGLE_TEST, // run just a single test RUN_SINGLE_PACKAGE, // run just a single package RUN_SEARCH, // run search HAMMER_SINGLE_TEST, // run just a single test, but repeatedly and with incrementing seeds } mode = RUN_ALL; // set defaults unsigned int autotest_id = 0; unsigned int package_id = 0; int verbose = 1; int stop_on_fail = 0; unsigned int rseed = time(NULL); unsigned int hammer_count = 100; char search_string[128] = ""; char filename[256] = ""; unsigned int i; // get input options int d; while((d = getopt(argc,argv,"ht:H:c:p:rR:Llxs:vqo:")) != EOF){ switch (d) { case 'h': usage(); return 0; case 't': autotest_id = atoi(optarg); mode = RUN_SINGLE_TEST; break; case 'H': autotest_id = atoi(optarg); mode = HAMMER_SINGLE_TEST; break; case 'c': hammer_count = atoi(optarg); break; case 'p': package_id = atoi(optarg); mode = RUN_SINGLE_PACKAGE; break; case 'r': mode = RUN_ALL_RANDOM; break; case 'R': rseed = atoi(optarg); break; case 'L': // list packages, scripts and exit print_test_list(); return 0; case 'l': // list only packages and exit print_package_list(); return 0; case 'x': stop_on_fail = 1; break; case 's': mode = RUN_SEARCH; strncpy(search_string, optarg, 128); search_string[127] = '\0'; break; case 'v': verbose = 1; liquid_autotest_verbose = 1; break; case 'q': verbose = 0; liquid_autotest_verbose = 0; break; case 'o': strncpy(filename,optarg,255); filename[255] = '\0'; break; default: return 1; } } // set random seed for repeatability srand(rseed); // validate results if (autotest_id >= NUM_AUTOSCRIPTS) { printf("error, cannot run autotest %u; index exceeded\n", autotest_id); return -1; } else if (package_id >= NUM_PACKAGES) { printf("error, cannot run package %u; index exceeded\n", package_id); return -1; } unsigned int n=0; switch (mode) { case RUN_ALL: for (i=0; i 0) break; } for (i=0; i= NUM_AUTOSCRIPTS) i %= NUM_AUTOSCRIPTS; } printf("executing test %4u (%4u / %4u)\n", i, n+1, NUM_AUTOSCRIPTS); execute_autotest( &scripts[i], verbose ); n++; if (stop_on_fail && liquid_autotest_num_failed > 0) break; } for (i=0; i 0) break; } if (verbose) print_autotest_results( &scripts[autotest_id] ); break; default: fprintf(stderr,"unknown run mode\n"); return -1; } // ugh liquid_fftwf_cleanup_wrapper(); if (liquid_autotest_verbose) print_unstable_tests(); printf("autotest seed: %u\n", rseed); autotest_print_results(); // program return value int rc = liquid_autotest_num_failed > 0 ? 1 : 0; if (strcmp(filename,"")==0) return rc; // export results to output .json file; try to open file for writing FILE * fid = fopen(filename,"w"); if (!fid) { fprintf(stderr,"error: %s, could not open '%s' for writing\n", __FILE__, filename); return -1; } // print header time_t now; time(&now); char timestamp[80]; strftime(timestamp,80,"%c",localtime(&now)); fprintf(fid,"{\n"); fprintf(fid," \"build-info\" : {},\n"); fprintf(fid," \"timestamp\" : \"%s\",\n", timestamp); fprintf(fid," \"pass\" : %s,\n", liquid_autotest_num_failed==0 ? "true" : "false"); fprintf(fid," \"num_failed\" : %lu,\n", liquid_autotest_num_failed); fprintf(fid," \"num_checks\" : %lu,\n", liquid_autotest_num_checks); fprintf(fid," \"num_warnings\" : %lu,\n", liquid_autotest_num_warnings); fprintf(fid," \"command-line\" : \""); for (i=0; i<(unsigned int)argc; i++) fprintf(fid," %s", argv[i]); fprintf(fid,"\",\n"); fprintf(fid," \"run-mode\" : "); switch (mode) { case RUN_ALL: fprintf(fid,"\"RUN_ALL\",\n"); break; case RUN_ALL_RANDOM: fprintf(fid,"\"RUN_RANDOM\",\n"); break; case RUN_SINGLE_TEST: fprintf(fid,"\"RUN_SINGLE_TEST\",\n"); break; case RUN_SINGLE_PACKAGE: fprintf(fid,"\"RUN_SINGLE_PACKAGE\",\n"); break; case RUN_SEARCH: fprintf(fid,"\"RUN_SEARCH\",\n"); break; case HAMMER_SINGLE_TEST: fprintf(fid,"\"HAMMER_SINGLE_TEST\",\n"); break; default: fprintf(fid,"\"(unknown)\",\n"); } fprintf(fid," \"rseed\" : %u,\n", rseed); fprintf(fid," \"stop-on-fail\" : %s,\n", stop_on_fail ? "true" : "false"); fprintf(fid," \"tests\" : [\n"); for (i=0; iname); } // start test and run timer struct rusage tic, toc; getrusage(RUSAGE_SELF, &tic); _test->api(); getrusage(RUSAGE_SELF, &toc); _test->num_passed = liquid_autotest_num_passed - autotest_num_passed_init; _test->num_failed = liquid_autotest_num_failed - autotest_num_failed_init; _test->num_warnings = liquid_autotest_num_warnings - autotest_num_warnings_init; _test->num_checks = _test->num_passed + _test->num_failed; _test->pass = (_test->num_failed==0) ? 1 : 0; if (_test->num_checks > 0) _test->percent_passed = 100.0f * (float) (_test->num_passed) / (float) (_test->num_checks); else _test->percent_passed = 0.0f; _test->executed = 1; _test->extime = calculate_execution_time(tic, toc); //if (_verbose) // print_autotest_results(_test); } // execute a specific package // _p : pointer to package object // _verbose : verbose output flag void execute_package(package_t * _p, int _verbose) { if (_verbose) printf("%u: %s\n", _p->id, _p->name); unsigned int i; for (i=0; i<_p->num_scripts; i++) { execute_autotest( &scripts[ i + _p->index ], _verbose ); } _p->executed = 1; } // execute a specific package if string matches void execute_package_search(package_t * _p, char * _str, int _verbose) { // see if search string matches autotest name if (strstr(_p->name, _str) != NULL) { // run the package execute_package(_p, _verbose); } else { unsigned int i; unsigned int i0 = _p->index; unsigned int i1 = _p->num_scripts + i0; for (i=i0; iexecuted = 1; } } } } double calculate_execution_time(struct rusage _tic, struct rusage _toc) { return _toc.ru_utime.tv_sec - _tic.ru_utime.tv_sec + 1e-6*(_toc.ru_utime.tv_usec - _tic.ru_utime.tv_usec) + _toc.ru_stime.tv_sec - _tic.ru_stime.tv_sec + 1e-6*(_toc.ru_stime.tv_usec - _tic.ru_stime.tv_usec); } // print results of a particular test void print_autotest_results(autotest_t * _test) { printf(" %4u", _test->id); if (!_test->executed) { printf("[ - ] IGNORED "); } else { printf("[%8.2f ms] %8s ", _test->extime*1e3f, _test->pass ? " PASS " : "<>"); } printf("passed %4lu/%4lu checks (%5.1f%%) %s\n", _test->num_passed, _test->num_checks, _test->percent_passed, _test->name); } // print results of a particular package void print_package_results(package_t * _p) { unsigned int i; printf("%u: %s:\n", _p->id, _p->name); for (i=_p->index; i<(_p->index+_p->num_scripts); i++) { //if ( scripts[i].executed ) // only print scripts that were executed print_autotest_results( &scripts[i] ); } printf("\n"); } // print all unstable tests (those which failed or gave warnings) void print_unstable_tests(void) { if (liquid_autotest_num_failed == 0 && liquid_autotest_num_warnings == 0) { return; } printf("==================================\n"); printf(" UNSTABLE TESTS:\n"); unsigned int t; for (t=0; t> %s\n", scripts[t].id, scripts[t].name); } if (scripts[t].num_warnings > 0) { printf(" %3u : %4lu warnings %s\n", scripts[t].id, scripts[t].num_warnings, scripts[t].name); } } } } void print_test_list(void) { unsigned int i; unsigned int j; for (i=0; i #include #include #include #include #include #include // define benchmark function pointer typedef void(benchmark_function_t) ( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations); // define benchmark_t typedef struct { unsigned int id; // identification of benchmark benchmark_function_t * api; // function interface const char * name; // name of function unsigned int name_len; unsigned int num_trials; float extime; float rate; float cycles_per_trial;// unsigned int num_attempts; // number of attempts to reach target time } benchmark_t; // define package_t typedef struct { unsigned int id; // package identification unsigned int index; // index of first benchmark unsigned int num_scripts; // number of tests in package const char* name; // package name } package_t; // include auto-generated benchmark header // // defines the following symbols: // #define AUTOSCRIPT_VERSION // #define NUM_AUTOSCRIPTS // benchmark_t scripts[NUM_AUTOSCRIPTS] // #define NUM_PACKAGES // package_t packages[NUM_PACKAGES] #include "benchmark_include.h" // helper functions: void estimate_cpu_clock(void); void set_num_trials_from_cpu_speed(void); void execute_benchmark(benchmark_t* _benchmark, int _verbose); void execute_package(package_t* _package, int _verbose); char convert_units(float * _s); void print_benchmark_results(benchmark_t* _benchmark); void print_package_results(package_t* _package); double calculate_execution_time(struct rusage, struct rusage); unsigned long int num_base_trials = 1<<12; float cpu_clock = 1.0f; // cpu clock speed (Hz) float runtime=0.050f; // minimum run time (s) FILE * fid; // output file id void output_benchmark_to_file(FILE * _fid, benchmark_t * _benchmark); void usage() { // help printf("Usage: benchmark [OPTION]\n"); printf("Execute benchmark scripts for liquid-dsp library.\n"); printf(" -h : display this help and exit\n"); printf(" -v : verbose\n"); printf(" -q : quiet\n"); printf(" -f : run fast version\n"); printf(" -e : estimate cpu clock frequency and exit\n"); printf(" -c : set cpu clock frequency (Hz)\n"); printf(" -n : set number of base trials\n"); printf(" -p : run specific package\n"); printf(" -b : run specific benchmark\n"); printf(" -t : set minimum execution time (s)\n"); printf(" -l : list available packages\n"); printf(" -L : list all available scripts\n"); printf(" -s : run all packages/benchmarks matching search string\n"); printf(" -o : output file (json)\n"); } // main function int main(int argc, char *argv[]) { // initialize timing variables unsigned int i, j; // options enum {RUN_ALL, RUN_SINGLE_BENCH, RUN_SINGLE_PACKAGE, RUN_SEARCH, } mode = RUN_ALL; unsigned int benchmark_id = 0; unsigned int package_id = 0; int verbose = 1; int autoscale = 1; int cpu_clock_detect = 1; char filename[256] = "benchmark.json"; char search_string[128]; // get input options int d; while((d = getopt(argc,argv,"hvqfec:n:b:p:t:lLs:o:")) != EOF){ switch (d) { case 'h': usage(); return 0; case 'v': verbose = 1; break; case 'q': verbose = 0; break; case 'f': num_base_trials = 100; runtime = 0.5e-3f; break; case 'e': estimate_cpu_clock(); return 0; case 'c': cpu_clock = atof(optarg); if (cpu_clock < 0) { printf("error: cpu clock speed is negative (%f)\n", cpu_clock); return -1; } cpu_clock_detect = 0; break; case 'n': num_base_trials = atoi(optarg); autoscale = 0; break; case 'b': benchmark_id = atoi(optarg); if (benchmark_id >= NUM_AUTOSCRIPTS) { printf("error, cannot run benchmark %u; index exceeded\n", benchmark_id); return -1; } else { mode = RUN_SINGLE_BENCH; } break; case 'p': package_id = atoi(optarg); if (package_id >= NUM_PACKAGES) { printf("error, cannot run package %u; index exceeded\n", package_id); return -1; } else { mode = RUN_SINGLE_PACKAGE; } break; case 't': runtime = atof(optarg); if (runtime < 1e-3f) runtime = 1e-3f; else if (runtime > 10.f) runtime = 10.0f; printf("minimum runtime: %d ms\n", (int) roundf(runtime*1e3)); break; case 'l': // list only packages and exit for (i=0; iapi(&start, &finish, &num_trials); _benchmark->extime = calculate_execution_time(start, finish); // check exit criteria if (_benchmark->extime >= runtime) { break; } else if (num_attempts == 30) { fprintf(stderr,"warning: benchmark could not execute over minimum run time\n"); break; } else { // increase number of trials n *= 2; } } while (1); _benchmark->num_trials = num_trials; _benchmark->num_attempts = num_attempts; _benchmark->rate = _benchmark->extime==0 ? 0 : (float)(_benchmark->num_trials) / _benchmark->extime; _benchmark->cycles_per_trial = _benchmark->extime==0 ? 0 : cpu_clock / (_benchmark->rate); if (_verbose) print_benchmark_results(_benchmark); } void execute_package(package_t* _package, int _verbose) { if (_verbose) printf("%u: %s\n", _package->id, _package->name); unsigned int i; for (i=0; i<_package->num_scripts; i++) { execute_benchmark( &scripts[ i + _package->index ], _verbose ); } } // convert raw value into metric units, // example: "0.01397s" -> "13.97 ms" char convert_units(float * _v) { char unit; if (*_v < 1e-9) { (*_v) *= 1e12; unit = 'p';} else if (*_v < 1e-6){ (*_v) *= 1e9; unit = 'n';} else if (*_v < 1e-3){ (*_v) *= 1e6; unit = 'u';} else if (*_v < 1e+0){ (*_v) *= 1e3; unit = 'm';} else if (*_v < 1e3) { (*_v) *= 1e+0; unit = ' ';} else if (*_v < 1e6) { (*_v) *= 1e-3; unit = 'k';} else if (*_v < 1e9) { (*_v) *= 1e-6; unit = 'M';} else if (*_v < 1e12){ (*_v) *= 1e-9; unit = 'G';} else { (*_v) *= 1e-12; unit = 'T';} return unit; } void print_benchmark_results(benchmark_t* _b) { // format trials (iterations) float trials_format = (float)(_b->num_trials); char trials_units = convert_units(&trials_format); // format time (seconds) float extime_format = _b->extime; char extime_units = convert_units(&extime_format); // format rate (trials/second) float rate_format = _b->rate; char rate_units = convert_units(&rate_format); // format processor efficiency (cycles/trial) float cycles_format = _b->cycles_per_trial; char cycles_units = convert_units(&cycles_format); printf(" %-3u: [%2u] %-30s: %6.2f %c trials / %6.2f %cs (%6.2f %c t/s, %6.2f %c c/t)\n", _b->id, _b->num_attempts, _b->name, trials_format, trials_units, extime_format, extime_units, rate_format, rate_units, cycles_format, cycles_units); } void print_package_results(package_t* _package) { unsigned int i; printf("%u: %s:\n", _package->id, _package->name); for (i=_package->index; i<(_package->index+_package->num_scripts); i++) print_benchmark_results( &scripts[i] ); printf("\n"); } double calculate_execution_time(struct rusage _start, struct rusage _finish) { return _finish.ru_utime.tv_sec - _start.ru_utime.tv_sec + 1e-6*(_finish.ru_utime.tv_usec - _start.ru_utime.tv_usec) + _finish.ru_stime.tv_sec - _start.ru_stime.tv_sec + 1e-6*(_finish.ru_stime.tv_usec - _start.ru_stime.tv_usec); } liquid-dsp-1.7.0/bench/example_benchmark.h000066400000000000000000000035251474751757600205230ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Example of a benchmark header // #include #include // strings parsed by benchmarkgen.py const char * mybench_opts[3] = { "opt1a opt1b", "opt2a opt2b opt2c", "opt3a opt3b opt3c" }; void benchmark_mybench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) // unsigned int argc, // char *argv[]) { // DSP initiazation goes here unsigned int i; float x, y, theta; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // DSP execution goes here x = cosf(M_PI/2.0f); y = sinf(M_PI/2.0f); theta = atan2(y,x); } getrusage(RUSAGE_SELF, _finish); // DSP cleanup goes here } liquid-dsp-1.7.0/bench/fftbench.c000066400000000000000000000435121474751757600166300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftbench.c : benchmark fft algorithms // // default include headers #include #include #include #include #include #include #include #include #include "liquid.h" void usage() { // help printf("Usage: benchmark [OPTION]\n"); printf("Execute benchmark scripts for liquid-dsp library.\n"); printf(" -h display this help and exit\n"); printf(" -v/q verbose/quiet\n"); printf(" -t[SECONDS] set minimum execution time (s)\n"); printf(" -o[FILENAME] export output\n"); printf(" -n[NFFT_MIN] minimum FFT size (benchmark single FFT)\n"); printf(" -N[NFFT_MAX] maximum FFT size\n"); printf(" -m[MODE] mode: all, radix2, composite, prime, fftwbench, single\n"); printf(" -l[library] library: float, fftw\n"); } // benchmark structure struct benchmark_s { // fft options unsigned int nfft; // FFT size int direction; // FFT direction int flags; // FFT flags/method // benchmark results unsigned int num_trials; // number of trials float extime; // execution time // derived values float time_per_trial; // execution time per trial float flops; // computation bandwidth }; typedef enum { LIB_FLOAT=0, LIB_FFTW, } library_t; // simulation structure struct fftbench_s { enum {RUN_ALL=0, RUN_RADIX2, RUN_COMPOSITE, RUN_PRIME, RUN_FFTWBENCH, RUN_SINGLE, } mode; // library version library_t library; int verbose; float runtime; // minimum run time (s) // min/max sizes for other modes unsigned int nfft_min; // minimum FFT size (also, size for RUN_SINGLE mode) unsigned int nfft_max; // maximum FFT size // output file char filename[128]; // output filename FILE * fid; // output file pointer int output_to_file; // output file write flag }; // helper functions: char convert_units(float * _s); double calculate_execution_time(struct rusage, struct rusage); // run all benchmarks void fftbench_execute(struct fftbench_s * _fftbench); // execute single benchmark void execute_benchmark_fft(struct benchmark_s * _benchmark, float _runtime, library_t _library); // main benchmark script (floating-point precision) void benchmark_fft(struct rusage * _start, struct rusage * _finish, struct benchmark_s * _benchmark); // main benchmark script (FFTW) void benchmark_fftw(struct rusage * _start, struct rusage * _finish, struct benchmark_s * _benchmark); void benchmark_print_to_file(FILE * _fid, struct benchmark_s * _benchmark); void benchmark_print(struct benchmark_s * _benchmark); // main function int main(int argc, char *argv[]) { // options struct fftbench_s fftbench; fftbench.mode = RUN_RADIX2; fftbench.library = LIB_FLOAT; fftbench.verbose = 1; fftbench.runtime = 0.1f; fftbench.nfft_min = 2; fftbench.nfft_max = 1024; fftbench.filename[0]= '\0'; fftbench.fid = NULL; fftbench.output_to_file = 0; // get input options int d; while((d = getopt(argc,argv,"hvqn:N:t:o:m:l:")) != EOF){ switch (d) { case 'h': usage(); return 0; case 'v': fftbench.verbose = 1; break; case 'q': fftbench.verbose = 0; break; case 'n': fftbench.nfft_min = atoi(optarg); break; case 'N': fftbench.nfft_max = atoi(optarg); break; case 't': fftbench.runtime = atof(optarg); if (fftbench.runtime < 1e-3f) fftbench.runtime = 1e-3f; else if (fftbench.runtime > 10.f) fftbench.runtime = 10.0f; printf("minimum runtime: %d ms\n", (int) roundf(fftbench.runtime*1e3)); break; case 'o': fftbench.output_to_file = 1; strcpy(fftbench.filename, optarg); break; case 'm': if (strcmp(optarg,"all")==0) fftbench.mode = RUN_ALL; else if (strcmp(optarg,"radix2")==0) fftbench.mode = RUN_RADIX2; else if (strcmp(optarg,"composite")==0) fftbench.mode = RUN_COMPOSITE; else if (strcmp(optarg,"prime")==0) fftbench.mode = RUN_PRIME; else if (strcmp(optarg,"fftwbench")==0) fftbench.mode = RUN_FFTWBENCH; else if (strcmp(optarg,"single")==0) fftbench.mode = RUN_SINGLE; else { fprintf(stderr,"error: %s, unknown mode '%s'\n", argv[0], optarg); exit(1); } break; case 'l': if (strcmp(optarg,"float")==0) fftbench.library = LIB_FLOAT; else if (strcmp(optarg,"fftw")==0) fftbench.library = LIB_FFTW; else { fprintf(stderr,"error: %s, unknown library option '%s'\n", argv[0], optarg); exit(1); } break; default: usage(); return 0; } } // run empty loop; a bug was found that sometimes the first package run // resulted in a longer execution time than what the benchmark really // reflected. This loop prevents that from happening. unsigned int i; for (i=0; i<1e6; i++) { // do nothing } // open output file (if applicable) if (fftbench.output_to_file) { fftbench.fid = fopen(fftbench.filename,"w"); if (!fftbench.fid) { fprintf(stderr,"error: %s, could not open file '%s' for writing\n", argv[0], fftbench.filename); exit(1); } FILE * fid = fftbench.fid; // print header fprintf(fid,"# %s : auto-generated file\n", fftbench.filename); fprintf(fid,"#\n"); fprintf(fid,"# invoked as:\n"); fprintf(fid,"# "); for (i=0; i "13.97 ms" char convert_units(float * _v) { char unit; if (*_v < 1e-9) { (*_v) *= 1e12; unit = 'p';} else if (*_v < 1e-6){ (*_v) *= 1e9; unit = 'n';} else if (*_v < 1e-3){ (*_v) *= 1e6; unit = 'u';} else if (*_v < 1e+0){ (*_v) *= 1e3; unit = 'm';} else if (*_v < 1e3) { (*_v) *= 1e+0; unit = ' ';} else if (*_v < 1e6) { (*_v) *= 1e-3; unit = 'k';} else if (*_v < 1e9) { (*_v) *= 1e-6; unit = 'M';} else if (*_v < 1e12){ (*_v) *= 1e-9; unit = 'G';} else { (*_v) *= 1e-12; unit = 'T';} return unit; } double calculate_execution_time(struct rusage _start, struct rusage _finish) { return _finish.ru_utime.tv_sec - _start.ru_utime.tv_sec + 1e-6*(_finish.ru_utime.tv_usec - _start.ru_utime.tv_usec) + _finish.ru_stime.tv_sec - _start.ru_stime.tv_sec + 1e-6*(_finish.ru_stime.tv_usec - _start.ru_stime.tv_usec); } // run all benchmarks void fftbench_execute(struct fftbench_s * _fftbench) { // validate input if (_fftbench->nfft_min > _fftbench->nfft_max && _fftbench->mode != RUN_SINGLE) { fprintf(stderr,"execute_benchmarks_composite(), nfft_min cannot be greater than nfft_max\n"); exit(1); } else if (_fftbench->runtime <= 0.0f) { fprintf(stderr,"execute_benchmarks_composite(), runtime must be greater than zero\n"); exit(1); } // create benchmark structure struct benchmark_s benchmark; if (_fftbench->mode == RUN_SINGLE) { // run single benchmark and exit // initialize benchmark structure benchmark.nfft = _fftbench->nfft_min; benchmark.direction = LIQUID_FFT_FORWARD; benchmark.num_trials = 1; benchmark.flags = 0; benchmark.extime = 0.0f; benchmark.flops = 0.0f; // run the benchmark execute_benchmark_fft(&benchmark, _fftbench->runtime, _fftbench->library); benchmark_print(&benchmark); return; } else if (_fftbench->mode == RUN_FFTWBENCH) { printf("running composite FFTs from FFTW benchmark\n"); unsigned int nfftw[18] = {6,9,12,15,18,24,36,80,108,210,504, 1000,1960,4725,10368,27000,75600,165375}; unsigned int i; for (i=0; i<18; i++) { // initialize benchmark structure benchmark.nfft = nfftw[i]; benchmark.direction = LIQUID_FFT_FORWARD; benchmark.num_trials = 1; benchmark.flags = 0; // run the benchmark execute_benchmark_fft(&benchmark, _fftbench->runtime, _fftbench->library); benchmark_print(&benchmark); if (_fftbench->output_to_file) benchmark_print_to_file(_fftbench->fid, &benchmark); } return; } else if (_fftbench->mode == RUN_RADIX2) { printf("running all power-of-two FFTs from %u to %u:\n", _fftbench->nfft_min, _fftbench->nfft_max); unsigned int nfft = 1 << liquid_nextpow2(_fftbench->nfft_min); while ( nfft <= _fftbench->nfft_max) { // initialize benchmark structure benchmark.nfft = nfft; benchmark.direction = LIQUID_FFT_FORWARD; benchmark.num_trials = 1; benchmark.flags = 0; // run the benchmark execute_benchmark_fft(&benchmark, _fftbench->runtime, _fftbench->library); benchmark_print(&benchmark); if (_fftbench->output_to_file) benchmark_print_to_file(_fftbench->fid, &benchmark); nfft *= 2; }; return; } printf("running "); switch (_fftbench->mode) { case RUN_ALL: printf("all"); break; case RUN_COMPOSITE: printf("all composite"); break; case RUN_PRIME: printf("all prime"); break; case RUN_SINGLE: default:; } printf(" FFTs from %u to %u:\n", _fftbench->nfft_min, _fftbench->nfft_max); unsigned int nfft; for (nfft=_fftbench->nfft_min; nfft<=_fftbench->nfft_max; nfft++) { int isprime = liquid_is_prime(nfft); int isradix2 = (1 << liquid_nextpow2(nfft))==nfft ? 1 : 0; // check run mode if (_fftbench->mode == RUN_COMPOSITE && (isprime || isradix2)) continue; if (_fftbench->mode == RUN_PRIME && !isprime) continue; // run the transform benchmark.nfft = nfft; benchmark.direction = LIQUID_FFT_FORWARD; benchmark.num_trials = 1; benchmark.flags = 0; benchmark.extime = 0.0f; benchmark.flops = 0.0f; execute_benchmark_fft(&benchmark, _fftbench->runtime, _fftbench->library); if (_fftbench->verbose) benchmark_print(&benchmark); if (_fftbench->output_to_file) benchmark_print_to_file(_fftbench->fid, &benchmark); } } // execute single benchmark void execute_benchmark_fft(struct benchmark_s * _benchmark, float _runtime, library_t _library) { unsigned long int n = _benchmark->num_trials; struct rusage start, finish; unsigned int num_attempts = 0; do { // increment number of attempts num_attempts++; // set number of trials and run benchmark _benchmark->num_trials = n; // run appropriate library switch (_library) { case LIB_FLOAT: benchmark_fft(&start, &finish, _benchmark); break; case LIB_FFTW: benchmark_fftw(&start, &finish, _benchmark); break; default: fprintf(stderr,"error: execute_benchmark_fft(), invalid library\n"); exit(1); } // calculate execution time _benchmark->extime = calculate_execution_time(start, finish); // check exit criteria if (_benchmark->extime >= _runtime) { break; } else if (num_attempts == 30) { fprintf(stderr,"warning: benchmark could not execute over minimum run time\n"); break; } else { // increase number of trials n *= 2; } } while (1); // compute time per trial _benchmark->time_per_trial = _benchmark->extime / (float)_benchmark->num_trials; // computational bandwidth (see: http://www.fftw.org/speed/) _benchmark->flops = 5.0f * _benchmark->nfft * log2f(_benchmark->nfft) / _benchmark->time_per_trial; } // main benchmark script void benchmark_fft(struct rusage * _start, struct rusage * _finish, struct benchmark_s * _benchmark) { // initialize arrays, plan float complex * x = (float complex *) malloc((_benchmark->nfft)*sizeof(float complex)); float complex * y = (float complex *) malloc((_benchmark->nfft)*sizeof(float complex)); fftplan q = fft_create_plan(_benchmark->nfft, x, y, _benchmark->direction, _benchmark->flags); unsigned long int i; // initialize input with random values for (i=0; i<_benchmark->nfft; i++) x[i] = randnf() + randnf()*_Complex_I; // scale number of iterations to keep execution time // relatively linear unsigned int num_iterations = _benchmark->num_trials; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; inum_trials = num_iterations * 4; fft_destroy_plan(q); free(x); free(y); } // main benchmark script (FFTW) void benchmark_fftw(struct rusage * _start, struct rusage * _finish, struct benchmark_s * _benchmark) { // initialize arrays, plan float complex * x = (float complex *) fftwf_malloc((_benchmark->nfft)*sizeof(float complex)); float complex * y = (float complex *) fftwf_malloc((_benchmark->nfft)*sizeof(float complex)); fftwf_plan q = fftwf_plan_dft_1d(_benchmark->nfft, x, y, //_benchmark->direction, FFTW_FORWARD, FFTW_ESTIMATE); unsigned long int i; // initialize input with random values for (i=0; i<_benchmark->nfft; i++) x[i] = randnf() + randnf()*_Complex_I; // scale number of iterations to keep execution time // relatively linear unsigned int num_iterations = _benchmark->num_trials; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; inum_trials = num_iterations * 4; fftwf_destroy_plan(q); fftwf_free(x); fftwf_free(y); } void benchmark_print_to_file(FILE * _fid, struct benchmark_s * _benchmark) { fprintf(_fid," %12u %12u %12.4e %12.6f %12.3f\n", _benchmark->nfft, _benchmark->num_trials, _benchmark->extime, _benchmark->time_per_trial * 1e6f, _benchmark->flops * 1e-6f); } void benchmark_print(struct benchmark_s * _benchmark) { // format time/trial float time_format = _benchmark->time_per_trial; char time_units = convert_units(&time_format); printf(" %12u: %12u trials / %10.3f ms (%10.3f %cs/t) > %10.3f M flops\n", _benchmark->nfft, _benchmark->num_trials, _benchmark->extime * 1e3f, time_format, time_units, _benchmark->flops * 1e-6f); } liquid-dsp-1.7.0/bench/main.c000066400000000000000000000031231474751757600157670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // bench/main.c // // Benchmark generator script #include #include #include #include "benchmarkgen.h" int main(int argc, char*argv[]) { // create benchmarkgen object benchmarkgen q = benchmarkgen_create(); // parse files int i; for (i=1; i #include // null benchmark void benchmark_null(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { unsigned long int i; *_num_iterations *= 100; getrusage(RUSAGE_SELF, _start); unsigned int x = 0; for (i=0; i<*_num_iterations; i++) { // perform mindless task x <<= 1; x |= 1; x &= 0xff; x ^= 0xff; } *_num_iterations += (x & 0x1234) ? 0 : 1; getrusage(RUSAGE_SELF, _finish); } liquid-dsp-1.7.0/bootstrap.sh000077500000000000000000000024751474751757600162050ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2007 - 2016 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # bootstrap.sh # # This is the bootstrapping script to auto-generate a configure # script for checking build environments, etc. # rm -f config.cache aclocal.m4 aclocal autoconf autoheader #automake --foreign --add-missing liquid-dsp-1.7.0/cmake/000077500000000000000000000000001474751757600147015ustar00rootroot00000000000000liquid-dsp-1.7.0/cmake/FindSIMD.cmake000066400000000000000000000110241474751757600172360ustar00rootroot00000000000000INCLUDE(CheckCSourceRuns) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckCXXSourceRuns) SET(SSE4_CODE " #include int main() { float _v[8] = { 0.f, 1.f, 2.f, 3.f,}; float _h[8] = { 1.f,-1.f, 1.f,-1.f,}; __m128 v = _mm_loadu_ps(_v); __m128 h = _mm_loadu_ps(_h); __m128 s = _mm_mul_ps(v, h); // unload packed array float w[4]; _mm_storeu_ps(w, s); return (w[0]== 0.f && w[1]== -1.f && w[2]== 2.f && w[3]== -3.f) ? 0 : 1; } ") # TODO: distinguish between AVX, FMA, AVX2 SET(AVX2_CODE " #include int main() { float _v[8] = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f,}; float _h[8] = { 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f,}; __m256 v = _mm256_loadu_ps(_v); __m256 h = _mm256_loadu_ps(_h); __m256 s = _mm256_mul_ps(v, h); // unload packed array float w[4]; _mm256_storeu_ps(w, s); return (w[ 0]== 0.f && w[ 1]== -1.f && w[ 2]== 2.f && w[ 3]== -3.f && w[ 4]== 4.f && w[ 5]== -5.f && w[ 6]== 6.f && w[ 7]== -7.f) ? 0 : 1; } ") SET(AVX512_CODE " #include int main() { float _v[16] = { 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f,10.f,11.f,12.f,13.f,14.f,15.f,}; float _h[16] = { 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f, 1.f,-1.f,}; __m512 v = _mm512_loadu_ps(_v); __m512 h = _mm512_loadu_ps(_h); __m512 s = _mm512_mul_ps(v, h); // unload packed array float w[4]; _mm512_storeu_ps(w, s); return (w[ 0]== 0.f && w[ 1]== -1.f && w[ 2]== 2.f && w[ 3]== -3.f && w[ 4]== 4.f && w[ 5]== -5.f && w[ 6]== 6.f && w[ 7]== -7.f && w[ 8]== 8.f && w[ 9]== -9.f && w[10]==10.f && w[11]==-11.f && w[12]==12.f && w[13]==-13.f && w[14]==14.f && w[15]==-15.f) ? 0 : 1; } ") SET(NEON_CODE " #include int main() { float _v[4] = {1.0f, 2.0f, 3.0f, 4.0f}; float _h[4] = {2.0f, 4.0f, 6.0f, 8.0f}; float32x4_t v = vld1q_f32(_v); float32x4_t h = vld1q_f32(_h); float32x4_t s = vmulq_f32(h,v); // unload packed array float w[4]; vst1q_f32(w, s); return (w[0] == 2.0f && w[1] == 8.0f && w[2] == 18.0f && w[3] == 32.0f) ? 0 : -1; } ") # NOTE: altivec is extremely old at this point; I'm not sure if this code is even correct SET(ALTIVEC_CODE " int main() { vector float v = {1.0f, 2.0f, 3.0f, 4.0f}; vector float h = {2.0f, 4.0f, 6.0f, 8.0f}; vector float z = (vector float)(0); union { vector float r; float w[4]; } s; s.r = vec_madd(v, h, z); // unload packed array return (s.w[0]== 0.f && s.w[1]== -1.f && s.w[2]== 2.f && s.w[3]== -3.f) ? 0 : 1; } ") MACRO(CHECK_SIMD lang type flags) SET(__FLAG_I 1) SET(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS}) FOREACH(__FLAG ${flags}) #message("testing ${lang} ${type} ${__FLAG}") IF(NOT ${lang}_${type}_FOUND) SET(CMAKE_REQUIRED_FLAGS ${__FLAG}) # TODO: check that program runs and returns proper exit code 0 IF(lang STREQUAL "CXX") CHECK_CXX_SOURCE_RUNS("${${type}_CODE}" ${lang}_HAS_${type}_${__FLAG_I}) ELSE() CHECK_C_SOURCE_RUNS("${${type}_CODE}" ${lang}_HAS_${type}_${__FLAG_I}) ENDIF() IF(${lang}_HAS_${type}_${__FLAG_I}) SET(${lang}_${type}_FOUND TRUE CACHE BOOL "${lang} ${type} support") SET(${lang}_${type}_FLAGS "${__FLAG}" CACHE STRING "${lang} ${type} flags") ENDIF() MATH(EXPR __FLAG_I "${__FLAG_I}+1") ENDIF() ENDFOREACH() SET(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE}) IF(NOT ${lang}_${type}_FOUND) SET(${lang}_${type}_FOUND FALSE CACHE BOOL "${lang} ${type} support") SET(${lang}_${type}_FLAGS "" CACHE STRING "${lang} ${type} flags") ENDIF() SEPARATE_ARGUMENTS(${lang}_${type}_FLAGS) MARK_AS_ADVANCED(${lang}_${type}_FOUND ${lang}_${type}_FLAGS) ENDMACRO() # TODO: check msvc arch flags CHECK_SIMD(C "SSE4" " ;-msse4.2;/arch:SSE") CHECK_SIMD(C "AVX" " ;-mavx;/arch:AVX") CHECK_SIMD(C "AVX2" " ;-mavx2 -mfma -mf16c;/arch:AVX2") CHECK_SIMD(C "AVX512" " ;-mavx512f -mavx512dq -mavx512vl -mavx512bw -mfma;/arch:AVX512") CHECK_SIMD(C "NEON" " ;-ffast-math;/arch:armv8.0;/arch:armv9.0") CHECK_SIMD(C "ALTIVEC" " ;-fno-common -faltivec;/arch:altivec") CHECK_SIMD(CXX "SSE4" " ;-msse4.2;/arch:SSE") CHECK_SIMD(CXX "AVX" " ;-mavx;/arch:AVX") CHECK_SIMD(CXX "AVX2" " ;-mavx2 -mfma -mf16c;/arch:AVX2") CHECK_SIMD(CXX "AVX512" " ;-mavx512f -mavx512dq -mavx512vl -mavx512bw -mfma;/arch:AVX512") CHECK_SIMD(CXX "NEON" " ;-ffast-math;/arch:armv8.0;/arch:armv9.0") CHECK_SIMD(CXX "ALTIVEC" " ;-fno-common -faltivec;/arch:altivec") liquid-dsp-1.7.0/cmake/config.h.cmake000066400000000000000000000003071474751757600173760ustar00rootroot00000000000000#cmakedefine HAVE_GETOPT_LONG 1 #cmakedefine HAVE_GETOPT_H #cmakedefine HAVE_MEMORY_H #cmakedefine HAVE_STDIO_H #cmakedefine HAVE_STDLIB_H #cmakedefine HAVE_LIBC #cmakedefine SIZEOF_INT @SIZEOF_INT@ liquid-dsp-1.7.0/cmake/debug.cmake000066400000000000000000000011171474751757600167710ustar00rootroot00000000000000# dump a (sorted) list of cmake variables function(liquid_debug_print_vars) get_cmake_property(_variableNames VARIABLES) list (SORT _variableNames) foreach (_variableName ${_variableNames}) message(STATUS "${_variableName}=${${_variableName}}") endforeach() endfunction() liquid_debug_print_vars() message("top: CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}") message("top: CMAKE_BINARY_DIR = ${CMAKE_BINARY_DIR}") message("top: CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") message("top: CMAKE_CURRENT_BINARY_DIR = ${CMAKE_CURRENT_BINARY_DIR}") liquid-dsp-1.7.0/cmake/summary.cmake000066400000000000000000000105161474751757600174030ustar00rootroot00000000000000# status report function # Automatically align right column and selects text based on condition. function(liquid_status text) set(status_cond) set(status_then) set(status_else) set(status_current_name "cond") foreach(arg ${ARGN}) if(arg STREQUAL "THEN") set(status_current_name "then") elseif(arg STREQUAL "ELSE") set(status_current_name "else") else() list(APPEND status_${status_current_name} ${arg}) endif() endforeach() if(DEFINED status_cond) set(status_placeholder_length 23) string(RANDOM LENGTH ${status_placeholder_length} ALPHABET " " status_placeholder) string(LENGTH "${text}" status_text_length) if(status_text_length LESS status_placeholder_length) string(SUBSTRING "${text}${status_placeholder}" 0 ${status_placeholder_length} status_text) elseif(DEFINED status_then OR DEFINED status_else) message(STATUS "${text}") set(status_text "${status_placeholder}") else() set(status_text "${text}") endif() if(DEFINED status_then OR DEFINED status_else) if(${status_cond}) string(REPLACE ";" " " status_then "${status_then}") string(REGEX REPLACE "^[ \t]+" "" status_then "${status_then}") message(STATUS "${status_text} ${status_then}") else() string(REPLACE ";" " " status_else "${status_else}") string(REGEX REPLACE "^[ \t]+" "" status_else "${status_else}") message(STATUS "${status_text} ${status_else}") endif() else() string(REPLACE ";" " " status_cond "${status_cond}") string(REGEX REPLACE "^[ \t]+" "" status_cond "${status_cond}") message(STATUS "${status_text} ${status_cond}") endif() else() message(STATUS "${text}") endif() endfunction() # Function merging lists of compiler flags to single string. # Usage: # liquid_merge_flag_lists(out_variable [] [] ...) function(liquid_merge_flag_lists out_var) set(__result "") foreach(__list ${ARGN}) foreach(__flag ${${__list}}) string(STRIP ${__flag} __flag) set(__result "${__result} ${__flag}") endforeach() endforeach() string(STRIP ${__result} __result) set(${out_var} ${__result} PARENT_SCOPE) endfunction() # Prints accumulated liquid-dsp configuration summary # Usage: # liquid_print_config_summary() function(liquid_print_config_summary) liquid_merge_flag_lists(__flags_rel CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS) liquid_merge_flag_lists(__flags_deb CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS) liquid_status("") liquid_status("******************* liquid-dsp Configuration Summary *******************") liquid_status("General:") liquid_status(" Version : ${PROJECT_VERSION}") liquid_status(" System : ${CMAKE_SYSTEM_NAME}") liquid_status(" C++ compiler : ${CMAKE_CXX_COMPILER}") liquid_status(" Release CXX flags : ${__flags_rel}") liquid_status(" Debug CXX flags : ${__flags_deb}") liquid_status(" Build type : ${CMAKE_BUILD_TYPE}") liquid_status("") liquid_status(" BUILD_EXAMPLES : ${BUILD_EXAMPLES}") liquid_status(" BUILD_SANDBOX : ${BUILD_SANDBOX}") liquid_status(" BUILD_AUTOTESTS : ${BUILD_AUTOTESTS}") liquid_status(" BUILD_BENCHMARKS : ${BUILD_BENCHMARKS}") liquid_status(" BUILD_DOC : ${BUILD_DOC}") liquid_status(" COVERAGE : ${COVERAGE}") liquid_status("") liquid_status("Acceleration:") liquid_status(" NEON : " C_NEON_FOUND THEN "Yes" ELSE "No") liquid_status(" SSE4 : " C_SSE4_FOUND THEN "Yes" ELSE "No") liquid_status(" AVX : " C_AVX_FOUND THEN "Yes" ELSE "No") liquid_status(" AVX2 : " C_AVX2_FOUND THEN "Yes" ELSE "No") liquid_status(" AVX512 : " C_AVX512_FOUND THEN "Yes" ELSE "No") liquid_status(" AltiVec : " C_ALTIVEC_FOUND THEN "Yes" ELSE "No") #liquid_status(" Pthread : " USE_PTHREAD THEN "Yes" ELSE "No") #liquid_status(" TBB : " USE_TBB AND TBB_FOUND THEN "Yes (ver. ${TBB_INTERFACE_VERSION})" ELSE "No") #liquid_status(" OMP : " USE_OMP AND OMP_FOUND THEN "Yes" ELSE "No") liquid_status("") liquid_status("Install:") liquid_status(" Install path : ${CMAKE_INSTALL_PREFIX}") liquid_status("") endfunction() liquid-dsp-1.7.0/cmake/version.c.in000066400000000000000000000004321474751757600171360ustar00rootroot00000000000000// const char * version = "@PROJECT_VERSION@"; unsigned int version_major = @PROJECT_VERSION_MAJOR@; unsigned int version_minor = @PROJECT_VERSION_MINOR@+0; unsigned int version_patch = @PROJECT_VERSION_PATCH@+0; unsigned int version_tweak = @PROJECT_VERSION_TWEAK@+0; liquid-dsp-1.7.0/configure.ac000066400000000000000000000276411474751757600161210ustar00rootroot00000000000000# Copyright (c) 2007 - 2025 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # liquid-dsp library configure # Process with autoconf to generate configure script # AC_INIT([liquid-dsp],[1.7.0],[joseph@liquidsdr.org]) AC_CONFIG_SRCDIR([src/libliquid.c]) AC_CONFIG_MACRO_DIR([scripts]) # permit auxiliary scripts directory (e.g. config.sub, config.guess, install-sh) AC_CONFIG_AUX_DIR(scripts/) # Specify 'C' language AC_LANG(C) # uncomment the following line to reset "CFLAGS" variable; it defaults to '-g -O2' #: ${CFLAGS=""} # Autoheader AH_TEMPLATE([LIQUID_FFTOVERRIDE], [Force internal FFT even if libfftw is available]) AH_TEMPLATE([LIQUID_SIMDOVERRIDE], [Force overriding of SIMD (use portable C code)]) AH_TEMPLATE([LIQUID_SUPPRESS_ERROR_OUTPUT],[Suppress printing errors to stderr]) AH_TEMPLATE([LIQUID_STRICT_EXIT], [Enable strict program exit on error]) AC_CONFIG_HEADERS([config.h]) AH_TOP([ #ifndef __LIQUID_CONFIG_H__ #define __LIQUID_CONFIG_H__ ]) AH_BOTTOM([ #endif // __LIQUID_CONFIG_H__ ]) # Configure options AC_ARG_ENABLE(debug-messages, AS_HELP_STRING([--enable-debug-messages],[enable verbose debug messages (-DDEBUG)]), [DEBUG_MSG_OPTION="-DDEBUG"], [DEBUG_MSG_OPTION=""] ) AC_ARG_ENABLE(simdoverride, AS_HELP_STRING([--enable-simdoverride],[use portable C code for dotprod, etc. even if SIMD extensions are available]), [AC_DEFINE(LIQUID_SIMDOVERRIDE)], [], ) AC_ARG_ENABLE(fftoverride, AS_HELP_STRING([--enable-fftoverride],[use internal fft even if libfftw is available]), [AC_DEFINE(LIQUID_FFTOVERRIDE)], [], ) # code coverage AC_ARG_ENABLE(coverage, AS_HELP_STRING([--enable-coverage],[enable flags to test code coverage]), [ # check that gcovr program is installed AC_CHECK_PROG(HAVE_GCOVR,gcovr,yes) AS_IF([test x"$HAVE_GCOVR" != x"yes"], [AC_MSG_ERROR(Need gcovr with coverage option)], [COVERAGE_OPTION="--coverage"])], [COVERAGE_OPTION=""] ) AC_ARG_ENABLE(suppress-errors, AS_HELP_STRING([--enable-suppress-errors],[suppress printing errors to stderr]), [AC_DEFINE(LIQUID_SUPPRESS_ERROR_OUTPUT)], [], ) AC_ARG_ENABLE(strict, AS_HELP_STRING([--enable-strict],[use strict error handling at runtime]), [AC_DEFINE(LIQUID_STRICT_EXIT)], [], ) # Check for necessary programs AC_PROG_CC AC_PROG_SED AC_PROG_GREP AC_PROG_INSTALL AC_PROG_RANLIB # Check for necessary libraries, library functions AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_FUNC_REALLOC # AC_CHECK_LIB (library, function, [action-if-found], [action-if-not-found], [other-libraries]) AC_CHECK_LIB([c],[main],[],[AC_MSG_ERROR(Could not use standard C library)], []) AC_CHECK_LIB([m],[main],[],[AC_MSG_ERROR(Could not use standard math library)],[]) # AC_CHECK_FUNC(function, [action-if-found], [action-if-not-found]) AC_CHECK_FUNCS([malloc realloc free memset memmove],[], [AC_MSG_ERROR(Could not use memory allocation functions)]) AC_CHECK_FUNCS([sinf cosf expf cargf cexpf crealf cimagf sqrtf],[], [AC_MSG_ERROR(Could not use special math functions)],) # Check for necessary header files AC_CHECK_HEADERS([stdio.h stdlib.h complex.h string.h getopt.h sys/resource.h float.h inttypes.h limits.h stdlib.h string.h unistd.h],[], [AC_MSG_ERROR(Could not use standard headers)]) # Check for optional header files, libraries, programs AC_CHECK_HEADERS(fec.h fftw3.h) AC_CHECK_LIB([fftw3f], [fftwf_plan_dft_1d], [], [AC_MSG_WARN(fftw3 library useful but not required)], []) AC_CHECK_LIB([fec], [create_viterbi27], [], [AC_MSG_WARN(fec library useful but not required)], []) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Check size of certain variables AC_CHECK_SIZEOF(short int) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long int) AC_CHECK_SIZEOF(long long int) # AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) # Try to guess the "native" architecture of the target to use with gcc's # -march or -mtune flags. Default success action adds $ax_cv_gcc_archflag to # $CFLAGS (sets to "unknown" on failure). #AX_GCC_ARCHFLAG([no],[],[]) # get canonical target architecture AC_CANONICAL_TARGET # override SIMD if test "${enable_simdoverride+set}" = set; then # portable C version MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.o \ src/dotprod/src/dotprod_crcf.o \ src/dotprod/src/dotprod_rrrf.o \ src/dotprod/src/sumsq.o" ARCH_OPTION="" else # Check canonical system case $target_cpu in i386|i486|i586|i686|x86|x86_64) # check for MMX/SSE/AVX CPU extensions and intrinsics headers # MMX : mmintrin.h # SSE : xmmintrin.h # SSE2 : emmintrin.h # SSE3 : pmmintrin.h # SSSE3 : tmmintrin.h # SSE4.1/2: smmintrin.h # AVX : immintrin.h # AVX2 : immintrin.h # AVX512 : immintrin.h AX_EXT if [ test "$ax_cv_have_avx512f_ext" = yes ]; then # AVX512 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx512f.o \ src/dotprod/src/dotprod_crcf.avx512f.o \ src/dotprod/src/dotprod_rrrf.avx512f.o \ src/dotprod/src/sumsq.avx512f.o" ARCH_OPTION='-mavx512f' elif [ test "$ax_cv_have_avx2_ext" = yes ]; then # AVX2 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ src/dotprod/src/dotprod_rrrf.avx.o \ src/dotprod/src/sumsq.avx.o" ARCH_OPTION='-mavx2' elif [ test "$ax_cv_have_avx_ext" = yes ]; then # AVX extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.avx.o \ src/dotprod/src/dotprod_crcf.avx.o \ src/dotprod/src/dotprod_rrrf.avx.o \ src/dotprod/src/sumsq.avx.o" ARCH_OPTION='-mavx' elif [ test "$ax_cv_have_sse41_ext" = yes ]; then # SSE4.1/2 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ src/dotprod/src/dotprod_crcf.sse.o \ src/dotprod/src/dotprod_rrrf.sse.o \ src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse4.1' elif [ test "$ax_cv_have_sse3_ext" = yes ]; then # SSE3 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ src/dotprod/src/dotprod_crcf.sse.o \ src/dotprod/src/dotprod_rrrf.sse.o \ src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse3' elif [ test "$ax_cv_have_sse2_ext" = yes ]; then # SSE2 extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.sse.o \ src/dotprod/src/dotprod_crcf.sse.o \ src/dotprod/src/dotprod_rrrf.sse.o \ src/dotprod/src/sumsq.sse.o" ARCH_OPTION='-msse2' else # portable C version MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.o \ src/dotprod/src/dotprod_crcf.o \ src/dotprod/src/dotprod_rrrf.o \ src/dotprod/src/sumsq.o" fi;; powerpc*) MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.o \ src/dotprod/src/dotprod_rrrf.av.o \ src/dotprod/src/dotprod_crcf.av.o \ src/dotprod/src/sumsq.o" ARCH_OPTION="-fno-common -faltivec";; armv1*|armv2*|armv3*|armv4*|armv5*|armv6*) # assume neon instructions are NOT available MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.o \ src/dotprod/src/dotprod_crcf.o \ src/dotprod/src/dotprod_rrrf.o \ src/dotprod/src/sumsq.o" ARCH_OPTION="-ffast-math";; arm|armv7*|armv8*|aarch64) # assume neon instructions are available # TODO: check for Neon availability # ARM architecture : use neon extensions MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.neon.o \ src/dotprod/src/dotprod_crcf.neon.o \ src/dotprod/src/dotprod_rrrf.neon.o \ src/dotprod/src/sumsq.o" case $target_os in darwin*) # M1 mac, ARM architecture : use neon extensions ARCH_OPTION="-ffast-math";; *) # TODO: check these flags #ARCH_OPTION="-ffast-math -mcpu=cortex-a8 -mfloat-abi=softfp -mfpu=neon";; ARCH_OPTION="-ffast-math -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4";; esac;; *) # unknown architecture : use portable C version MLIBS_DOTPROD="src/dotprod/src/dotprod_cccf.o \ src/dotprod/src/dotprod_crcf.o \ src/dotprod/src/dotprod_rrrf.o \ src/dotprod/src/sumsq.o" ARCH_OPTION="";; esac fi # for now all vector operations are portable C versions MLIBS_VECTOR="src/vector/src/vectorf_add.port.o \ src/vector/src/vectorf_norm.port.o \ src/vector/src/vectorf_mul.port.o \ src/vector/src/vectorf_trig.port.o \ src/vector/src/vectorcf_add.port.o \ src/vector/src/vectorcf_norm.port.o \ src/vector/src/vectorcf_mul.port.o \ src/vector/src/vectorcf_trig.port.o" case $target_os in darwin*) AN_MAKEVAR([LIBTOOL], [AC_PROG_LIBTOOL]) AN_PROGRAM([libtool], [AC_PROG_LIBTOOL]) AC_DEFUN([AC_PROG_LIBTOOL], [AC_CHECK_TOOL(LIBTOOL, libtool, :)]) AC_PROG_LIBTOOL AR_LIB=ar # archive extension SH_LIB=dylib # shared library extension REBIND="" ;; *) AN_MAKEVAR([AR], [AC_PROG_AR]) AN_PROGRAM([ar], [AC_PROG_AR]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) AC_PROG_AR AR_LIB=a # archive extension SH_LIB=so # shared library extension REBIND=ldconfig ;; esac # # autoconf variable substitutions # AC_SUBST(LIBS) # shared libraries (-lc, -lm, etc.) AC_SUBST(MLIBS_DOTPROD) # AC_SUBST(MLIBS_VECTOR) # AC_SUBST(AR_LIB) # archive library AC_SUBST(SH_LIB) # output shared library target AC_SUBST(REBIND) # rebinding tool (e.g. ldconfig) AC_SUBST(ARCH_OPTION) # compiler architecture option AC_SUBST(DEBUG_MSG_OPTION) # debug messages option (.e.g -DDEBUG) AC_SUBST(COVERAGE_OPTION) # source code coverage option (e.g. -fprofile-arcs -ftest-coverage) AC_SUBST(CLIB) # C library linkage (e.g. '-lc') AC_CONFIG_FILES([makefile]) AC_OUTPUT liquid-dsp-1.7.0/doc/000077500000000000000000000000001474751757600143665ustar00rootroot00000000000000liquid-dsp-1.7.0/doc/CMakeLists.txt000066400000000000000000000000361474751757600171250ustar00rootroot00000000000000# documentation build script liquid-dsp-1.7.0/examples/000077500000000000000000000000001474751757600154375ustar00rootroot00000000000000liquid-dsp-1.7.0/examples/.gitignore000066400000000000000000000000121474751757600174200ustar00rootroot00000000000000*_example liquid-dsp-1.7.0/examples/CMakeLists.txt000066400000000000000000000113741474751757600202050ustar00rootroot00000000000000# build configuration for examples set(EXAMPLES agc_crcf_example agc_crcf_squelch_example agc_crcf_qpsk_example agc_rrrf_example ampmodem_example asgramcf_example asgramf_example autocorr_cccf_example bpacketsync_example bpresync_example bsequence_example cbufferf_example cgsolve_example channel_cccf_example compand_example compand_cf_example complementary_codes_example conversion_example crc_example cpfskmodem_example cpfskmodem_psd_example cvsd_example detector_cccf_example dds_cccf_example dsssframesync_example dotprod_rrrf_example dotprod_cccf_example eqlms_cccf_block_example eqlms_cccf_blind_example eqlms_cccf_decisiondirected_example eqlms_cccf_example eqrls_cccf_example error_handling_example fec_example fec_soft_example fdelay_rrrf_example fft_example fftfilt_crcf_example firdecim_crcf_example firfarrow_rrrf_example firfilt_cccf_example firfilt_cccf_notch_example firfilt_crcf_copy_example firfilt_crcf_example firfilt_crcf_dcblocker_example firfilt_rrrf_example firdes_doppler_example firdes_kaiser_example firdespm_callback_example firdespm_halfband_example firdespm_example firdespm_lowpass_example firhilb_example firhilb_decim_example firhilb_filter_example firhilb_interp_example firpfb_rrrf_example firpfbch2_crcf_example firpfbch2_crcf_reconstruct_example firpfbchr_crcf_example firinterp_crcf_example firinterp_firdecim_crcf_example firinterp_rrrf_linear_example firinterp_rrrf_window_example firpfbch_crcf_example firpfbch_crcf_analysis_example firpfbch_crcf_msource_example firpfbch_crcf_synthesis_example flexframesync_debug_example flexframesync_example flexframesync_reconfig_example framesync64_example framesync64_performance_example freqmodem_example fskframesync_example fskmodem_example fskmodem_waterfall_example gasearch_example gasearch_knapsack_example gmskframesync_example gmskmodem_example gmsk_eqlms_example gmsk_tracking_example gradsearch_datafit_example gradsearch_example interleaver_example interleaver_soft_example interleaver_scatterplot_example iirdes_example iirdes_analog_example iirdes_pll_example iirdecim_crcf_example iirfilt_cccf_example iirfilt_crcf_example iirfilt_crcf_dcblocker_example iirhilb_example iirhilb_filter_example iirinterp_crcf_example kaiser_window_example kbd_window_example lpc_example libliquid_example matched_filter_example math_lngamma_example math_primitive_root_example modem_arb_example modem_example modem_pi4dqpsk_example modem_soft_example modular_arithmetic_example msequence_autocorr_example msequence_example msequence_generator_example msourcecf_example msresamp_crcf_example msresamp_crcf_noise_example msresamp2_crcf_example nco_crcf_mix_example nco_crcf_tone_example nco_example nco_pll_example nco_pll_real_example nco_pll_modem_example nyquist_filter_example ofdmflexframesync_example ofdmframesync_example ordfilt_rrrf_example packetizer_example packetizer_soft_example pll_example polyfit_comparison_example polyfit_example polyfit_lagrange_example poly_findroots_example qdetector_cccf_example qdsync_cccf_example qpacketmodem_performance_example qpacketmodem_example qpilotsync_example qnsearch_example qs1dsearch_example quantize_example random_histogram_example repack_bytes_example rresamp_crcf_example rresamp_crcf_partition_example rresamp_crcf_rnyquist_example rresamp_rrrf_example resamp_crcf_example resamp_crcf_noise_example resamp_crcf_rate_match_example resamp2_cccf_example resamp2_crcf_example resamp2_crcf_decim_example resamp2_crcf_filter_example resamp2_crcf_interp_example ricek_channel_example scramble_example smatrix_example spgramcf_example spgramf_example spwaterfallcf_example symsync_crcf_example symsync_crcf_full_example symsync_crcf_kaiser_example symstreamcf_delay_example symstreamcf_example symstreamrcf_delay_example symstreamrcf_example symtrack_cccf_example wdelayf_example windowf_example window_enbw_example windowing_example ) foreach(example IN LISTS EXAMPLES) add_executable(${example} ${example}.c) target_include_directories(${example} PRIVATE ${INCLUDE}) target_link_libraries(${example} ${LIBNAME}) # add example program as a test #add_test(NAME ${example} COMMAND ${example}) endforeach() liquid-dsp-1.7.0/examples/README.md000066400000000000000000000644001474751757600167220ustar00rootroot00000000000000 liquid-dsp examples =================== This directory contains all the examples for interfacing the liquid modules. * `agc_crcf_example.c`: Automatic gain control example demonstrating its transient response. * `agc_crcf_qpsk_example.c`: Automatic gain control test for data signals with fluctuating signal levels. QPSK modulation introduces periodic random zero-crossings which gives instantaneous amplitude levels near zero. This example tests the response of the AGC to these types of signals. * `ampmodem_example.c`: Tests simple modulation/demodulation of the ampmodem (analog amplitude modulator/demodulator) with noise, carrier phase, and carrier frequency offsets. * `asgramcf_example.c`: ASCII spectrogram example for complex inputs. This example demonstrates the functionality of the ASCII spectrogram. A sweeping complex sinusoid is generated and the resulting spectral periodogram is printed to the screen. * `asgramf_example.c`: ASCII spectrogram example for real-valued input. This example demonstrates the functionality of the ASCII spectrogram for real-valued input siganls. A cosine signal with time-varying frequency is generated and the resulting spectral periodogram is printed to the screen. Because the time signal has no complex component, its spectrum is symmetric. * `autocorr_cccf_example.c`: This example demonstrates the autocorr (auto-correlation) object functionality. A random time-domain sequence is generated which exhibits time-domain repetitions (auto-correlation properties), for example: abcdabcdabcd....abcd. The sequence is pushed through the autocorr object, and the results are written to an output file. The command-line arguments allow the user to experiment with the sequence length, number of sequence repetitions, and properties of the auto-correlator, as well as signal-to- noise ratio. * `bpacketsync_example.c`: * `bpresync_example.c`: This example demonstrates the binary pre-demodulator synchronizer. A random binary sequence is generated, modulated with BPSK, and then interpolated. The resulting sequence is used to generate a bpresync object which in turn is used to detect a signal in the presence of carrier frequency and timing offsets and additive white Gauss noise. * `bsequence_example.c`: This example demonstrates the interface to the bsequence (binary sequence) object. The bsequence object acts like a buffer of bits which are stored and manipulated efficiently in memory. * `bufferf_example.c`: * `cgsolve_example.c`: Solve linear system of equations `Ax = b` using the conjugate- gradient method where A is a symmetric positive-definite matrix. Compare speed to matrixf_linsolve() for same system. * `chromosome_example.c`: * `compand_cf_example.c`: * `compand_example.c`: This example demonstrates the interface to the compand function (compression, expansion). The compander is typically used with the quantizer to increase the dynamic range of the converter, particularly for low-level signals. The transfer function is computed (empirically) and printed to the screen. * `complementary_codes_example.c`: This example demonstrates how to generate complementary binary codes in liquid. A pair of codes is generated using the bsequence interface, their auto-correlations are computed, and the result is summed and printed to the screen. The results are also printed to an output file, which plots the sequences and their auto-correlations. SEE ALSO: `bsequence_example.c` `msequence_example.c` * `cpfskmodem_example.c`: * `conversion_example.c`: This example demonstrates conversion from complex baseband to a real-valued signal, and then down-conversion back to complex baseband while removing the negative image. STEP 1: A signal is generated at complex baseband consisting of narrow-band filtered noise and an offset tone (to show asymmetry in the transmit spectrum). STEP 2: The signal is mixed up to a carrier 'fc' (relative to the sampling frequency) and the real-component of the result is retained. This is the DAC output. The spectrum of this signal has two images: one at +fc, the other at -fc. STEP 3: The DAC output is mixed back down to complex baseband and the lower image is (mostly) filtered off. Reminants of the lower frequency component are still visible due to the wide-band and low-order filter on the receiver. The received complex baseband signal also has a reduction in power by 2 because half the signal's energy (the negative image) is filtered off. * `crc_example.c`: Cyclic redundancy check (CRC) example. This example demonstrates how a CRC can be used to validate data received through un-reliable means (e.g. a noisy channel). A CRC is, in essence, a strong algebraic error detection code that computes a key on a block of data using base-2 polynomials. Also available is a checksum for data validation. SEE ALSO: `fec_example.c` * `cvsd_example.c`: Continuously-variable slope delta example, sinusoidal input. This example demonstrates the CVSD audio encoder interface, and its response to a sinusoidal input. The output distortion ratio is computed, and the time-domain results are written to a file. * `dds_cccf_example.c`: Direct digital synthesizer example. This example demonstrates the interface to the direct digital synthesizer. A baseband pulse is generated and then efficiently up-converted (interpolated and mixed up) using the DDS object. The resulting signal is then down-converted (mixed down and decimated) using the same DDS object. Results are written to a file. * `dotprod_cccf_example.c`: This example demonstrates the interface to the complex floating-point dot product object (dotprod_cccf). * `dotprod_rrrf_example.c`: This example demonstrates the interface to the floating-point dot product object (dotprod_rrrf). * `eqlms_cccf_blind_example.c`: This example tests the least mean-squares (LMS) equalizer (EQ) on a signal with an unknown modulation and carrier frequency offset. That is, the equalization is done completely blind of the modulation scheme or its underlying data set. The error estimate assumes a constant modulus linear modulation scheme. This works surprisingly well even more amplitude-modulated signals, e.g. 'qam16'. * `eqlms_cccf_block_example.c`: This example tests the least mean-squares (LMS) equalizer (EQ) on a signal with an unknown modulation and carrier frequency offset. Equalization is performed blind on a block of samples and the reulting constellation is output to a file for plotting. * `eqlms_cccf_decisiondirected_example.c`: Tests least mean-squares (LMS) equalizer (EQ) on a signal with a known linear modulation scheme, but unknown data. The equalizer is updated using decision-directed demodulator output samples. * `eqlms_cccf_example.c`: * `eqrls_cccf_example.c`: * `error_handling_example.c`: This example demonstrates error handling in liquid. * `fct_example.c`: * `fec_example.c`: This example demonstrates the interface for forward error-correction (FEC) codes. A buffer of data bytes is encoded and corrupted with several errors. The decoder then attempts to recover the original data set. The user may select the FEC scheme from the command-line interface. SEE ALSO: `crc_example.c` `checksum_example.c` `packetizer_example.c` * `fec_soft_example.c`: This example demonstrates the interface for forward error-correction (FEC) codes with soft-decision decoding. A buffer of data bytes is encoded before the data are corrupted with at least one error and noise. The decoder then attempts to recover the original data set from the soft input bits. The user may select the FEC scheme from the command-line interface. SEE ALSO: `fec_example.c` `packetizer_soft_example.c` * `fft_example.c`: This example demonstrates the interface to the fast discrete Fourier transform (FFT). SEE ALSO: `mdct_example.c` `fct_example.c` * `fftfilt_crcf_example.c` Complex FFT-based finite impulse response filter example. This example demonstrates the functionality of firfilt by designing a low-order prototype and using it to filter a noisy signal. The filter coefficients are real, but the input and output arrays are complex. The filter order and cutoff frequency are specified at the beginning, and the result is compared to the regular corresponding firfilt_crcf output. SEE ALSO: `firfilt_crcf_example.c` * `firdecim_crcf_example.c`: This example demonstrates the interface to the firdecim (finite impulse response decimator) family of objects. Data symbols are generated and then interpolated according to a finite impulse response square-root Nyquist filter. The resulting sequence is then decimated with the same filter, matched to the interpolator. SEE ALSO: `firinterp_crcf_example.c` * `firdes_kaiser_example.c`: This example demonstrates finite impulse response filter design using a Kaiser window. SEE ALSO: `firdespm_example.c` * `firdespm_example.c`: This example demonstrates finite impulse response filter design using the Parks-McClellan algorithm. SEE ALSO: `firdes_kaiser_example.c` * `firfarrow_rrrf_sine_example.c`: * `firfilt_rrrf_example.c`: * `firfilt_cccf_example.c`: This example demonstrates the finite impulse response (FIR) filter with complex coefficients as a cross-correlator between transmitted and received sequences. * `firfilt_crcf_example.c`: Complex finite impulse response filter example. Demonstrates the functionality of firfilt by designing a low-order prototype and using it to filter a noisy signal. The filter coefficients are real, but the input and output arrays are complex. The filter order and cutoff frequency are specified at the beginning. * `firhilb_decim_example.c`: Hilbert transform: 2:1 real-to-complex decimator. This example demonstrates the functionality of firhilb (finite impulse response Hilbert transform) decimator which converts a real time series into a complex one with half the number of samples. The input is a real-valued sinusoid of N samples. The output is a complex-valued sinusoid of N/2 samples. SEE ALSO: `firhilb_interp_example.c` * `firhilb_example.c`: * `firhilb_interp_example.c`: Hilbert transform: 1:2 complex-to-real interpolator. This example demonstrates the functionality of firhilb (finite impulse response Hilbert transform) interpolator which converts a complex time series into a real one with twice the number of samples. The input is a complex-valued sinusoid of N samples. The output is a real-valued sinusoid of 2*N samples. SEE ALSO: `firhilb_decim_example.c` * `firpfbch2_crcf_example.c`: Example of the finite impulse response (FIR) polyphase filterbank (PFB) channelizer with an output rate of 2 Fs / M as an (almost) perfect reconstructive system. * `firinterp_crcf_example.c`: This example demonstrates the interp object (interpolator) interface. Data symbols are generated and then interpolated according to a finite impulse response Nyquist filter. * `firpfbch_crcf_analysis_example.c`: Example of the analysis channelizer filterbank. The input signal is comprised of several signals spanning different frequency bands. The channelizer downconverts each to baseband (maximally decimated), and the resulting spectrum of each is plotted. * `firpfbch_crcf_example.c`: Finite impulse response (FIR) polyphase filter bank (PFB) channelizer example. This example demonstrates the functionality of the polyphase filter bank channelizer and how its output is mathematically equivalent to a series of parallel down-converters (mixers/decimators). Both the synthesis and analysis filter banks are presented. * `firpfbch_crcf_synthesis_example.c`: Example of the synthesis channelizer filterbank. Random symbols are generated and loaded into the bins of the channelizer and the time-domain signal is synthesized. Subcarriers around the band edges are disabled as well as those near 0.25 to demonstrate the synthesizer's ability to efficiently notch the spectrum. The results are printed to a file for plotting. * `flexframesync_example.c`: This example demonstrates the basic interface to the flexframegen and flexframesync objects used to completely encapsulate raw data bytes into frame samples (nearly) ready for over-the-air transmission. A 14-byte header and variable length payload are encoded into baseband symbols using the flexframegen object. The resulting symbols are interpolated using a root-Nyquist filter and the resulting samples are then fed into the flexframesync object which attempts to decode the frame. Whenever frame is found and properly decoded, its callback function is invoked. * `flexframesync_reconfig_example.c`: Demonstrates the reconfigurability of the flexframegen and flexframesync objects. * `framesync64_example.c`: This example demonstrates the interfaces to the framegen64 and framesync64 objects used to completely encapsulate data for over-the-air transmission. A 24-byte header and 64-byte payload are encoded, modulated, and interpolated using the framegen64 object. The resulting complex baseband samples are corrupted with noise and moderate carrier frequency and phase offsets before the framesync64 object attempts to decode the frame. The resulting data are compared to the original to validate correctness. SEE ALSO: `flexframesync_example.c` * `freqmodem_example.c`: * `fskmodem_example.c`: This example demonstrates the M-ary frequency-shift keying (MFSK) modem in liquid. A message signal is modulated and the resulting signal is recovered using a demodulator object. * `gasearch_example.c`: * `gasearch_knapsack_example.c`: * `gmskmodem_example.c`: * `gradsearch_example.c`: * `gradsearch_datafit_example.c`: Fit 3-parameter curve to sampled data set in the minimum mean-squared error sense. * `iirdes_analog_example.c`: Tests infinite impulse response (IIR) analog filter design. While this example seems purely academic as IIR filters used in liquid are all digital, it is important to realize that they are all derived from their analog counterparts. This example serves to check the response of the analog filters to ensure they are correct. The results of design are written to a file. SEE ALSO: `iirdes_example.c` `iirfilt_crcf_example.c` * `iirdes_example.c`: Tests infinite impulse response (IIR) digital filter design. SEE ALSO: `iirdes_analog_example.c` `iirfilt_crcf_example.c` * `iirdes_pll_example.c`: This example demonstrates 2nd-order IIR phase-locked loop filter design with a practical simulation. SEE ALSO: `nco_pll_example.c` `nco_pll_modem_example.c` * `iirfilt_cccf_example.c`: Complex infinite impulse response filter example. Demonstrates the functionality of iirfilt with complex coefficients by designing a filter with specified parameters and then filters noise. * `iirfilt_crcf_example.c`: Complex infinite impulse response filter example. Demonstrates the functionality of iirfilt by designing a low-order prototype (e.g. Butterworth) and using it to filter a noisy signal. The filter coefficients are real, but the input and output arrays are complex. The filter order and cutoff frequency are specified at the beginning. * `iirinterp_crcf_example.c`: This example demonstrates the iirinterp object (IIR interpolator) interface. * `interleaver_example.c`: This example demonstrates the functionality of the liquid interleaver object. Interleavers serve to distribute grouped bit errors evenly throughout a block of data. This aids certain forward error-correction codes in correcting bit errors. In this example, data bits are interleaved and de-interleaved; the resulting sequence is validated to match the original. SEE ALSO: `packetizer_example.c` * `interleaver_scatterplot_example.c`: * `interleaver_soft_example.c`: * `kbd_window_example.c`: * `lpc_example.c`: This example demonstrates linear prediction in liquid. An input signal is generated which exhibits a strong temporal correlation. The linear predictor generates an approximating all-pole filter which minimizes the squared error between the prediction and the actual output. * `matched_filter_example.c`: * `math_lngamma_example.c`: Demonstrates accuracy of lngamma function. * `mdct_example.c`: * `modem_arb_example.c`: This example demonstrates the functionality of the arbitrary modem, a digital modulator/demodulator object with signal constellation points chosen arbitrarily. A simple bit-error rate simulation is then run to test the performance of the modem. The results are written to a file. SEE ALSO: `modem_example.c` * `modem_example.c`: This example demonstrates the digital modulator/demodulator (modem) object. Data symbols are modulated into complex samples which are then demodulated without noise or phase offsets. The user may select the modulation scheme via the command-line interface. SEE ALSO: `modem_arb_example.c` * `modem_soft_example.c`: This example demonstrates soft demodulation of linear modulation schemes. * `modular_arithmetic_example.c`: This example demonstrates some modular arithmetic functions. * `msequence_example.c`: This example demonstrates the auto-correlation properties of a maximal-length sequence (m-sequence). An m-sequence of a certain length is used to generate two binary sequences (buffers) which are then cross-correlated. The resulting correlation produces -1 for all values except at index zero, where the sequences align. SEE ALSO: `bsequence_example.c` * `msourcecf_example.c`: This example demonstrates generating multiple signal sources simultaneously for testing using the msource (multi-source) family of objects. * `msresamp_crcf_example.c`: Demonstration of the multi-stage arbitrary resampler. * `msresamp2_crcf_example.c`: Demonstration of the multi-stage half-band resampler. * `nco_example.c`: This example demonstrates the most basic functionality of the numerically-controlled oscillator (NCO) object. SEE ALSO: `nco_pll_example.c` `nco_pll_modem_example.c` * `nco_pll_example.c`: This example demonstrates how the use the nco/pll object (numerically-controlled oscillator with phase-locked loop) interface for tracking to a complex sinusoid. The loop bandwidth, phase offset, and other parameter can be specified via the command-line interface. SEE ALSO: `nco_example.c` `nco_pll_modem_example.c` * `nco_pll_modem_example.c`: This example demonstrates how the nco/pll object (numerically-controlled oscillator with phase-locked loop) can be used for carrier frequency recovery in digital modems. The modem type, SNR, and other parameters are specified via the command-line interface. SEE ALSO: `nco_example.c` `nco_pll_example.c` * `nyquist_filter_example.c`: * `ofdmflexframesync_example.c`: * `ofdmframegen_example.c`: * `ofdmframesync_example.c`: * `packetizer_example.c`: Demonstrates the functionality of the packetizer object. Data are encoded using two forward error-correction schemes (an inner and outer code) before data errors are introduced. The decoder then tries to recover the original data message. SEE ALSO: `fec_example.c` `crc_example.c` * `packetizer_soft_example.c`: This example demonstrates the functionality of the packetizer object for soft-decision decoding. Data are encoded using two forward error- correction schemes (an inner and outer code) before noise and data errors are added. The decoder then tries to recover the original data message. Only the outer code uses soft-decision decoding. SEE ALSO: `fec_soft_example.c` `packetizer_example.c` * `pll_example.c`: Demonstrates a basic phase-locked loop to track the phase of a complex sinusoid. * `poly_findroots_example.c`: * `polyfit_example.c`: Test polynomial fit to sample data. SEE ALSO: `polyfit_lagrange_example.c` * `polyfit_lagrange_example.c`: Test exact polynomial fit to sample data using Lagrange interpolating polynomials. SEE ALSO: `polyfit_example.c` * `qdetector_cccf_example.c`: This example demonstrates the functionality of the qdetector object to detect an arbitrary signal in time in the presence of noise, carrier frequency/phase offsets, and fractional-sample timing offsets. * `qpacketmodem_example.c`: This example demonstrates the basic packet modem encoder/decoder operation. A packet of data is encoded and modulated into symbols, channel noise is added, and the resulting packet is demodulated and decoded. * `qnsearch_example.c`: * `quantize_example.c`: * `random_histogram_example.c`: This example tests the random number generators for different distributions. * `repack_bytes_example.c`: This example demonstrates the repack_bytes() interface by packing a sequence of three 3-bit symbols into five 2-bit symbols. The results are printed to the screen. Because the total number of bits in the input is 9 and not evenly divisible by 2, the last of the 5 output symbols has a zero explicitly padded to the end. * `resamp2_cccf_example.c` This example demonstrates the halfband resampler cenetered at the quarter sample rate to split the signal into positive and negative frequency bands. Two distinct narrow-band signals are generated; one at a positive frequency and one at a negative frequency. The resamp2 object is run as a filter to separate the two about the zero- frequency center point. * `resamp2_crcf_example.c`: This example demonstrates the halfband resampler running as both an interpolator and a decimator. A narrow-band signal is first interpolated by a factor of 2, and then decimated. The resulting RMS error between the final signal and original is computed and printed to the screen. * `resamp2_crcf_decim_example.c`: Halfband decimator. This example demonstrates the interface to the decimating halfband resampler. A low-frequency input sinusoid is generated and fed into the decimator two samples at a time, producing one output at each iteration. The results are written to an output file. SEE ALSO: `resamp2_crcf_interp_example.c` `decim_rrrf_example.c` * `resamp2_crcf_filter_example.c`: Halfband (two-channel) filterbank example. This example demonstrates the analyzer/synthesizer execute() methods for the resamp2_xxxt family of objects. NOTE: The filterbank is not a perfect reconstruction filter; a significant amount of distortion occurs in the transition band of the half-band filters. * `resamp2_crcf_interp_example.c`: Halfband interpolator. This example demonstrates the interface to the interpolating halfband resampler. A low-frequency input sinusoid is generated and fed into the interpolator one sample at a time, producing two outputs at each iteration. The results are written to an output file. SEE ALSO: `resamp2_crcf_decim_example.c` `interp_crcf_example.c` * `resamp_crcf_example.c`: * `scramble_example.c`: Data-scrambling example. Physical layer synchronization of received waveforms relies on independent and identically distributed underlying data symbols. If the message sequence, however, is '00000....' and the modulation scheme is BPSK, the synchronizer probably won't be able to recover the symbol timing. It is imperative to increase the entropy of the data for this to happen. The data scrambler routine attempts to 'whiten' the data sequence with a bit mask in order to achieve maximum entropy. This example demonstrates the interface. * `smatrix_example.c`: * `spgramcf_example.c`: Spectral periodogram example with complex inputs. * `spgramf_example.c`: Spectral periodogram example with real inputs. * `symsync_crcf_example.c`: This example demonstrates the basic principles of the symbol timing recovery family of objects, specifically symsync_crcf. A set of random QPSK symbols are generated and interpolated with a timing offset. The resulting signal is run through the symsync_crcf object which applies a matched filter and recovers timing producing a clean constellation. * `symsync_crcf_full_example.c`: This example extends that of `symsync_crcf_example.c` by including options for simulating a timing rate offset in addition to just a timing phase error. The resulting output file shows not just the constellation but the time domain sequence as well as the timing phase estimate over time. * `symsync_crcf_kaiser_example.c`: This is a simplified example of the symync family of objects to show how symbol timing can be recovered after the matched filter output. * `symtrack_cccf_example.c`: This example demonstrates how to recover data symbols using the symtrack object. A stream of modulated and interpolated symbols are generated using the symstream object. The resulting samples are passed through a channel to add various impairments. The symtrack object recovers timing, carrier, and other information imparted by the channel and returns data symbols ready for demodulation. * `wdelayf_example.c`: * `windowf_example.c`: This example demonstrates the functionality of a window buffer (also known as a circular or ring buffer) of floating-point values. Values are written to and read from the buffer using several different methods. SEE ALSO: `bufferf_example.c` `wdelayf_example.c` liquid-dsp-1.7.0/examples/agc_crcf_example.c000066400000000000000000000073471474751757600210600ustar00rootroot00000000000000// // agc_crcf_example.c // // Automatic gain control example demonstrating its transient // response. // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "agc_crcf_example.m" // print usage/help message void usage() { printf("agc_example [options]\n"); printf(" h : print usage\n"); printf(" n : number of samples, n >=100, default: 2000\n"); printf(" b : AGC bandwidth, b >= 0, default: 0.01\n"); } int main(int argc, char*argv[]) { // options float bt = 0.01f; // agc loop bandwidth float gamma = 0.001f; // initial signal level unsigned int num_samples = 2000; // number of samples int dopt; while((dopt = getopt(argc,argv,"hn:N:s:b:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'b': bt = atof(optarg); break; default: exit(1); } } // validate input if (bt < 0.0f) { fprintf(stderr,"error: %s, bandwidth must be positive\n", argv[0]); exit(1); } else if (num_samples == 0) { fprintf(stderr,"error: %s, number of samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // create objects agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); //agc_crcf_set_scale(q, 0.5f); float complex x[num_samples]; // input float complex y[num_samples]; // output float rssi[num_samples]; // received signal strength // print info agc_crcf_print(q); // generate signal for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "agc_crcf_qpsk_example.m" int main(int argc, char*argv[]) { // options float noise_floor= -40.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float bt = 0.05f; // loop bandwidth unsigned int num_symbols= 100; // number of iterations unsigned int d = 5; // print every d iterations unsigned int k = 2; // interpolation factor (samples/symbol) unsigned int m = 3; // filter delay (symbols) float beta = 0.3f; // filter excess bandwidth factor float dt = 0.0f; // filter fractional sample delay // derived values unsigned int num_samples=num_symbols*k; float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain float nstd = powf(10.0f, noise_floor / 20.0f); // arrays float complex x[num_samples]; float complex y[num_samples]; float rssi[num_samples]; // create objects modemcf mod = modemcf_create(LIQUID_MODEM_QPSK); firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_RRC,k,m,beta,dt); agc_crcf p = agc_crcf_create(); agc_crcf_set_bandwidth(p, bt); unsigned int i; // print info printf("automatic gain control // loop bandwidth: %4.2e\n",bt); unsigned int sym; float complex s; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "agc_crcf_squelch_example.m" // print usage/help message void usage() { printf("agc_crcf_squelch_example [options]\n"); printf(" -h : print usage\n"); printf(" -b : AGC bandwidth, b >= 0, default: 0.25\n"); } int main(int argc, char*argv[]) { // options float bt = 0.25f; // agc loop bandwidth int dopt; while((dopt = getopt(argc,argv,"hn:N:s:b:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'b': bt = atof(optarg); break; default: exit(1); } } // validate input if (bt < 0.0f) { fprintf(stderr,"error: %s, bandwidth must be positive\n", argv[0]); exit(1); } unsigned int i; // create agc object, set loop bandwidth, and initialize parameters agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); agc_crcf_set_signal_level(q,1e-3f); // initial guess at starting signal level // initialize squelch functionality agc_crcf_squelch_enable(q); // enable squelch agc_crcf_squelch_set_threshold(q, -50); // threshold for detection [dB] agc_crcf_squelch_set_timeout (q, 100); // timeout for hysteresis // initialize arrays unsigned int num_samples = 2000; // total number of samples to run float complex x [num_samples]; // input float complex y [num_samples]; // output float rssi[num_samples]; // received signal strength int mode[num_samples]; // squelch mode // print info printf("automatic gain control // loop bandwidth: %4.2e\n",bt); // generate signal, applying tapering window appropriately for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "agc_rrrf_example.m" // print usage/help message void usage() { printf("agc_example [options]\n"); printf(" h : print usage\n"); printf(" n : number of samples, n >=100, default: 2000\n"); printf(" b : AGC bandwidth, b >= 0, default: 0.01\n"); } int main(int argc, char*argv[]) { // options float bt = 0.01f; // agc loop bandwidth float gamma = 0.001f; // initial signal level unsigned int num_samples = 2000; // number of samples int dopt; while((dopt = getopt(argc,argv,"hn:N:s:b:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'b': bt = atof(optarg); break; default: exit(1); } } // validate input if (bt < 0.0f) { fprintf(stderr,"error: %s, bandwidth must be positive\n", argv[0]); exit(1); } else if (num_samples == 0) { fprintf(stderr,"error: %s, number of samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // create objects agc_rrrf q = agc_rrrf_create(); agc_rrrf_set_bandwidth(q, bt); float x[num_samples]; // input float y[num_samples]; // output float rssi[num_samples]; // received signal strength // print info printf("automatic gain control // loop bandwidth: %4.2e\n",bt); // generate signal for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ampmodem_example.m" // print usage/help message void usage() { printf("ampmodem_example [options]\n"); printf(" -h : print usage\n"); printf(" -m : modulation index, default: 0.8\n"); printf(" -f : freq. offset [rad/sample], default: 0.05\n"); printf(" -p : phase offset, default: 2.8\n"); printf(" -n : number of samples, default: 2400\n"); printf(" -S : SNR [dB], default: 30\n"); printf(" -t : AM type (dsb/usb/lsb), default: usb\n"); printf(" -s : suppress the carrier, default: off (carrier enabled)\n"); } int main(int argc, char*argv[]) { // options float mod_index = 0.8f; // modulation index (bandwidth) float dphi = 0.05f; // carrier frequency offset [radians/sample] float phi = 2.8f; // carrier phase offset [radians] float SNRdB = 30.0f; // signal-to-noise ratio (set very high for testing) unsigned int num_samples = 2400; // number of samples liquid_ampmodem_type type = LIQUID_AMPMODEM_USB; int suppressed_carrier = 0; int dopt; while ((dopt = getopt(argc,argv,"hm:f:p:n:S:t:s")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': mod_index = atof(optarg); break; case 'f': dphi = atof(optarg); break; case 'p': phi = atof(optarg); break; case 'n': num_samples = atoi(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': if (strcmp(optarg,"dsb")==0) { type = LIQUID_AMPMODEM_DSB; } else if (strcmp(optarg,"usb")==0) { type = LIQUID_AMPMODEM_USB; } else if (strcmp(optarg,"lsb")==0) { type = LIQUID_AMPMODEM_LSB; } else { fprintf(stderr,"error: %s, invalid AM type: %s\n", argv[0], optarg); return 1; } break; case 's': suppressed_carrier = 1; break; default: return 1; } } // create mod/demod objects ampmodem mod = ampmodem_create(mod_index, type, suppressed_carrier); ampmodem demod = ampmodem_create(mod_index, type, suppressed_carrier); unsigned int delay = ampmodem_get_delay_mod(mod) + ampmodem_get_delay_demod(demod); ampmodem_print(mod); unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; // generate 'audio' signal (simple windowed sum of tones) unsigned int nw = (unsigned int)(0.90*num_samples); // window length unsigned int nt = (unsigned int)(0.05*num_samples); // taper length for (i=0; i M_PI) phi -= 2*M_PI; while (phi < -M_PI) phi += 2*M_PI; } // demodulate signal for (i=0; i // usleep #include #include #include #include "liquid.h" int main() { // options unsigned int nfft = 64; // transform size unsigned int num_frames = 200; // total number of frames unsigned int msdelay = 25; // delay between transforms [ms] float noise_floor = -40.0f; // noise floor // initialize objects asgramcf q = asgramcf_create(nfft); asgramcf_set_scale(q, noise_floor+15.0f, 5.0f); unsigned int i; unsigned int n; float theta = 0.0f; // current instantaneous phase float dtheta = 0.0f; // current instantaneous frequency float phi = 0.0f; // phase of sinusoidal frequency drift float dphi = 0.003f; // frequency of sinusoidal frequency drift float complex x[nfft]; float nstd = powf(10.0f,noise_floor/20.0f); // noise standard deviation for (n=0; n // usleep #include #include #include "liquid.h" int main() { // options unsigned int nfft = 64; // transform size unsigned int num_frames = 200; // total number of frames unsigned int msdelay = 25; // delay between transforms [ms] float noise_floor = -40.0f; // noise floor // initialize objects asgramf q = asgramf_create(nfft); asgramf_set_scale(q, noise_floor+15.0f, 5.0f); unsigned int i; unsigned int n; float theta = 0.0f; // current instantaneous phase float dtheta = 0.0f; // current instantaneous frequency float phi = 0.0f; // phase of sinusoidal frequency drift float dphi = 0.003f; // frequency of sinusoidal frequency drift float nstd = powf(10.0f,noise_floor/20.0f); // noise standard deviation for (n=0; n #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "autocorr_cccf_example.m" // print usage/help message void usage() { printf("autocorr_cccf_example:\n"); printf(" u/h : print usage/help\n"); printf(" m : sequence length, default: 32\n"); printf(" n : number of sequences (repetitions), default: 8\n"); printf(" w : autocorr window length, default: 64\n"); printf(" d : autocorr delay length (multiple of 's'), default: 32\n"); printf(" e : normalize by energy? default: off\n"); printf(" s : SNR, signal-to-noise ratio [dB], default: 20\n"); } int main(int argc, char*argv[]) { // options unsigned int sequence_len = 32; // short sequence length unsigned int n = 8; // number short sequences (repetition length) unsigned int window_size = 64; // autocorr window size unsigned int delay = sequence_len; // autocorr delay (multiple of 's') int normalize_by_energy = 0; // normalize output by E{x^2}? float SNRdB=20.0f; // signal-to-noise ratio (dB) int dopt; while ((dopt = getopt(argc,argv,"uhm:n:w:d:es:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'm': sequence_len = atof(optarg); break; case 'n': n = atof(optarg); break; case 'w': window_size = atof(optarg); break; case 'd': delay = atof(optarg); break; case 'e': normalize_by_energy = 1; break; case 's': SNRdB = atoi(optarg); break; usage(); return 1; } } // derived values unsigned int num_samples = sequence_len*(n+2); // pad end w/ zeros // data arrays float complex sequence[sequence_len]; // short sequence float complex x[num_samples]; // autocorr input sequence float complex rxx[num_samples]; // autocorr output // generate objects autocorr_cccf q = autocorr_cccf_create(window_size,delay); unsigned int i; // generate random training sequence using QPSK symbols modemcf mod = modemcf_create(LIQUID_MODEM_QPSK); for (i=0; i cabsf(rxx_peak)) rxx_peak = rxx[i]; } printf("peak auto-correlation : %12.8f, angle %12.8f\n", cabsf(rxx_peak), cargf(rxx_peak)); // destroy allocated objects autocorr_cccf_destroy(q); // // write results to file // FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"num_samples = %u;\n", num_samples); // write signal to output file for (i=0; i #include #include #include #include #include "liquid.h" int callback(unsigned char * _payload, int _payload_valid, unsigned int _payload_len, framesyncstats_s _stats, void * _userdata) { printf("callback invoked, payload (%u bytes) : %s\n", _payload_len, _payload_valid ? "valid" : "INVALID!"); // copy data if valid if (_payload_valid) { unsigned char * msg_dec = (unsigned char*) _userdata; memmove(msg_dec, _payload, _payload_len*sizeof(unsigned char)); } return 0; } // print usage/help message void usage() { printf("bpacketsync_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : input data size (number of uncoded bytes): 8 default\n"); printf(" e : bit error rate of channel, default: 0\n"); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): h74 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int n=8; // original data message length crc_scheme check = LIQUID_CRC_32; // data integrity check fec_scheme fec0 = LIQUID_FEC_HAMMING74; // inner code fec_scheme fec1 = LIQUID_FEC_NONE; // outer code float bit_error_rate = 0.0f; // bit error rate // read command-line options int dopt; while((dopt = getopt(argc,argv,"uhn:e:v:c:k:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': n = atoi(optarg); break; case 'e': bit_error_rate = atof(optarg); break; case 'v': // data integrity check check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'c': // inner FEC scheme fec0 = liquid_getopt_str2fec(optarg); if (fec0 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported inner FEC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'k': // outer FEC scheme fec1 = liquid_getopt_str2fec(optarg); if (fec1 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported outer FEC scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } // validate input if (n == 0) { fprintf(stderr,"error: %s, packet length must be greater than zero\n", argv[0]); exit(1); } else if (bit_error_rate < 0.0f || bit_error_rate > 1.0f) { fprintf(stderr,"error: %s, channel bit error rate must be in [0,1]\n", argv[0]); exit(1); } // create packet generator bpacketgen pg = bpacketgen_create(0, n, check, fec0, fec1); bpacketgen_print(pg); unsigned int i; // compute packet length unsigned int k = bpacketgen_get_packet_len(pg); // initialize arrays unsigned char msg_org[n]; // original message unsigned char msg_enc[k]; // encoded message unsigned char msg_rec[k+1]; // received message unsigned char msg_dec[n]; // decoded message // create packet synchronizer bpacketsync ps = bpacketsync_create(0, callback, (void*)msg_dec); bpacketsync_print(ps); // initialize original data message for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "bpresync_example.m" // print usage/help message void usage() { printf("bpresync_example -- test binary pre-demodulation synchronization\n"); printf("options (default values in <>):\n"); printf(" h : print usage/help\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter delay [symbols], default: 5\n"); printf(" n : number of data symbols, default: 64\n"); printf(" b : bandwidth-time product beta in (0,1), default: 0.3\n"); printf(" F : carrier frequency offset, default: 0.02\n"); printf(" t : fractional sample offset dt in [-0.5, 0.5], default: 0\n"); printf(" S : SNR [dB], default: 20\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int m=5; // filter delay (symbols) float beta=0.3f; // bandwidth-time product float dt = 0.0f; // fractional sample timing offset unsigned int num_sync_symbols = 64; // number of synchronization symbols float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi = 0.02f; // carrier frequency offset float phi = 2*M_PI*randf(); // carrier phase offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:t:F:t:S:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 't': dt = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } else if (dt < -0.5f || dt > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_sync_symbols + 2*m + 10; unsigned int num_samples = k*num_symbols; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays float complex seq[num_sync_symbols]; // synchronization pattern (symbols) float complex s0[k*num_sync_symbols]; // synchronization pattern (samples) float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float complex rxy[num_samples]; // pre-demod correlation output float dphi_hat[num_samples]; // carrier offset estimate // create transmit/receive interpolator/decimator firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_RRC,k,m,beta,dt); // generate synchronization pattern (BPSK) and interpolate for (i=0; i 0.6f) { printf("****** preamble found, rxy = %12.8f (dphi-hat: %12.8f), i=%3u ******\n", cabsf(rxy[i]), dphi_hat[i], i); } // retain maximum if (cabsf(rxy[i]) > rxy_max) { rxy_max = cabsf(rxy[i]); dphi_est = dphi_hat[i]; delay_est = (int)i - (int)2*k*m + 1; } } // destroy objects firinterp_crcf_destroy(interp); bpresync_cccf_destroy(sync); // print results printf("\n"); printf("rxy (max) : %12.8f\n", rxy_max); printf("dphi est. : %12.8f ,error=%12.8f\n", dphi_est, dphi-dphi_est); printf("delay est.: %12d ,error=%3d sample(s)\n", delay_est, k*num_sync_symbols - delay_est); printf("\n"); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"k = %u;\n", k); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"rxy = zeros(1,num_samples);\n"); for (i=0; i #include #include #include "liquid.h" //#define OUTPUT_FILENAME "bsequence_example.m" int main() { // create and initialize binary sequence unsigned int n=16; bsequence q = bsequence_create(n); unsigned char v[4] = {0x35, 0x35}; bsequence_init(q,v); bsequence_push(q,1); bsequence_push(q,1); bsequence_push(q,1); bsequence_push(q,1); bsequence_push(q,0); bsequence_push(q,1); bsequence_print(q); bsequence_circshift(q); bsequence_print(q); bsequence_circshift(q); bsequence_print(q); unsigned int b; unsigned int i; for (i=0; i #include "liquid.h" int main() { float v[] = {1, 2, 3, 4, 5, 6, 7, 8}; float *r; // reader unsigned int num_requested = 3; unsigned int num_read; cbufferf cb = cbufferf_create(10); cbufferf_write(cb, v, 4); cbufferf_read(cb, num_requested, &r, &num_read); printf("cbufferf: requested %u elements, read %u elements\n", num_requested, num_read); unsigned int i; for (i=0; i #include #include #include #include "liquid.h" int main() { // options unsigned int n = 8; unsigned int i; // allocate memory for arrays float A[n*n]; float b[n]; float x[n]; float x_hat[n]; // generate symmetric positive-definite matrix by first generating // lower triangular matrix L and computing A = L*L' float L[n*n]; unsigned int j; for (i=0; i i) matrix_access(L,n,n,i,j) = 0.0; else if (j == i) matrix_access(L,n,n,i,j) = randnf(); else if ((rand()%4)==0) matrix_access(L,n,n,i,j) = randnf(); else matrix_access(L,n,n,i,j) = 0.0; #else // full matrix matrix_access(L,n,n,i,j) = (j < i) ? 0.0 : randnf(); #endif } } matrixf_mul_transpose(L, n, n, A); // generate random solution for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "channel_cccf_example.m" // print usage/help message void usage() { printf("channel_cccf_example [options]\n"); printf(" h : print this help file\n"); printf(" k : filter samples/symbol, default: 2\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" H : multi-path channel length, default: 4000\n"); printf(" n : number of symbols, default: 4000\n"); printf(" s : signal-to-noise ratio, default: 30 dB\n"); printf(" w : timing pll bandwidth, default: 0.02\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay (symbols) float beta = 0.25f; // filter excess bandwidth factor unsigned int num_symbols = 4000; // number of data symbols unsigned int hc_len = 5; // channel filter length float noise_floor = -60.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.02f; // loop filter bandwidth float dphi = 0.00f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:H:n:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'H': hc_len = atoi(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bandwidth = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (bandwidth <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } unsigned int i; // derived/fixed values unsigned int num_samples = num_symbols*k; float complex x[num_samples]; // input (interpolated) samples float complex y[num_samples]; // channel output samples float complex sym_out[num_symbols + 64];// synchronized symbols // // generate input sequence using symbol stream generator // symstreamcf gen = symstreamcf_create_linear(LIQUID_FIRFILT_ARKAISER,k,m,beta,ms); symstreamcf_write_samples(gen, x, num_samples); symstreamcf_destroy(gen); // create channel channel_cccf channel = channel_cccf_create(); // add channel impairments channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); channel_cccf_add_multipath (channel, NULL, hc_len); channel_cccf_add_shadowing (channel, 1.0f, 0.1f); // print channel internals channel_cccf_print(channel); // apply channel to input signal channel_cccf_execute_block(channel, x, num_samples, y); // destroy channel channel_cccf_destroy(channel); // // create and run symbol synchronizer // symtrack_cccf symtrack = symtrack_cccf_create(LIQUID_FIRFILT_RRC,k,m,beta,ms); // set tracking bandwidth symtrack_cccf_set_bandwidth(symtrack,0.05f); unsigned int num_symbols_sync = 0; symtrack_cccf_execute_block(symtrack, y, num_samples, sym_out, &num_symbols_sync); symtrack_cccf_destroy(symtrack); // print results printf("symbols in : %u\n", num_symbols); printf("symbols out : %u\n", num_symbols_sync); // estimate spectrum unsigned int nfft = 1200; float psd[nfft]; spgramcf_estimate_psd(nfft, y, num_samples, psd); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"close all;\nclear all;\n\n"); fprintf(fid,"num_symbols=%u;\n",num_symbols_sync); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "compand_cf_example.m" int main() { // options float mu=255.0f; int n=31; // open debug file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); float complex x, y, z; int i, j; for (i=0; i ", crealf(x), cimagf(x)); printf("%8.4f + j*%8.4f > ", crealf(y), cimagf(y)); printf("%8.4f + j*%8.4f\n", crealf(z), cimagf(z)); } fprintf(fid,"x(%3d,%3d) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(x), cimagf(x)); fprintf(fid,"y(%3d,%3d) = %12.4e + j*%12.4e;\n", i+1, j+1, crealf(y), cimagf(y)); } } for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "compand_example.m" // print usage/help message void usage() { printf("compand_example\n"); printf(" u/h : print usage/help\n"); printf(" v/q : verbose/quiet, default: verbose\n"); printf(" n : number of samples, default: 31\n"); printf(" m : companding parameter: mu > 0, default: 255\n"); printf(" r : range > 0, default: 1.25\n"); } int main(int argc, char*argv[]) { // options unsigned int n=31; float mu=255.0f; float range = 1.25f; int verbose = 1; int dopt; while ((dopt = getopt(argc,argv,"uhvqn:m:r:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'v': verbose = 1; break; case 'q': verbose = 0; break; case 'n': n = atoi(optarg); break; case 'm': mu = atof(optarg); break; case 'r': range = atof(optarg); break; default: exit(1); } } // validate input if (mu < 0) { fprintf(stderr,"error: %s, mu must be positive\n", argv[0]); usage(); exit(1); } else if (range <= 0) { fprintf(stderr,"error: %s, range must be greater than zero\n", argv[0]); usage(); exit(1); } // open debug file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); float x = -range; float y, z; float dx = 2.0*range/(float)(n-1); unsigned int i; for (i=0; i %8.4f > %8.4f\n", x, y, z); fprintf(fid,"x(%3u) = %12.4e;\n", i+1, x); fprintf(fid,"y(%3u) = %12.4e;\n", i+1, y); fprintf(fid,"z(%3u) = %12.4e;\n", i+1, z); x += dx; } // plot results fprintf(fid,"\n\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(x,y,'-b','LineWidth',2,x,z,'-r');\n"); fprintf(fid,"axis square\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('x');\n"); fprintf(fid,"ylabel('f(x)');\n"); // close debug file fclose(fid); printf("results wrtten to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/complementary_codes_example.c000066400000000000000000000076051474751757600233620ustar00rootroot00000000000000// // complementary_codes_example.c // // This example demonstrates how to generate complementary binary // codes in liquid. A pair of codes is generated using the bsequence // interface, their auto-correlations are computed, and the result is // summed and printed to the screen. The results are also printed to an // output file, which plots the sequences and their auto-correlations. // // SEE ALSO: bsequence_example.c // msequence_example.c #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "complementary_codes_example.m" // print usage/help message void usage() { printf("complementary_codes_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : sequence length, 8,16,32,64,... (default: 32)\n"); } int main(int argc, char*argv[]) { // options unsigned int n = 32; int dopt; while ((dopt = getopt(argc,argv,"uhn:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; default: exit(1); } } // validate input if ( (1< #include #include #include "liquid.h" #define OUTPUT_FILENAME "conversion_example.m" int main() { // spectral periodogram options unsigned int nfft = 1200; // spectral periodogram FFT size unsigned int num_samples = 64000; // number of samples float fc = 0.20f; // carrier (relative to sampling rate) // create objects iirfilt_crcf filter_tx = iirfilt_crcf_create_lowpass(15, 0.05); nco_crcf mixer_tx = nco_crcf_create(LIQUID_VCO); nco_crcf mixer_rx = nco_crcf_create(LIQUID_VCO); iirfilt_crcf filter_rx = iirfilt_crcf_create_lowpass(7, 0.2); // set carrier frequencies nco_crcf_set_frequency(mixer_tx, fc * 2*M_PI); nco_crcf_set_frequency(mixer_rx, fc * 2*M_PI); // create objects for measuring power spectral density spgramcf spgram_tx = spgramcf_create_default(nfft); spgramf spgram_dac = spgramf_create_default(nfft); spgramcf spgram_rx = spgramcf_create_default(nfft); // run through loop one step at a time unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "cpfskmodem_example.m" // print usage/help message void usage() { printf("cpfskmodem_example -- continuous-phase frequency-shift keying example\n"); printf("options:\n"); printf(" -h : print help\n"); printf(" -t : filter type: [square], rcos-full, rcos-half, gmsk\n"); printf(" -p : bits/symbol, default: 1\n"); printf(" -H : modulation index, default: 0.5\n"); printf(" -k : samples/symbol, default: 8\n"); printf(" -m : filter delay (symbols), default: 3\n"); printf(" -b : filter roll-off, default: 0.35\n"); printf(" -n : number of data symbols, default: 80\n"); printf(" -s : SNR [dB], default: 40\n"); } int main(int argc, char*argv[]) { // options unsigned int bps = 1; // number of bits/symbol float h = 0.5f; // modulation index (h=1/2 for MSK) unsigned int k = 4; // filter samples/symbol unsigned int m = 3; // filter delay (symbols) float beta = 0.35f; // GMSK bandwidth-time factor unsigned int num_symbols = 20; // number of data symbols float SNRdB = 40.0f; // signal-to-noise ratio [dB] int filter_type = LIQUID_CPFSK_SQUARE; int dopt; while ((dopt = getopt(argc,argv,"ht:p:H:k:m:b:n:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': if (strcmp(optarg,"square")==0) { filter_type = LIQUID_CPFSK_SQUARE; } else if (strcmp(optarg,"rcos-full")==0) { filter_type = LIQUID_CPFSK_RCOS_FULL; } else if (strcmp(optarg,"rcos-half")==0) { filter_type = LIQUID_CPFSK_RCOS_PARTIAL; } else if (strcmp(optarg,"gmsk")==0) { filter_type = LIQUID_CPFSK_GMSK; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'p': bps = atoi(optarg); break; case 'H': h = atof(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_samples = k*num_symbols; unsigned int M = 1 << bps; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned int sym_in [num_symbols]; // input symbols float complex x [num_samples]; // transmitted signal float complex y [num_samples]; // received signal unsigned int sym_out[num_symbols]; // output symbols // create modem objects cpfskmod mod = cpfskmod_create(bps, h, k, m, beta, filter_type); cpfskdem dem = cpfskdem_create(bps, h, k, m, beta, filter_type); // print modulator cpfskmod_print(mod); cpfskdem_print(dem); // get full symbol delay unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem); printf("delay: %u samples\n", delay); // generate message signal for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "cpfsk_psd_example.m" // print usage/help message void usage() { printf("cpfsk_psd_example -- continuous-phase frequency-shift keying example\n"); printf("options:\n"); printf(" h : print help\n"); printf(" p : bits/symbol, default: 1\n"); printf(" H : modulation index, default: 0.5\n"); printf(" k : samples/symbol, default: 8\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter roll-off, default: 0.35\n"); printf(" n : number of data symbols, default: 80\n"); } int main(int argc, char*argv[]) { // options unsigned int bps = 1; // number of bits/symbol float h = 0.5f; // modulation index (h=1/2 for MSK) unsigned int k = 8; // filter samples/symbol unsigned int m = 7; // filter delay (symbols) float beta = 0.35f; // GMSK bandwidth-time factor unsigned int num_symbols = 48000; // number of data symbols unsigned int nfft = 2400; // spectral periodogram FFT size int dopt; while ((dopt = getopt(argc,argv,"hp:H:k:m:b:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'p': bps = atoi(optarg); break; case 'H': h = atof(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int M = 1 << bps; // constellation size // create modulators cpfskmod mod_0 = cpfskmod_create(bps, h, k, m, beta, LIQUID_CPFSK_SQUARE); cpfskmod mod_1 = cpfskmod_create(bps, h, k, m, beta, LIQUID_CPFSK_RCOS_FULL); cpfskmod mod_2 = cpfskmod_create(bps, h, k, m, beta, LIQUID_CPFSK_RCOS_PARTIAL); cpfskmod mod_3 = cpfskmod_create(bps, h, k, m, beta, LIQUID_CPFSK_GMSK); // buffers float complex buf_0[k]; float complex buf_1[k]; float complex buf_2[k]; float complex buf_3[k]; // create PSD estimators // spectral periodogram options // create spectral periodogram spgramcf spgram_0 = spgramcf_create_default(nfft); spgramcf spgram_1 = spgramcf_create_default(nfft); spgramcf spgram_2 = spgramcf_create_default(nfft); spgramcf spgram_3 = spgramcf_create_default(nfft); // estimate PSD for each symbol for (i=0; i #include #include #include "liquid.h" // print usage/help message void usage() { printf("crc_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : input data size (number of uncoded bytes)\n"); printf(" v : checking scheme, (crc32 default):\n"); liquid_print_crc_schemes(); } int main(int argc, char*argv[]) { // options unsigned int n = 32; // data length (bytes) crc_scheme check = LIQUID_CRC_32; // error-detection scheme int dopt; while((dopt = getopt(argc,argv,"uhn:v:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': n = atoi(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported error-detection scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } // validate input unsigned int i; // initialize data array, leaving space for key at the end unsigned char data[n+4]; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "cvsd_example.m" // print usage/help message void usage() { printf("cvsd_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : number of samples, default: 512\n"); printf(" f : input signal frequency, default: 0.02\n"); printf(" b : cvsd param: num-bits, default: 3\n"); printf(" z : cvsd param: zeta, default: 1.5\n"); printf(" a : cvsd param: alpha, default: 0.95\n"); } int main(int argc, char*argv[]) { // options unsigned int n=512; // number of samples float fc = 0.02; // input signal frequency unsigned int nbits=3; // number of adjacent bits to observe float zeta=1.5f; // slope adjustment multiplier float alpha = 0.95; // pre-/post-filter coefficient int dopt; while ((dopt = getopt(argc,argv,"uhn:f:b:z:a:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; case 'b': nbits = atoi(optarg); break; case 'z': zeta = atof(optarg); break; case 'a': alpha = atof(optarg); break; default: exit(1); } } // validate input unsigned int i; // data arrays float x[n]; // input time series unsigned char b[n]; // encoded bit pattern float y[n]; // reconstructed time series // create cvsd codecs cvsd cvsd_encoder = cvsd_create(nbits, zeta, alpha); cvsd cvsd_decoder = cvsd_create(nbits, zeta, alpha); cvsd_print(cvsd_encoder); // generate input time series for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "dds_cccf_example.m" int main() { // options float fc = -0.2f; // input (output) decim (interp) frequency unsigned int num_stages = 3; // number of halfband interp/decim stages unsigned int num_samples = 64; // number of input samples float As = 60.0f; // DDS stop-band attenuation [dB] float bw = 0.25f; // signal bandwidth // derived values unsigned int r=1< #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "detector_example.m" // print usage/help message void usage() { printf("detector_example -- test binary pre-demodulation synchronization\n"); printf("options:\n"); printf(" h : print usage/help\n"); printf(" n : number of sync samples, default: 128\n"); printf(" F : carrier frequency offset, default: 0.02\n"); printf(" T : fractional sample offset dt in [-0.5, 0.5], default: 0\n"); printf(" S : SNR [dB], default: 20\n"); printf(" t : detection threshold, default: 0.3\n"); } int main(int argc, char*argv[]) { //srand(time(NULL)); // options unsigned int n = 128; // number of sync samples float dt = 0.0f; // fractional sample timing offset float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi = 0.0f; // carrier frequency offset float phi = 0.0f; // carrier phase offset float threshold = 0.3f; // detection threshold int dopt; while ((dopt = getopt(argc,argv,"hn:T:F:S:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; case 'F': dphi = atof(optarg); break; case 'T': dt = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': threshold = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (dt < -0.5f || dt > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // derived values unsigned int num_samples = 3*n; float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); // arrays float complex s[n]; // synchronization pattern (samples) float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal // generate synchronization pattern (OFDM symbol, slightly over-sampled) float complex S[n]; for (i=0; i 0.6*n) ? randnf() + _Complex_I*randnf() : 0.0f; fft_run(n, S, s, LIQUID_FFT_BACKWARD, 0); float s2 = 0.0f; for (i=0; i #include "liquid.h" int main() { // input array float complex x[] = { 1 + 1 * _Complex_I, 2 + 1 * _Complex_I, 3 + 1 * _Complex_I, 4 + 1 * _Complex_I, 5 + 1 * _Complex_I}; // coefficients array float complex h[] = { 1 + 1 * _Complex_I, -1 + 1 * _Complex_I, 1 + 1 * _Complex_I, -1 + 1 * _Complex_I, 1 + 1 * _Complex_I}; // dot product result float complex y; // run regular dot product dotprod_cccf_run(x,h,5,&y); printf("dotprod_cccf : %8.2f + j%8.2f\n", crealf(y), cimagf(y)); // run structured dot product dotprod_cccf q = dotprod_cccf_create(x,5); dotprod_cccf_execute(q,h,&y); printf("dotprod_cccf (structured) : %8.2f + j%8.2f\n", crealf(y), cimagf(y)); dotprod_cccf_destroy(q); return 0; } liquid-dsp-1.7.0/examples/dotprod_rrrf_example.c000066400000000000000000000013151474751757600220240ustar00rootroot00000000000000// // dotprod_rrrf_example.c // // This example demonstrates the interface to the floating-point dot // product object (dotprod_rrrf). // #include #include "liquid.h" int main() { // input array float x[] = { 1, 2, 3, 4, 5}; // coefficients array float h[] = { 1, -1, 1, -1, 1}; // dot product result float y; // run regular dot product dotprod_rrrf_run(x,h,5,&y); printf("dotprod_rrrf : %8.2f\n", y); // run structured dot product dotprod_rrrf q = dotprod_rrrf_create(x,5); dotprod_rrrf_execute(q,h,&y); printf("dotprod_rrrf (structured) : %8.2f\n", y); dotprod_rrrf_print(q); dotprod_rrrf_destroy(q); return 0; } liquid-dsp-1.7.0/examples/dsssframe64sync_example.c000066400000000000000000000064051474751757600223610ustar00rootroot00000000000000// This example demonstrates the basic interface to the dsssframe64gen and // dsssframe64sync objects. #include #include #include #include #include #include #include #include "liquid.h" // static callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _context) { printf("*** callback invoked (%s) ***\n", _payload_valid ? "pass" : "FAIL"); framesyncstats_print(&_stats); // save recovered symbols to file unsigned int i; FILE * fid = (FILE*)_context; for (i=0; i<_stats.num_framesyms; i++) { fprintf(fid,"s(%3u) = %12.8f + %12.8fj;\n", i+1, crealf(_stats.framesyms[i]), cimagf(_stats.framesyms[i])); } return 0; } int main(int argc, char *argv[]) { // options unsigned int nfft = 2400; float SNRdB = -10.0f; const char * filename = "dsssframe64sync_example.m"; // create dsssframe64gen object dsssframe64gen fg = dsssframe64gen_create(); // generate the frame in blocks unsigned int buf_len = dsssframe64gen_get_frame_len(fg); float complex * buf_tx = (float complex *)malloc(buf_len*sizeof(float complex)); float complex * buf_rx = (float complex *)malloc(buf_len*sizeof(float complex)); // export results to file FILE * fid = fopen(filename,"w"); fprintf(fid,"%% %s : auto-generated file\n", filename); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"s=[];\n"); // generate in one step (for now) dsssframe64gen_execute(fg, NULL, NULL, buf_tx); // apply channel (AWGN) float nstd = powf(10.0f,-SNRdB/20.0f); unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "dsssframe64sync_performance_example.m" // add noise to channel void frame64_add_noise(float complex * _buf, unsigned int _buf_len, float _SNRdB) { float nstd = powf(10.0f, -_SNRdB/20.0f); nstd *= M_SQRT2; // scale noise to account for signal being over-sampled by 2 unsigned int i; for (i=0; i<_buf_len; i++) _buf[i] += nstd*( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; } int main(int argc, char*argv[]) { // create frame generator, synchronizer objects dsssframe64gen fg = dsssframe64gen_create(); dsssframe64sync fs = dsssframe64sync_create(NULL,NULL); unsigned int min_errors = 5; unsigned int min_trials = 80; unsigned int max_trials = 1000; // create buffer for the frame samples unsigned int frame_len = dsssframe64gen_get_frame_len(fg); float complex * frame = (float complex *)malloc(frame_len*sizeof(float complex)); float SNRdB = -25.0f; FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"SNR=[]; pdetect=[]; pvalid=[];\n"); printf("# %8s %6s (%7s) %6s (%7s) %6s\n", "SNR", "missed", "percent", "errors", "percent", "trials"); fclose(fid); while (SNRdB < -5.0f) { dsssframe64sync_reset_framedatastats(fs); unsigned int num_trials = 0, num_errors = 0; while (1) { unsigned int i; for (i=0; i= min_errors) break; if (num_trials >= max_trials) break; } // print results framedatastats_s stats = dsssframe64sync_get_framedatastats(fs); unsigned int num_misses = num_trials - stats.num_frames_detected; float pmd = (float) num_misses / (float) num_trials; float per = (float) num_errors / (float) num_trials; printf(" %8.3f %6u (%6.2f%%) %6u (%6.2f%%) %6u\n", SNRdB,num_misses,pmd*100,num_errors,per*100,num_trials); fid = fopen(OUTPUT_FILENAME,"a"); fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%12g; pvalid(end+1)=%12g;\n", SNRdB, (float)stats.num_frames_detected / (float)num_trials, (float)stats.num_payloads_valid / (float)num_trials); fclose(fid); if (num_errors < min_errors) break; SNRdB += 1.0f; } fid = fopen(OUTPUT_FILENAME,"a"); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid," semilogy(SNR, 1-pvalid +eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"xlabel('SNR [dB]');\n"); fprintf(fid,"ylabel('Prob. of Error');\n"); fprintf(fid,"legend('detect','decoding','location','northeast');\n"); fprintf(fid,"axis([-30 10 1e-3 1]);\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); // clean up allocated objects and memory blocks dsssframe64gen_destroy(fg); dsssframe64sync_destroy(fs); free(frame); return 0; } liquid-dsp-1.7.0/examples/dsssframesync_example.c000066400000000000000000000120531474751757600222030ustar00rootroot00000000000000// // dsssframesync_example.c // #include #include #include #include #include #include #include #include "liquid.h" void usage() { printf("dsssframesync_example [options]\n"); printf(" u/h : print usage\n"); printf(" s : signal-to-noise ratio [dB], default: 20\n"); printf(" F : carrier frequency offset, default: 0.01\n"); printf(" n : payload length [bytes], default: 480\n"); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): h74 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); printf(" d : enable debugging\n"); } // dsssframesync callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata); int main(int argc, char * argv[]) { srand(time(NULL)); // options crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) unsigned int payload_len = 20; // payload length int debug_enabled = 0; // enable debugging? float noise_floor = -60.0f; // noise floor float SNRdB = -3.0f; // signal-to-noise ratio float dphi = 0.03f; // carrier frequency offset // get options int dopt; while ((dopt = getopt(argc, argv, "uhs:F:n:m:v:c:k:d")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'n': payload_len = atol(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); break; case 'c': fec0 = liquid_getopt_str2fec(optarg); break; case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 'd': debug_enabled = 1; break; default: exit(-1); } } // derived values unsigned int i; float nstd = powf(10.0f, noise_floor / 20.0f); // noise std. dev. float gamma = powf(10.0f, (SNRdB + noise_floor) / 20.0f); // channel gain // create dsssframegen object dsssframegenprops_s fgprops; fgprops.check = check; fgprops.fec0 = fec0; fgprops.fec1 = fec1; dsssframegen fg = dsssframegen_create(&fgprops); // create dsssframesync object dsssframesync fs = dsssframesync_create(callback, NULL); if (debug_enabled) { // dsssframesync_debug_enable(fs); } // assemble the frame (NULL pointers for default values) dsssframegen_assemble(fg, NULL, NULL, payload_len); // dsssframegen_print(fg); // generate the frame in blocks unsigned int buf_len = 256; float complex x[buf_len]; float complex y[buf_len]; int frame_complete = 0; float phi = 0.0f; while (!frame_complete) { frame_complete = dsssframegen_write_samples(fg, x, buf_len); // add noise and push through synchronizer for (i = 0; i < buf_len; i++) { // apply channel gain and carrier offset to input y[i] = gamma * x[i] * cexpf(_Complex_I * phi); phi += dphi; // add noise y[i] += nstd * (randnf() + _Complex_I * randnf()) * M_SQRT1_2; } // run through frame synchronizer dsssframesync_execute(fs, y, buf_len); } dsssframesync_print(fs); // export debugging file if (debug_enabled) { // dsssframesync_debug_print(fs, "dsssframesync_debug.m"); } // dsssframesync_print(fs); // destroy allocated objects dsssframegen_destroy(fg); dsssframesync_destroy(fs); printf("done.\n"); return 0; } static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata) { printf("******** callback invoked\n"); // count bit errors (assuming all-zero message) unsigned int bit_errors = 0; unsigned int i; for (i = 0; i < _payload_len; i++) bit_errors += liquid_count_ones(_payload[i]); framesyncstats_print(&_stats); printf(" header crc : %s\n", _header_valid ? "pass" : "FAIL"); printf(" payload length : %u\n", _payload_len); printf(" payload crc : %s\n", _payload_valid ? "pass" : "FAIL"); printf(" payload bit errors : %u / %u\n", bit_errors, 8 * _payload_len); return 0; } liquid-dsp-1.7.0/examples/eqlms_cccf_blind_example.c000066400000000000000000000267671474751757600226070ustar00rootroot00000000000000// This example tests the least mean-squares (LMS) equalizer (EQ) on a // signal with an unknown modulation and carrier frequency offset. That // is, the equalization is done completely blind of the modulation // scheme or its underlying data set. The error estimate assumes a // constant modulus linear modulation scheme. This works surprisingly // well even more amplitude-modulated signals, e.g. 'qam16'. #include #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqlms_cccf_blind_example.m" // print usage/help message void usage() { printf("Usage: eqlms_cccf_blind_example [OPTION]\n"); printf(" h : print help\n"); printf(" n : number of symbols, default: 500\n"); printf(" s : SNR [dB], default: 30\n"); printf(" c : number of channel filter taps (minimum: 1), default: 5\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter semi-length (symbols), default: 4\n"); printf(" b : filter excess bandwidth factor, default: 0.3\n"); printf(" p : equalizer semi-length (symbols), default: 3\n"); printf(" u : equalizer learning rate, default; 0.05\n"); printf(" M : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); } int main(int argc, char*argv[]) { //srand(time(NULL)); // options unsigned int num_symbols=800; // number of symbols to observe float SNRdB = 30.0f; // signal-to-noise ratio [dB] float fc = 0.002f; // carrier offset unsigned int hc_len=5; // channel filter length unsigned int k=2; // matched filter samples/symbol unsigned int m=3; // matched filter delay (symbols) float beta=0.3f; // matched filter excess bandwidth factor unsigned int p=3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.08f; // equalizer learning rate // modulation type/depth modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"hn:s:c:k:m:b:p:u:M:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'p': p = atoi(optarg); break; case 'u': mu = atof(optarg); break; case 'M': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // validate input if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]); exit(1); } else if (k < 2) { fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (beta < 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } // derived values unsigned int hm_len = 2*k*m+1; // matched filter length unsigned int hp_len = 2*k*p+1; // equalizer filter length unsigned int num_samples = k*num_symbols; // bookkeeping variables float complex syms_tx[num_symbols]; // transmitted data symbols float complex x[num_samples]; // interpolated time series float complex y[num_samples]; // channel output float complex z[num_samples]; // equalized output float complex syms_rx[num_symbols]; // received data symbols float hm[hm_len]; // matched filter response float complex hc[hc_len]; // channel filter coefficients float complex hp[hp_len]; // equalizer filter coefficients unsigned int i; // generate matched filter response liquid_firdes_prototype(LIQUID_FIRFILT_RRC, k, m, beta, 0.0f, hm); firinterp_crcf interp = firinterp_crcf_create(k, hm, hm_len); // create the modem objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); unsigned int M = 1 << modemcf_get_bps(mod); // generate channel impulse response, filter hc[0] = 1.0f; for (i=1; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqlms_cccf_block_example.m" // print usage/help message void usage() { printf("Usage: eqlms_cccf_block_example [OPTION]\n"); printf(" h : print help\n"); printf(" n : number of symbols, default: 500\n"); printf(" c : number of channel filter taps (minimum: 1), default: 5\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter semi-length (symbols), default: 4\n"); printf(" b : filter excess bandwidth factor, default: 0.3\n"); printf(" p : equalizer semi-length (symbols), default: 3\n"); printf(" u : equalizer learning rate, default; 0.05\n"); } int main(int argc, char*argv[]) { //srand(time(NULL)); // options unsigned int num_samples = 2400; // number of symbols to observe unsigned int hc_len = 5; // channel filter length unsigned int k = 2; // matched filter samples/symbol unsigned int m = 3; // matched filter delay (symbols) float beta = 0.3f; // matched filter excess bandwidth factor unsigned int p = 3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.15f; // equalizer learning rate modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"hn:c:k:m:b:p:u:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'c': hc_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'p': p = atoi(optarg); break; case 'u': mu = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (num_samples == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]); exit(1); } else if (k < 2) { fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (beta < 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } // derived/fixed values unsigned int buf_len = 37; float complex buf_input [buf_len]; float complex buf_channel[buf_len]; float complex buf_output [buf_len]; // // generate input sequence using symbol stream generator // symstreamcf gen = symstreamcf_create_linear(LIQUID_FIRFILT_ARKAISER,k,m,beta,ms); // // create multi-path channel filter // float complex hc[hc_len]; for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqlms_cccf_decisiondirected_example.m" // print usage/help message void usage() { printf("Usage: eqlms_cccf_decisiondirected_example [OPTION]\n"); printf(" h : print help\n"); printf(" n : number of symbols, default: 500\n"); printf(" s : SNR [dB], default: 30\n"); printf(" c : number of channel filter taps (minimum: 1), default: 5\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter semi-length (symbols), default: 4\n"); printf(" b : filter excess bandwidth factor, default: 0.3\n"); printf(" p : equalizer semi-length (symbols), default: 3\n"); printf(" u : equalizer learning rate, default; 0.05\n"); printf(" M : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int num_symbols=500; // number of symbols to observe float SNRdB = 30.0f; // signal-to-noise ratio [dB] unsigned int hc_len=5; // channel filter length unsigned int k=2; // matched filter samples/symbol unsigned int m=3; // matched filter delay (symbols) float beta=0.3f; // matched filter excess bandwidth factor unsigned int p=3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.08f; // learning rate // modulation type/depth modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"hn:s:c:k:m:b:p:u:M:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'p': p = atoi(optarg); break; case 'u': mu = atof(optarg); break; case 'M': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // validate input if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, channel must have at least 1 tap\n", argv[0]); exit(1); } else if (k < 2) { fprintf(stderr,"error: %s, samples/symbol must be at least 2\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (beta < 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s, filter excess bandwidth must be in [0,1]\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer semi-length must be at least 1 symbol\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } // derived values unsigned int hm_len = 2*k*m+1; // matched filter length unsigned int hp_len = 2*k*p+1; // equalizer filter length unsigned int num_samples = k*num_symbols; // bookkeeping variables float complex sym_tx[num_symbols]; // transmitted data sequence float complex x[num_samples]; // interpolated time series float complex y[num_samples]; // channel output float complex z[num_samples]; // equalized output float hm[hm_len]; // matched filter response float complex hc[hc_len]; // channel filter coefficients float complex hp[hp_len]; // equalizer filter coefficients unsigned int i; // generate matched filter response liquid_firdes_prototype(LIQUID_FIRFILT_RRC, k, m, beta, 0.0f, hm); firinterp_crcf interp = firinterp_crcf_create(k, hm, hm_len); // create the modem objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); unsigned int M = 1 << modemcf_get_bps(mod); // generate channel impulse response, filter hc[0] = 1.0f; for (i=1; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqlms_cccf_example.m" int main() { unsigned int i, h_len=5, w_len=11, num_symbols=400; float mu = 0.7f; // modem modemcf mod = modemcf_create(LIQUID_MODEM_QPSK); // create channel filter (random coefficients) float complex h[h_len]; h[0] = 1.0f; for (i=1; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqrls_cccf_example.m" int main() { // options unsigned int n=512; // number of symbols to observe unsigned int ntrain=256;// number of training symbols unsigned int h_len=6; // channel filter length unsigned int p=12; // equalizer order // bookkeeping variables float complex d[n]; // data sequence float complex y[n]; // received data sequence (filtered by channel) float complex d_hat[n]; // recovered data sequence float complex h[h_len]; // channel filter coefficients float complex w[p]; // equalizer filter coefficients unsigned int i; // create equalizer (default initial coefficients) eqrls_cccf eq = eqrls_cccf_create(NULL,p); // create channel filter (random delay taps) h[0] = 1.0f; for (i=1; i #include #include "liquid.h" int main(int argc, char*argv[]) { // create agc object agc_crcf q = agc_crcf_create(); // try to set invalid parameter int rc = agc_crcf_set_bandwidth(q, -1e-3f); if (rc != LIQUID_OK) printf("received error %d: %s\n", rc, liquid_error_info(rc)); // destroy object agc_crcf_destroy(q); // printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/fading_generator_example.c000066400000000000000000000052411474751757600226160ustar00rootroot00000000000000// // Fading generator example // #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "debug_fading_generator_example.m" int main() { // options unsigned int h_len=51; // doppler filter length float fd=0.05f; // maximum doppler frequency float K=2.0f; // Rice fading factor float omega=1.0f; // mean power float theta=0.0f; // angle of arrival unsigned int n=256; // number of samples // generate filter unsigned int i; float h[h_len]; fir_design_doppler(h_len,fd,K,theta,h); firfilt_rrrf fi = firfilt_rrrf_create(h,h_len); firfilt_rrrf fq = firfilt_rrrf_create(h,h_len); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n",OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "fdelay_rrrf_example.m" int main() { // options unsigned int nmax = 200; // maximum delay unsigned int m = 12; // filter semi-length unsigned int npfb = 10; // fractional delay resolution unsigned int num_samples= 240; // number of samples to run float delay =27.8; // requested delay // create delay object and set delay fdelay_rrrf q = fdelay_rrrf_create(nmax, m, npfb); fdelay_rrrf_set_delay(q, delay); fdelay_rrrf_print(q); // generate impulse and propagate through object float x[num_samples]; float y[num_samples]; unsigned int i; for (i=0; i #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("fec_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : input data size (number of uncoded bytes)\n"); printf(" c : coding scheme, (h74 default):\n"); liquid_print_fec_schemes(); } int main(int argc, char*argv[]) { // options unsigned int n = 4; // data length (bytes) unsigned int nmax = 2048; // maximum data length fec_scheme fs = LIQUID_FEC_HAMMING74; // error-correcting scheme int dopt; while((dopt = getopt(argc,argv,"uhn:c:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': n = atoi(optarg); break; case 'c': fs = liquid_getopt_str2fec(optarg); if (fs == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } // ensure proper data length n = (n > nmax) ? nmax : n; // create arrays unsigned int n_enc = fec_get_enc_msg_length(fs,n); printf("dec msg len : %u\n", n); printf("enc msg len : %u\n", n_enc); unsigned char data[n]; // original data message unsigned char msg_enc[n_enc]; // encoded data message unsigned char msg_cor[n_enc]; // corrupted data message unsigned char msg_dec[n]; // decoded data message // create object fec q = fec_create(fs,NULL); fec_print(q); unsigned int i; // create message for (i=0; i>= 1; } } //printf("number of symbol errors detected: %d\n", num_errors_detected); printf("number of symbol errors received: %3u / %3u\n", num_sym_errors, n); printf("number of bit errors received: %3u / %3u\n", num_bit_errors, n*8); // clean up objects fec_destroy(q); return 0; } liquid-dsp-1.7.0/examples/fec_soft_example.c000066400000000000000000000142521474751757600211120ustar00rootroot00000000000000// // fec_soft_example.c // // This example demonstrates the interface for forward error-correction // (FEC) codes with soft-decision decoding. A buffer of data bytes is // encoded before the data are corrupted with at least one error and // noise. The decoder then attempts to recover the original data set // from the soft input bits. The user may select the FEC scheme from // the command-line interface. // // SEE ALSO: fec_example.c // packetizer_soft_example.c #include #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("fecsoft_example [options]\n"); printf(" u/h : print usage\n"); printf(" v/q : verbose/queit (print soft bits?)\n"); printf(" n : input data size (number of uncoded bytes)\n"); printf(" c : coding scheme, (h74 default):\n"); liquid_print_fec_schemes(); } int main(int argc, char*argv[]) { // options unsigned int n = 4; // data length (bytes) unsigned int nmax = 2048; // maximum data length fec_scheme fs = LIQUID_FEC_HAMMING74; // error-correcting scheme int verbose = 1; // verbose? int dopt; while((dopt = getopt(argc,argv,"uhvqn:c:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'v': verbose = 1; break; case 'q': verbose = 0; break; case 'n': n = atoi(optarg); break; case 'c': fs = liquid_getopt_str2fec(optarg); if (fs == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } // ensure proper data length n = (n > nmax) ? nmax : n; // create arrays unsigned int n_enc = fec_get_enc_msg_length(fs,n); printf("dec msg len : %u\n", n); printf("enc msg len : %u\n", n_enc); unsigned char data[n]; // original data message unsigned char msg_enc[n_enc]; // encoded data message unsigned char msg_cor_soft[8*n_enc]; // corrupted data message (soft bits) unsigned char msg_cor_hard[n_enc]; // corrupted data message (hard bits) unsigned char msg_dec[n]; // decoded data message // create object fec q = fec_create(fs,NULL); fec_print(q); unsigned int i; // create message for (i=0; i 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; msg_cor_soft[i] = soft_bit; } // convert to hard bits (printing purposes) for (i=0; i> 0) & 0x80; msg_cor_hard[i] |=(msg_cor_soft[8*i+1] >> 1) & 0x40; msg_cor_hard[i] |=(msg_cor_soft[8*i+2] >> 2) & 0x20; msg_cor_hard[i] |=(msg_cor_soft[8*i+3] >> 3) & 0x10; msg_cor_hard[i] |=(msg_cor_soft[8*i+4] >> 4) & 0x08; msg_cor_hard[i] |=(msg_cor_soft[8*i+5] >> 5) & 0x04; msg_cor_hard[i] |=(msg_cor_soft[8*i+6] >> 6) & 0x02; msg_cor_hard[i] |=(msg_cor_soft[8*i+7] >> 7) & 0x01; } // decode message fec_decode_soft(q, n, msg_cor_soft, msg_dec); printf("original message: [%3u] ",n); for (i=0; i> (8-j-1)) & 0x01; unsigned int bit_rec = (msg_cor_soft[8*i+j] > 127) ? 1 : 0; //printf("%1u %3u (%1u) %c", bit_enc, msg_cor_soft[i], bit_rec, bit_enc != bit_rec ? '*' : ' '); printf("%4u%c", msg_cor_soft[8*i+j], bit_enc != bit_rec ? '*' : ' '); } printf(" : %c%.2X\n", msg_cor_hard[i]==msg_enc[i] ? ' ' : '*', (unsigned int) (msg_cor_hard[i])); } } // verbose printf("decoded message: [%3u] ",n); for (i=0; i>= 1; } } //printf("number of symbol errors detected: %d\n", num_errors_detected); printf("number of symbol errors received: %3u / %3u\n", num_sym_errors, n); printf("number of bit errors received: %3u / %3u\n", num_bit_errors, n*8); // clean up objects fec_destroy(q); return 0; } liquid-dsp-1.7.0/examples/fft_example.c000066400000000000000000000053461474751757600201050ustar00rootroot00000000000000// // fft_example.c // // This example demonstrates the interface to the fast discrete Fourier // transform (FFT). // SEE ALSO: mdct_example.c // fct_example.c // #include #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("fft_example [options]\n"); printf(" h : print help\n"); printf(" v/q : verbose/quiet\n"); printf(" n : fft size, default: 16\n"); } int main(int argc, char*argv[]) { // options unsigned int nfft = 16; // transform size int method = 0; // fft method (ignored) int verbose = 0; // verbose output? int dopt; while ((dopt = getopt(argc,argv,"hvqn:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbose = 1; break; case 'q': verbose = 0; break; case 'n': nfft = atoi(optarg); break; default: exit(1); } } // allocate memory arrays float complex * x = (float complex*) fft_malloc(nfft*sizeof(float complex)); float complex * y = (float complex*) fft_malloc(nfft*sizeof(float complex)); float complex * z = (float complex*) fft_malloc(nfft*sizeof(float complex)); // initialize input unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "fftfilt_crcf_example.m" int main() { // options unsigned int h_len=57; // filter length float fc=0.10f; // cutoff frequency float As=60.0f; // stop-band attenuation unsigned int n=64; // number of samples per block unsigned int num_blocks=6; // total number of blocks // derived values unsigned int num_samples = n * num_blocks; // design filter float h[h_len]; liquid_firdes_kaiser(h_len, fc, As, 0, h); // design FFT-based filter and scale to bandwidth fftfilt_crcf q0 = fftfilt_crcf_create(h, h_len, n); fftfilt_crcf_set_scale(q0, 2.0f*fc); // design regular FIR filter firfilt_crcf q1 = firfilt_crcf_create(h, h_len); firfilt_crcf_set_scale(q1, 2.0f*fc); unsigned int i; // allocate memory for data arrays float complex x[num_samples]; // input float complex y0[num_samples]; // output (fftfilt) float complex y1[num_samples]; // output (firfilt) // generate input signal (noise) for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdecim_crcf_example.m" // print usage/help message void usage() { printf("firdecim_crcf_example:\n"); printf(" -h : print usage/help\n"); printf(" -M : decimation factor, M > 1 default: 2\n"); printf(" -m : filter delay (symbols), m > 0, default: 2\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); printf(" -n : number of samples (after decim), default: 8\n"); } int main(int argc, char*argv[]) { // options unsigned int M = 6; // decimation factor unsigned int m = 8; // filter delay float As = 60.0f; // filter stop-band attenuation unsigned int num_samples = 120; // number of samples (after decim) int dopt; while ((dopt = getopt(argc,argv,"hM:m:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'M': M = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'n': num_samples = atoi(optarg); break; default: usage(); return 1; } } // validate options if (M < 2) { fprintf(stderr,"error: %s, decim factor must be greater than 1\n", argv[0]); return 1; } else if (m < 1) { fprintf(stderr,"error: %s, filter delay must be greater than 0\n", argv[0]); return 1; } else if (As <= 0.0) { fprintf(stderr,"error: %s, stop-band attenuation must be greater than zero\n", argv[0]); return 1; } else if (num_samples < 1) { fprintf(stderr,"error: %s, must have at least one sample\n", argv[0]); return 1; } // data arrays float complex x[M*num_samples]; // number of samples before decimation float complex y[ num_samples]; // number of samples after decimation // initialize input array unsigned int i; unsigned int w_len = (unsigned int)(0.9*M*num_samples); float f0 = 0.017f; float f1 = 0.021f; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdes_doppler_example.m" int main() { // options float fd = 0.2f; // Normalized Doppler frequency float K = 10.0f; // Rice fading factor float theta = 0.0f; // LoS component angle of arrival unsigned int h_len = 161; // filter length // generate the filter float h[h_len]; liquid_firdes_doppler(h_len,fd,K,theta,h); // output to file FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h_len=%u;\n",h_len); unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdes_kaiser_example.m" // print usage/help message void usage() { printf("firdes_kaiser_example:\n"); printf(" u/h : print usage/help\n"); printf(" f : filter cutoff frequency, 0 < f < 0.5, default: 0.2\n"); printf(" s : filter stop-band attenuation [dB], 0 < s, default: 60\n"); printf(" m : fractional sample delay, -0.5 < m < 0.5, default: 0\n"); printf(" n : filter length [taps], n > 1, default: 55\n"); } int main(int argc, char*argv[]) { // options float fc=0.2f; // filter cutoff frequency float As=60.0f; // stop-band attenuation [dB] float mu=0.0f; // fractional timing offset unsigned int h_len=55; // filter length int dopt; while ((dopt = getopt(argc,argv,"uhf:n:s:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'f': fc = atof(optarg); break; case 'n': h_len = atoi(optarg); break; case 's': As = atof(optarg); break; case 'm': mu = atof(optarg); break; default: exit(1); } } // validate input if ( fc <= 0.0f ) { fprintf(stderr,"error: %s, filter cutoff frequency must be greater than zero\n", argv[0]); exit(1); } else if ( h_len == 0 ) { fprintf(stderr,"error: %s, filter length must be greater than zero\n", argv[0]); exit(1); } printf("filter design parameters\n"); printf(" cutoff frequency : %8.4f\n", fc); printf(" stop-band attenuation [dB] : %8.4f\n", As); printf(" fractional sample offset : %8.4f\n", mu); printf(" filter length : %u\n", h_len); // generate the filter unsigned int i; float h[h_len]; liquid_firdes_kaiser(h_len,fc,As,mu,h); // print coefficients for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdespm_callback_example.m" // user-defined callback function defining response and weights int callback(double _frequency, void * _userdata, double * _desired, double * _weight) { // de-reference pointer as floating-point value unsigned int n = *((unsigned int*)_userdata); double v = sincf(n*_frequency); double fc = 1.0f / (float)n; // inverse sinc if (_frequency < fc) { *_desired = 1.0f / v; // inverse of sinc *_weight = 4.0f; } else { *_desired = 0.0f; // stop-band *_weight = 10*fabs(v) * exp(4.0*_frequency); } return 0; } int main(int argc, char*argv[]) { // filter design parameters unsigned int n = 8; // sinc filter length unsigned int h_len = 81; // inverse sinc filter length liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; unsigned int num_bands = 2; float bands[4] = {0.00f, 0.75f/(float)n, // pass-band 1.05f/(float)n, 0.5f}; // stop-band // design filter float h[h_len]; firdespm q = firdespm_create_callback(h_len,num_bands,bands,btype,callback,&n); firdespm_execute(q,h); firdespm_destroy(q); // print coefficients unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdespm_example.m" int main(int argc, char*argv[]) { // filter design parameters unsigned int h_len = 91; liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; unsigned int num_bands = 4; float bands[8] = {0.00f, 0.10f, 0.12f, 0.18f, 0.20f, 0.30f, 0.31f, 0.50f}; float des[4] = {1.0f, 0.0f, 0.1f, 0.0f}; float weights[4] = {1.0f, 4.0f, 8.0f, 4.0f}; liquid_firdespm_wtype wtype[4] = {LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_EXPWEIGHT}; unsigned int i; float h[h_len]; firdespm_run(h_len,num_bands,bands,des,weights,wtype,btype,h); // print coefficients for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdespm_halfband_example.m" int main(int argc, char*argv[]) { // filter design parameters unsigned int m = 4; float ft = 0.4f; // derived values unsigned int h_len = 4*m + 1; float h[h_len]; liquid_firdespm_halfband_ft(m, ft, h); // print coefficients unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdespm_lowpass_example.m" // print usage/help message void usage() { printf("firdespm_lowpass_example:\n"); printf(" -h : print usage/help\n"); printf(" -n : filter length, 1 < n default: 57\n"); printf(" -f : filter cutoff frequency, 0 < f < 0.5, default: 0.2\n"); printf(" -s : stop-band attenuation [dB], 0 < s, default: 60\n"); } int main(int argc, char*argv[]) { // options unsigned int n = 57; // filter cutoff frequency float fc = 0.2f; // filter cutoff frequency float As = 60.0f; // stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hn:f:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; case 's': As = atof(optarg); break; default: return -1; } } unsigned int i; printf("filter design parameters\n"); printf(" length : %12u\n", n); printf(" cutoff frequency : %12.8f Fs\n", fc); printf(" stop-band attenuation : %12.3f dB\n", As); // design the filter float h[n]; firdespm_lowpass(n,fc,As,0,h); #if 0 // print coefficients for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firfarrow_rrrf_example.m" // print usage/help message void usage() { printf("firfarrow_rrrf_example [options]\n"); printf(" h : print help\n"); printf(" t : fractional sample offset, t in [-0.5,0.5], default: 0.2\n"); } int main(int argc, char*argv[]) { // options unsigned int h_len = 19; // filter length unsigned int p = 5; // polynomial order float fc = 0.45f; // filter cutoff float As = 60.0f; // stop-band attenuation [dB] float mu = 0.1f; // fractional sample delay unsigned int num_samples = 60; // number of samples to evaluate int dopt; while ((dopt = getopt(argc,argv,"ht:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': mu = atof(optarg); break; default: exit(1); } } // data arrays float x[num_samples]; // input data array float y[num_samples]; // output data array // create and initialize Farrow filter object firfarrow_rrrf f = firfarrow_rrrf_create(h_len, p, fc, As); firfarrow_rrrf_set_delay(f, mu); // create low-pass filter for input signal iirfilt_rrrf lowpass = iirfilt_rrrf_create_lowpass(3, 0.1f); // push input through filter unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firfilt_cccf_example.m" // print usage/help message void usage() { printf("firfilt_cccf_example:\n"); printf(" h : print usage/help\n"); printf(" n : sequence length, default: 32\n"); printf(" s : SNR, signal-to-noise ratio [dB], default: 20\n"); } int main(int argc, char*argv[]) { // options unsigned int sequence_len = 256; // sequence length float SNRdB = 10.0f; // signal-to-noise ratio (dB) int dopt; while ((dopt = getopt(argc,argv,"hn:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': sequence_len = atof(optarg); break; case 's': SNRdB = atoi(optarg); break; default: usage(); exit(-1); } } unsigned int i; // derived values unsigned int num_samples = 3*sequence_len; // data arrays float complex sequence[sequence_len]; // sequence float complex x[num_samples]; // input sequence float complex rxy[num_samples]; // correlator output // generate random sequence for (i=0; i cabsf(rxy_peak)) rxy_peak = rxy[i]; } printf("peak cross-correlation : %12.8f, angle %12.8f\n", cabsf(rxy_peak), cargf(rxy_peak)); // destroy allocated objects firfilt_cccf_destroy(q); // // write results to file // FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"num_samples = %u;\n", num_samples); // write signal to output file for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firfilt_cccf_notch_example.m" int main() { // options unsigned int num_samples = 600; // number of samples unsigned int m = 25; // prototype filter semi-length float As = 30.0f; // prototype filter stop-band suppression float f0 = 0.15f; // notch frequency // design filter from prototype firfilt_cccf q = firfilt_cccf_create_notch(m,As,f0); firfilt_cccf_print(q); // allocate memory for data arrays float complex x[num_samples]; // original input float complex y[num_samples]; // filtered signal // generate input signal unsigned int i; for (i=0; i #include #include #include "liquid.h" int main() { // design filter from prototype firfilt_crcf filt_orig = firfilt_crcf_create_kaiser(21, 0.345f, 60.0f, 0.0f); firfilt_crcf_set_scale(filt_orig, 2.0f); firfilt_crcf_print(filt_orig); // start running input through filter unsigned int n = 32; unsigned int i; float complex x, y_orig, y_copy; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firfilt_crcf_dcblocker_example.m" int main() { // options unsigned int num_samples = 1200; // number of samples unsigned int m = 25; // prototype filter semi-length float As = 30.0f; // prototype filter stop-band suppression // design filter from prototype firfilt_crcf q = firfilt_crcf_create_dc_blocker(m,As); firfilt_crcf_print(q); // allocate memory for data arrays float complex x[num_samples]; // original input float complex y[num_samples]; // input with DC offset float complex z[num_samples]; // DC-blocked result // generate signals unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firfilt_crcf_example.m" int main() { // options unsigned int h_len=65; // filter length float fc=0.1f; // cutoff frequency float As=60.0f; // stop-band attenuation unsigned int n=240; // number of samples // design filter from prototype and scale to bandwidth firfilt_crcf q = firfilt_crcf_create_kaiser(h_len, fc, As, 0.0f); firfilt_crcf_set_scale(q, 2.0f*fc); firfilt_crcf_print(q); unsigned int i; // allocate memory for data arrays float complex x[n]; float complex y[n]; // generate input signal (sine wave with decaying amplitude) unsigned int wlen = (unsigned int)roundf(0.75*n); for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "firfilt_rrrf_example.m" int main() { // options unsigned int h_len = 65; // filter length float fc = 0.1f; // cutoff frequency float As = 60.0f; // stop-band attenuation unsigned int n = 240; // number of samples // design filter from prototype and scale to bandwidth firfilt_rrrf q = firfilt_rrrf_create_kaiser(h_len, fc, As, 0.0f); firfilt_rrrf_set_scale(q, 2.0f*fc); // generate input signal (sine wave with decaying amplitude) float x[n], y[n]; // allocate memory for data arrays unsigned int wlen = (unsigned int)roundf(0.75*n); unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firhilb_decim_example.m" int main() { unsigned int m=5; // Hilbert filter semi-length float As=60.0f; // stop-band attenuation [dB] float fc=0.37f; // signal center frequency unsigned int num_samples=128; // number of samples // data arrays float x[2*num_samples]; // real input float complex y[num_samples]; // complex output // initialize input array unsigned int i; for (i=0; i<2*num_samples; i++) x[i] = cosf(2*M_PI*fc*i) + 0.6f*sinf(2*M_PI*1.1*fc*i); // create Hilbert transform object firhilbf q = firhilbf_create(m,As); // execute transform (decimator) to compute complex signal firhilbf_decim_execute_block(q, x, num_samples, y); // destroy Hilbert transform object firhilbf_destroy(q); printf("firhilb decimated %u real samples to %u complex samples\n", 2*num_samples, num_samples); // // export results to file // FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"h_len=%u;\n", 4*m+1); fprintf(fid,"num_samples=%u;\n", num_samples); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firhilb_example.m" int main() { unsigned int m = 7; // Hilbert filter semi-length float As = 60.0f; // stop-band attenuation [dB] float fc = 0.123456; // signal center frequency unsigned int num_input_samples=128; // number of samples // derived values unsigned int h_len = 4*m+1; // filter length unsigned int num_total_samples = num_input_samples + h_len; // create Hilbert transform object firhilbf qi = firhilbf_create(m,As); // interpolator firhilbf qd = firhilbf_create(m,As); // decimator firhilbf_print(qi); // data arrays float complex x[ num_total_samples]; // complex input float y[2*num_total_samples]; // real output float complex z[ num_total_samples]; // complex output // initialize input array unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firhilb_filter_example.m" int main() { unsigned int m = 7; // Hilbert filter semi-length float As = 60.0f; // stop-band attenuation [dB] unsigned int n = 128; // number of input samples int usb = 1; // keep upper (or lower) side-band // derived values unsigned int h_len = 4*m+1; // filter length unsigned int num_samples = n + h_len; // create Hilbert transform object firhilbf q0 = firhilbf_create(m,As); // interpolator firhilbf q1 = firhilbf_create(m,As); // decimator firhilbf_print(q0); // data arrays float complex x[num_samples]; // complex input float y[num_samples]; // real output float complex z[num_samples]; // complex output // run transform unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firhilb_interp_example.m" int main() { unsigned int m=5; // Hilbert filter semi-length float As=60.0f; // stop-band attenuation [dB] float fc=0.31f; // signal center frequency unsigned int num_samples=128; // number of samples // data arrays float complex x[num_samples]; // complex input float y[2*num_samples]; // real output // initialize input array unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firinterp_crcf_example.m" // print usage/help message void usage() { printf("firinterp_crcf_example:\n"); printf(" -h : print usage/help\n"); printf(" -k : samples/symbol (interp factor), k > 1, default: 4\n"); printf(" -m : filter delay (symbols), m > 0, default: 3\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); printf(" -n : number of data symbols, default: 16\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 4; // samples/symbol unsigned int m = 3; // filter delay float As = 60.0f; // filter stop-band attenuation unsigned int num_syms = 16; // number of data symbols int dopt; while ((dopt = getopt(argc,argv,"uhk:m:s:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'n': num_syms = atoi(optarg); break; default: exit(1); } } // validate options if (k < 2) { fprintf(stderr,"error: %s, interp factor must be greater than 1\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, filter delay must be greater than 0\n", argv[0]); exit(1); } else if (num_syms < 1) { fprintf(stderr,"error: %s, must have at least one data symbol\n", argv[0]); usage(); return 1; } // derived values unsigned int num_syms_total = num_syms + 2*m; // total symbols (w/ delay) unsigned int num_samples = k*num_syms_total; // total samples // create interpolator from prototype firinterp_crcf q = firinterp_crcf_create_kaiser(k,m,As); // generate input signal and interpolate float complex x[num_syms_total]; // input symbols float complex y[num_samples]; // output samples unsigned int i; for (i=0; i= k*m) && ((i%k)==0)) printf(" **\n"); else printf("\n"); } // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"num_syms_total = %u;\n", num_syms_total); fprintf(fid,"num_samples = k*num_syms_total;\n"); fprintf(fid,"x = zeros(1,num_syms_total);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firinterp_firdecim_crcf_example.m" // print usage/help message void usage() { printf("firinterp_firdecim_crcf_example:\n"); printf(" -h : print usage/help\n"); printf(" -k : samples/symbol (interp factor), k > 1, default: 2\n"); printf(" -m : filter delay (symbols), m > 0, default: 2\n"); printf(" -b : excess bandwidth factor, 0 < beta < 1, default: 0.5\n"); printf(" -n : number of data symbols, default: 8\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 2; // samples/symbol unsigned int m = 3; // filter delay float dt = 0.5f; // filter fractional symbol delay float beta = 0.5f; // filter excess bandwidth unsigned int num_syms = 8; // number of data symbols int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_syms = atoi(optarg); break; default: usage(); return 1; } } // validate options if (k < 2) { fprintf(stderr,"error: %s, interp factor must be greater than 1\n", argv[0]); return 1; } else if (m < 1) { fprintf(stderr,"error: %s, filter delay must be greater than 0\n", argv[0]); return 1; } else if (beta <= 0.0 || beta > 1.0f) { fprintf(stderr,"error: %s, beta (excess bandwidth factor) must be in (0,1]\n", argv[0]); return 1; } else if (num_syms < 1) { fprintf(stderr,"error: %s, must have at least one data symbol\n", argv[0]); return 1; } // derived values unsigned int h_len = 2*k*m + 1; // prototype filter length unsigned int num_syms_total = num_syms + 2*m; // number of total symbols (w/ delay) unsigned int num_samples = k*num_syms_total; // number of samples // design filter and create interpolator and decimator objects float h[h_len]; // transmit filter float g[h_len]; // receive filter (reverse of h) liquid_firdes_rrcos(k,m,beta,dt,h); unsigned int i; for (i=0; i= k*m) && ((i%k)==0)) printf(" **\n"); else printf("\n"); } printf("output symbols:\n"); for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firinterp_rrrf_linear_example.m" int main(int argc, char*argv[]) { // options unsigned int M = 8; // interpolation factor unsigned int num_symbols= 16; // number of data symbols // generate input signal and interpolate float x[ num_symbols]; // input symbols float y[M*num_symbols]; // output samples unsigned int i; for (i=0; i= M) && ((i%M)==0) ? " **" : ""); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"M = %u;\n", M); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = M*num_symbols;\n"); fprintf(fid,"x = zeros(1,num_symbols);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firinterp_rrrf_window_example.m" int main(int argc, char*argv[]) { // options unsigned int M = 8; // interpolation factor unsigned int m = 1; // filter semi-length unsigned int num_symbols= 16; // number of data symbols // generate input signal and interpolate float x[ num_symbols]; // input symbols float y[M*num_symbols]; // output samples unsigned int i; for (i=0; i= M) && ((i%M)==0) ? " **" : ""); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"M = %u;\n", M); fprintf(fid,"m = %u;\n", m); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = M*num_symbols;\n"); fprintf(fid,"x = zeros(1,num_symbols);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "firpfb_rrrf_example.m" int main(int argc, char*argv[]) { // options unsigned int M = 16; // interpolation factor unsigned int m = 4; // filter delay (input samples) unsigned int num_samples = 40; // number of input samples to generate // create object firpfb_rrrf pfb = firpfb_rrrf_create_default(M, m); firpfb_rrrf_print(pfb); // generate and interpolate signal (windowed sinc pulse) float buf_0[ num_samples]; float buf_1[M*num_samples]; unsigned int i, j; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch2_crcf_example.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" h : print help\n"); printf(" M : number of channels, default: 6\n"); printf(" m : prototype filter semi-length, default: 4\n"); printf(" s : prototype filter stop-band attenuation, default: 80\n"); printf(" n : number of 'symbols' to analyze, default: 20\n"); } int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels unsigned int m = 4; // filter semi-length (symbols) unsigned int num_symbols=20; // number of symbols float As = 80.0f; // filter stop-band attenuation int dopt; while ((dopt = getopt(argc,argv,"hM:m:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'M': num_channels = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'n': num_symbols = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (num_channels < 2 || num_channels % 2) { fprintf(stderr,"error: %s, number of channels must be greater than 2 and even\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be greater than zero\n", argv[0]); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: %s, number of symbols must be greater than zero", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; // allocate arrays float complex x[num_samples]; float complex y[num_samples]; // generate input signal for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch2_crcf_reconstruct_example.m" int main(int argc, char*argv[]) { // options unsigned int M = 64; // number of channels in analysis filterbank unsigned int P = 22; // number of channels in synthesis filterbank unsigned int m = 5; // filter semi-length (symbols) float As = 60.0f; // filter stop-band attenuation float fc = 0.23; // frequency in band to center synthesis bank unsigned int num_blocks=1<<14; // number of blocks to generate // derived values unsigned int M2=M/2, P2=P/2; // channelizer half sizes, for convenience int channel_id = (int)(roundf(fc*M)) % M; // index corresponding to fc unsigned int i; // create filterbank objects from prototype firpfbch2_crcf qa = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, M, m, As); firpfbch2_crcf qs = firpfbch2_crcf_create_kaiser(LIQUID_SYNTHESIZER, P, m, As); // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // add signals (gen, fc, bw, gain, {options}) msourcecf_add_noise(gen, 0.00f, 1.0f, -60); // wide-band noise msourcecf_add_noise(gen, -0.30f, 0.1f, -20); // narrow-band noise msourcecf_add_tone (gen, 0.08f, 0.0f, 0); // tone // modulated data msourcecf_add_modem(gen, 0.18f, // center frequency 0.080f, // bandwidth (symbol rate) -20, // gain LIQUID_MODEM_QPSK, // modulation scheme 12, // filter semi-length 0.3f); // modem parameters msourcecf_add_tone (gen, 0.24f, 0.0f, -40); // another tone // create spectral periodogoram unsigned int nfft = 2400; spgramcf p0 = spgramcf_create_default(nfft); // original spectrum spgramcf p1 = spgramcf_create_default(nfft); // reconstructed spectrum // run channelizer float complex buf_a_time[M2]; // analysis, time float complex buf_a_freq[M]; // analysis, frequency float complex buf_s_freq[P]; // synthesis, frequency float complex buf_s_time[P2]; // synthesis, time for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch_crcf_analysis_example.m" int main() { // options unsigned int num_channels = 8; // number of channels unsigned int m = 4; // filter delay float As = 60; // stop-band attenuation unsigned int num_frames = 25; // number of frames // unsigned int i; unsigned int k; // derived values unsigned int num_samples = num_frames * num_channels; // data arrays float complex x[num_samples]; // time-domain input [size: num_samples x 1 ] float complex y[num_samples]; // channelized output [size: num_channels x num_frames] // initialize input with zeros for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch_crcf_example.m" int main() { // options unsigned int num_channels=4; // number of channels unsigned int p=3; // filter length (symbols) unsigned int num_symbols=6; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate synthesis filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = p*num_channels; float h[h_len]; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch_crcf_msource_example.m" int main() { // options unsigned int M = 5; // number of channels unsigned int m = 12; // filter delay unsigned int num_samples= 512000; // number of samples to generate unsigned int nfft = 1200; // FFT size for analysis // data arrays unsigned int i; float complex buf_0[M]; // time-domain input float complex buf_1[M]; // channelized output // create filterbank channelizer object using external filter coefficients firpfbch_crcf q = firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, M, m, 0.5f, LIQUID_FIRFILT_ARKAISER); // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // add signals (gen, fc, bw, gain, {options}) msourcecf_add_noise(gen, 0.00f,1.00f, -40); // noise floor msourcecf_add_noise(gen, 0.02f,0.05f, 0); // narrow-band noise msourcecf_add_tone (gen, -0.40f,0.00f, 20); // tone msourcecf_add_modem(gen, 0.20f,0.10f, 0, LIQUID_MODEM_QPSK, 12, 0.2f); // modulated data (linear) msourcecf_add_gmsk (gen, -0.20f,0.05f, 0, 4, 0.3f); // modulated data (GMSK) // create objects for computing spectra spgramcf psd_0 = spgramcf_create_default(nfft); spgramcf psd_1[M]; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch_crcf_synthesis_example.m" int main() { // options unsigned int num_channels = 16; // number of channels unsigned int m = 5; // filter delay float As = 60; // stop-band attenuation unsigned int num_frames = 25; // number of frames // unsigned int i; unsigned int k; // derived values unsigned int num_samples = num_frames * num_channels; // data arrays float complex x[num_channels][num_frames]; // channelized input float complex y[num_samples]; // time-domain output [size: num_samples x 1] // create narrow-band pulse unsigned int pulse_len = 17; // pulse length [samples] float bw = 0.30f; // pulse width (bandwidth) float pulse[pulse_len]; // buffer liquid_firdes_kaiser(pulse_len, bw, 50.0f, 0.0f, pulse); // generate input signal(s) int enabled[num_channels]; // signal enabled? for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbchr_crcf_example.m" int main(int argc, char*argv[]) { // options unsigned int M = 16; // number of channels unsigned int P = 6; // output decimation rate unsigned int m = 5; // filter semi-length (symbols) unsigned int num_blocks=1<<16; // number of symbols float As = 60.0f; // filter stop-band attenuation unsigned int i; unsigned int channel_id = 3; // create filterbank objects from prototype firpfbchr_crcf qa = firpfbchr_crcf_create_kaiser(M, P, m, As); firpfbchr_crcf_print(qa); // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // add signals (gen, fc, bw, gain, {options}) msourcecf_add_noise(gen, 0.00f, 1.0f, -60); // wide-band noise msourcecf_add_noise(gen, -0.30f, 0.1f, -20); // narrow-band noise msourcecf_add_tone (gen, 0.08f, 0.0f, 0); // tone // modulated data msourcecf_add_modem(gen, (float)channel_id/(float)M, // center frequency 0.080f, // bandwidth (symbol rate) -20, // gain LIQUID_MODEM_QPSK, // modulation scheme 12, // filter semi-length 0.3f); // modem parameters // create spectral periodogoram unsigned int nfft = 2400; spgramcf p0 = spgramcf_create_default(nfft); spgramcf p1 = spgramcf_create_default(nfft); // run channelizer float complex buf_0[P]; float complex buf_1[M]; for (i=0; i #include #include #include #include #include #include #include "liquid.h" // flexframesync callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata) { const char * filename = (const char*)_userdata; FILE * fid = fopen(filename,"w"); if (fid == NULL) { printf("could not open '%s' for writing\n", filename); return 0; } unsigned int i; for (i=0; i<_stats.num_framesyms; i++) fprintf(fid,"%12.8f %12.8f\n", crealf(_stats.framesyms[i]), cimagf(_stats.framesyms[i])); fclose(fid); return 0; } int main(int argc, char *argv[]) { // options modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) unsigned int payload_len = 480; // payload length const char * filename = "flexframesync_debug_example.dat"; // create flexframegen object flexframegenprops_s fgprops; flexframegenprops_init_default(&fgprops); fgprops.mod_scheme = ms; fgprops.check = check; fgprops.fec0 = fec0; fgprops.fec1 = fec1; flexframegen fg = flexframegen_create(&fgprops); // create flexframesync object flexframesync fs = flexframesync_create(callback,(void*)filename); // assemble the frame (NULL pointers for default values) flexframegen_assemble(fg, NULL, NULL, payload_len); // generate the frame in blocks unsigned int buf_len = 256; float complex buf[buf_len]; int frame_complete = 0; while (!frame_complete) { // write samples to buffer frame_complete = flexframegen_write_samples(fg, buf, buf_len); // run through frame synchronizer flexframesync_execute(fs, buf, buf_len); } // destroy allocated objects flexframegen_destroy(fg); flexframesync_destroy(fs); return 0; } liquid-dsp-1.7.0/examples/flexframesync_example.c000066400000000000000000000142051474751757600221660ustar00rootroot00000000000000// // flexframesync_example.c // // This example demonstrates the basic interface to the flexframegen and // flexframesync objects used to completely encapsulate raw data bytes // into frame samples (nearly) ready for over-the-air transmission. A // 14-byte header and variable length payload are encoded into baseband // symbols using the flexframegen object. The resulting symbols are // interpolated using a root-Nyquist filter and the resulting samples are // then fed into the flexframesync object which attempts to decode the // frame. Whenever frame is found and properly decoded, its callback // function is invoked. // // SEE ALSO: flexframesync_reconfig_example.c // framesync64_example.c // #include #include #include #include #include #include #include #include "liquid.h" void usage() { printf("flexframesync_example [options]\n"); printf(" u/h : print usage\n"); printf(" s : signal-to-noise ratio [dB], default: 20\n"); printf(" F : carrier frequency offset, default: 0.01\n"); printf(" n : payload length [bytes], default: 480\n"); printf(" m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): h74 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); printf(" d : enable debugging\n"); } // flexframesync callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata); int main(int argc, char *argv[]) { //srand( time(NULL) ); // options modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) unsigned int payload_len = 480; // payload length int debug_enabled = 0; // enable debugging? float noise_floor = -60.0f; // noise floor float SNRdB = 20.0f; // signal-to-noise ratio float dphi = 0.01f; // carrier frequency offset // get options int dopt; while((dopt = getopt(argc,argv,"uhs:F:n:m:v:c:k:d")) != EOF){ switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'n': payload_len = atol(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); break; case 'c': fec0 = liquid_getopt_str2fec(optarg); break; case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 'd': debug_enabled = 1; break; default: exit(-1); } } // derived values unsigned int i; float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev. float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain // create flexframegen object flexframegenprops_s fgprops; flexframegenprops_init_default(&fgprops); fgprops.mod_scheme = ms; fgprops.check = check; fgprops.fec0 = fec0; fgprops.fec1 = fec1; flexframegen fg = flexframegen_create(&fgprops); // create flexframesync object flexframesync fs = flexframesync_create(callback,NULL); if (debug_enabled) flexframesync_debug_enable(fs); // assemble the frame (NULL pointers for default values) flexframegen_assemble(fg, NULL, NULL, payload_len); flexframegen_print(fg); // generate the frame in blocks unsigned int buf_len = 256; float complex x[buf_len]; float complex y[buf_len]; int frame_complete = 0; float phi = 0.0f; while (!frame_complete) { // write samples to buffer frame_complete = flexframegen_write_samples(fg, x, buf_len); // add noise and push through synchronizer for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "flexframesync_reconfig_example.m" void usage() { printf("flexframesync_example [options]\n"); printf(" u/h : print usage\n"); printf(" s : signal-to-noise ratio [dB], default: 30\n"); printf(" n : number of frames, default: 3\n"); } int main(int argc, char *argv[]) { srand( time(NULL) ); // define parameters float SNRdB = 30.0f; float noise_floor = -30.0f; unsigned int num_frames = 3; // get options int dopt; while((dopt = getopt(argc,argv,"uhvqs:f:m:p:n:")) != EOF){ switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'n': num_frames = atoi(optarg); break; default: exit(1); } } // create flexframegen object flexframegenprops_s fgprops; flexframegenprops_init_default(&fgprops); flexframegen fg = flexframegen_create(NULL); // frame data unsigned char header[14]; unsigned char * payload = NULL; // create flexframesync object with default properties flexframesync fs = flexframesync_create(NULL,NULL); // channel float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev. float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain unsigned int i; // initialize header, payload for (i=0; i<14; i++) header[i] = i; // frame buffers, properties unsigned int buf_len = 256; float complex buf[buf_len]; unsigned int j; for (j=0; j #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "framesync64_example.m" // static callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata) { printf("*** callback invoked ***\n"); framesyncstats_print(&_stats); return 0; } int main(int argc, char*argv[]) { // create frame generator, synchronizer objects framegen64 fg = framegen64_create(); framesync64 fs = framesync64_create(callback,NULL); // create buffer for the frame samples unsigned int frame_len = LIQUID_FRAME64_LEN; // fixed frame length float complex frame[frame_len]; // generate the frame with random header and payload framegen64_execute(fg, NULL, NULL, frame); // add minor channel effects unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "framesync64_performance_example.m" // add noise to channel void frame64_add_noise(float complex * _buf, float _SNRdB) { float nstd = powf(10.0f, -_SNRdB/20.0f); nstd *= M_SQRT2; // scale noise to account for signal being over-sampled by 2 unsigned int i; for (i=0; i= min_errors) break; if (num_trials >= max_trials) break; } // print results framedatastats_s stats = framesync64_get_framedatastats(fs); float per = (float)(num_trials - stats.num_payloads_valid)/(float)num_trials; if (per >= per_target) { per_0 = per; snr_0 = SNRdB; } else if (per_1 < 0.0f ) { per_1 = per; snr_1 = SNRdB; } printf(" %8.3f %6u %6u %6u %12.4e\n", SNRdB,stats.num_frames_detected,stats.num_payloads_valid,num_trials,per); fprintf(fid,"SNR(end+1)=%g; pdetect(end+1)=%g; pvalid(end+1)=%g;\n", SNRdB, (float)stats.num_frames_detected / (float)num_trials, (float)stats.num_payloads_valid / (float)num_trials); if (num_errors < min_errors) break; SNRdB += 0.5f; } float m = (logf(per_1) - logf(per_0)) / (snr_1 - snr_0); float snr_target = snr_0 + (logf(per_target) - logf(per_0)) / m; printf("per:{%12.4e,%12.4e}, snr:{%5.2f,%5.2f} => %.3f dB for PER %12.4e\n", per_0, per_1, snr_0, snr_1, snr_target, per_target); fprintf(fid,"figure;\n"); fprintf(fid,"hold on;\n"); fprintf(fid," semilogy(SNR, 1-pdetect+eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid," semilogy(SNR, 1-pvalid +eps,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"xlabel('SNR [dB]');\n"); fprintf(fid,"ylabel('Prob. of Error');\n"); fprintf(fid,"legend('detect','decoding','location','northeast');\n"); fprintf(fid,"axis([-6 10 1e-3 1]);\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); // clean up allocated objects framegen64_destroy(fg); framesync64_destroy(fs); return 0; } liquid-dsp-1.7.0/examples/freqmodem_example.c000066400000000000000000000110561474751757600213000ustar00rootroot00000000000000// Tests simple frequency modulation/demodulation #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "freqmodem_example.m" // print usage/help message void usage() { printf("freqmodem_example [options]\n"); printf(" h : print usage\n"); printf(" n : number of samples, default: 1024\n"); printf(" S : SNR [dB], default: 30\n"); printf(" k : FM modulation factor, default: 0.1\n"); } int main(int argc, char*argv[]) { // options float kf = 0.1f; // modulation factor unsigned int num_samples = 1024; // number of samples float SNRdB = 30.0f; // signal-to-noise ratio [dB] int dopt; while ((dopt = getopt(argc,argv,"hn:S:k:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'S': SNRdB = atof(optarg); break; case 'k': kf = atof(optarg); break; default: exit(1); } } // create mod/demod objects freqmod mod = freqmod_create(kf); // modulator freqdem dem = freqdem_create(kf); // demodulator freqmod_print(mod); unsigned int i; float m[num_samples]; // message signal float complex r[num_samples]; // received signal (complex baseband) float y[num_samples]; // demodulator output // generate message signal (sum of sines) for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "fskframesync_example.m" void usage() { printf("fskframesync_example [options]\n"); printf(" h : print usage\n"); printf(" d : enable debugging\n"); printf(" S : signal-to-noise ratio [dB], default: 20\n"); printf(" F : carrier frequency offset, default: 0\n"); printf(" P : carrier phase offset, default: 0\n"); printf(" T : fractional sample timing offset, default: 0.01\n"); } // static callback function static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata); // global arrays unsigned char header[8]; unsigned char payload[200]; int main(int argc, char*argv[]) { srand( time(NULL) ); // options float SNRdB = 20.0f; // signal-to-noise ratio float noise_floor = -20.0f; // noise floor float dphi = 0.01f; // carrier frequency offset float theta = 0.0f; // carrier phase offset float dt = -0.2f; // fractional sample timing offset crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) unsigned int payload_len = 200; // payload length int debug_enabled = 0; // get options int dopt; while((dopt = getopt(argc,argv,"hdS:F:P:T:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'd': debug_enabled = 1; break; case 'S': SNRdB = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'P': theta = atof(optarg); break; case 'T': dt = atof(optarg); break; default: exit(-1); } } printf("channel offsets: dt=%.3f, dphi=%.3f, theta=%.3f\n", dt, dphi, theta); // derived values float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev. float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain // create frame generator fskframegen fg = fskframegen_create(); fskframegen_print(fg); // create frame synchronizer using default properties fskframesync fs = fskframesync_create(callback,NULL); fskframesync_print(fs); if (debug_enabled) fskframesync_debug_enable(fs); // data payload unsigned int i; // initialize header and payload data for (i=0; i<8; i++) header[i] = i; for (i=0; i<200; i++) payload[i] = rand() & 0xff; // allocate memory for the frame samples unsigned int buf_len = 64; float complex buf_tx[buf_len]; // receive buffer float complex buf_rx[buf_len]; // transmit buffer // assemble the frame fskframegen_assemble(fg, header, payload, payload_len, check, fec0, fec1); // spectral periodogram unsigned int nfft = 4200; spgramcf periodogram = spgramcf_create_default(nfft); // write frame in blocks int frame_complete = 0; while (!frame_complete) { frame_complete = fskframegen_write_samples(fg, buf_tx, buf_len); // add noise, channel gain for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "fskmodem_example.m" // print usage/help message void usage() { printf("fskmodem_example -- frequency-shift keying example\n"); printf("options:\n"); printf(" h : print help\n"); printf(" m : bits/symbol, default: 3\n"); printf(" k : samples/symbol, default: 2*2^m\n"); printf(" b : signal bandwidth default: 0.2\n"); printf(" n : number of data symbols, default: 80\n"); printf(" s : SNR [dB], default: 40\n"); } int main(int argc, char*argv[]) { // options unsigned int m = 3; // number of bits/symbol unsigned int k = 0; // filter samples/symbol unsigned int num_symbols = 8000; // number of data symbols float SNRdB = 40.0f; // signal-to-noise ratio [dB] float bandwidth = 0.20; // frequency spacing unsigned int nfft = 1200; // FFT size for compute spectrum int dopt; while ((dopt = getopt(argc,argv,"hm:k:b:n:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; unsigned int j; // derived values if (k == 0) k = 2 << m; // set samples per symbol if not otherwise specified unsigned int M = 1 << m; float nstd = powf(10.0f, -SNRdB/20.0f); // validate input if (k < M) { fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M); exit(1); } else if (k > 2048) { fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__); exit(1); } else if (M > 1024) { fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M); exit(1); } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) { fprintf(stderr,"errors: %s, bandwidth must be in (0,0.5)\n", __FILE__); exit(1); } // create modulator/demodulator pair fskmod mod = fskmod_create(m,k,bandwidth); fskdem dem = fskdem_create(m,k,bandwidth); fskdem_print(dem); // float complex buf_tx[k]; // transmit buffer float complex buf_rx[k]; // transmit buffer // spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); // modulate, demodulate, count errors unsigned int num_symbol_errors = 0; for (i=0; i #include #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("fskmodem_waterfall_example -- frequency-shift keying waterfall example\n"); printf("options:\n"); printf(" -h : print help\n"); printf(" -m : bits/symbol, default: 2\n"); printf(" -b : signal bandwidth default: 0.2\n"); printf(" -n : number of data symbols, default: 80\n"); printf(" -s : SNR [dB], default: 40\n"); } int main(int argc, char*argv[]) { // options unsigned int m = 2; // number of bits/symbol unsigned int num_symbols = 400; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.10; // frequency spacing int dopt; while ((dopt = getopt(argc,argv,"hm:b:n:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; unsigned int j; // derived values unsigned int M = 1 << m; // constellation size unsigned int k = 500 * M; // samples per symbol (highly over-sampled) float nstd = powf(10.0f, -SNRdB/20.0f); // noise std. dev. // validate input if (k < M) { fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M); exit(1); } else if (k > 2048) { fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__); exit(1); } else if (M > 1024) { fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M); exit(1); } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) { fprintf(stderr,"errors: %s, bandwidth must be in (0,0.5)\n", __FILE__); exit(1); } // create spectral waterfall object unsigned int nfft = 1 << liquid_nextpow2(k); int wtype = LIQUID_WINDOW_HAMMING; unsigned int wlen = nfft/2; unsigned int delay = nfft/2; unsigned int time = 512; spwaterfallcf periodogram = spwaterfallcf_create(nfft,wtype,wlen,delay,time); spwaterfallcf_print(periodogram); // create modulator/demodulator pair fskmod mod = fskmod_create(m,k,bandwidth); float complex buf_tx[k]; // transmit buffer float complex buf_rx[k]; // transmit buffer // modulate, demodulate, count errors for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "gasearch_example.m" // peak callback function; value nearest {p, p, p, ...} where p = 1/sqrt(2) float peak_callback(void * _userdata, chromosome _c) { unsigned int i, n = chromosome_get_num_traits(_c); float u_global = 1.0f; float sig = 0.2f; float p = M_SQRT1_2; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gasearch_knapsack_example.m" // print usage/help message void usage() { printf("Usage: gasearch_knapsack_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : number of items available, default: 1000\n"); printf(" i : number of iterations (generations) to run, default: 2000\n"); printf(" c : knapsack capacity (maximum weight), default: 20\n"); printf(" p : ga population size, default: 100\n"); printf(" m : ga mutation rate, default: 0.4\n"); } // knapsack object structure definition struct knapsack_s { unsigned int num_items; // total number of items available float * weight; // weight of each item float * value; // value of each item float capacity; // maximum weight allowable }; // print knapsack object // _bag : knapsack object pointer // _c : test chromosome void knapsack_print(struct knapsack_s * _bag, chromosome _c); // utility callback function // _userdata : knapsack object pointer // _c : test chromosome float knapsack_utility(void * _userdata, chromosome _c); int main(int argc, char*argv[]) { unsigned int num_items = 1000; // number of items available unsigned int num_iterations = 2000; // number of iterations to run float capacity = 20.0f; // total capacity of the knapsack unsigned int population_size = 100; // number of chromosomes in the population float mutation_rate = 0.40f; // mutation rate of the GA int dopt; while((dopt = getopt(argc,argv,"uhn:i:c:p:m:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': num_items = atoi(optarg); break; case 'i': num_iterations = atoi(optarg); break; case 'c': capacity = atof(optarg); break; case 'p': population_size = atoi(optarg); break; case 'm': mutation_rate = atof(optarg); break; default: exit(1); } } // validate input if (num_items == 0) { fprintf(stderr,"error: %s, knapsack must have at least 1 item\n", argv[0]); exit(1); } else if (capacity <= 0.0f) { fprintf(stderr,"error: %s, knapsack capacity must be greater than zero\n", argv[0]); exit(1); } else if (population_size <= 0) { fprintf(stderr,"error: %s, ga population size must be greater than zero\n", argv[0]); exit(1); } else if (mutation_rate < 0.0f || mutation_rate > 1.0f) { fprintf(stderr,"error: %s, ga mutation rate must be in [0,1]\n", argv[0]); exit(1); } unsigned int i; // create knapsack/items (random weight, value) struct knapsack_s bag; bag.num_items = num_items; bag.capacity = capacity; bag.weight = (float*) malloc( bag.num_items*sizeof(float) ); bag.value = (float*) malloc( bag.num_items*sizeof(float) ); for (i=0; inum_items, _bag->capacity); for (i=0; i<_bag->num_items; i++) { printf(" %3u : %6.4f @ $%6.4f", i, _bag->weight[i], _bag->value[i]); unsigned int n = chromosome_value(_s, i); if (n != 0) printf(" *\n"); else printf("\n"); } } // utility callback function // _userdata : knapsack object pointer // _c : test chromosome float knapsack_utility(void * _userdata, chromosome _c) { struct knapsack_s * _bag = (struct knapsack_s *) _userdata; // chromosome represents number of each item in knapsack float total_value = 0; float total_weight = 0; unsigned int i; for (i=0; i<_bag->num_items; i++) { if ( chromosome_value(_c,i) == 1 ) { // include this item into knapsack total_value += _bag->value[i]; total_weight += _bag->weight[i]; } } // check for invalid solution, returning distance metric if (total_weight > _bag->capacity) return _bag->capacity - total_weight; // return total value of knapsack return total_value; } liquid-dsp-1.7.0/examples/gmsk_eqlms_example.c000066400000000000000000000066641474751757600214740ustar00rootroot00000000000000// test GMSK equalization #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmsk_eqlms_example.m" int main(int argc, char*argv[]) { // options unsigned int k = 4; // filter samples/symbol float beta = 0.3f; // bandwidth-time product unsigned int p = 3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.08f; // learning rate unsigned int num_symbols = 2400;// number of symbols to simulate unsigned int nfft = 1200;// number of symbols to simulate // create modulator gmskmod mod = gmskmod_create(k, 3, beta); // create equalizer eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_GMSKRX, k, p, beta, 0.0f); eqlms_cccf_set_bw(eq, mu); // create spectral periodogram spgramcf q = spgramcf_create_default(nfft); // write results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"syms = zeros(1,num_symbols);\n"); fprintf(fid,"psd = zeros(1,nfft);\n"); float complex buf[k]; unsigned int i; for (i=0; i 0 ? 1 : -1) * M_SQRT1_2 + (cimagf(d_hat) > 0 ? 1 : -1) * M_SQRT1_2 * _Complex_I; eqlms_cccf_step(eq, d_prime, d_hat); } // get equalizer weights unsigned int hp_len = 2*k*p+1; // equalizer filter length float complex hp[hp_len]; // equalizer filter coefficients eqlms_cccf_copy_coefficients(eq, hp); fprintf(fid,"hp = zeros(1,%u);\n", hp_len); for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmsk_tracking_example.m" int main(int argc, char*argv[]) { // options unsigned int k = 4; // filter samples/symbol float beta = 0.3f; // bandwidth-time product // create resampler object to facilitate sample rate offset unsigned int P = 203; // output rate (interpolation factor) unsigned int Q = 200; // input rate (decimation factor) rresamp_crcf resamp = rresamp_crcf_create_kaiser(k*P,k*Q,12,0.5,60.0f); // create modulator gmskmod mod = gmskmod_create(k, 3, beta); gmskmod_print(mod); // frequency demodulator freqdem dem = freqdem_create(0.01*k); // create matched filter firfilt_rrrf mf = firfilt_rrrf_create_rnyquist(LIQUID_FIRFILT_GMSKRX, k, 8, beta, 0); firfilt_rrrf_set_scale(mf,1./(float)k); // compensate for 'k' samples/symbol // create symbol synchronizer to operate after matched filter // NOTE: can alternatively skip the matched filter and apply with the symsync object symsync_rrrf sync = symsync_rrrf_create_kaiser(k, 4, 0/*ignored*/, 64); symsync_rrrf_set_lf_bw(sync,0.02); // set loop filter bandwidth symsync_rrrf_set_output_rate(sync,2); // set output rate as 2 samples/symbol // write results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"k = %u; v = [];\n", k); // run in blocks float complex buf_0[k*Q]; // original GMSK input float complex buf_1[k*P]; // resample output at a rate P/Q float buf_2[k*P]; // freqdem output & matched filter output float buf_3[k*P]; // symbol timing recovery output unsigned int i, j; for (i=0; i<25; i++) { // generate input GMSK signal for (j=0; j #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskframesync_example.m" // callback function int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata) { printf("***** gmskframesync callback invoked *****\n"); return 0; } int main(int argc, char*argv[]) { unsigned int k = 2; // samples/symbol unsigned int m = 3; // filter delay (symbols) float BT = 0.5f; // filter bandwidth-time product unsigned int payload_len = 40; // length of payload (bytes) crc_scheme check = LIQUID_CRC_32; fec_scheme fec0 = LIQUID_FEC_HAMMING128; fec_scheme fec1 = LIQUID_FEC_NONE; unsigned int i; // allocate memory for payload and initialize unsigned char header[8] = {0,1,2,3,4,5,6,7}; unsigned char payload[payload_len]; memset(payload, 0x00, payload_len); // create frame generator and assemble gmskframegen fg = gmskframegen_create_set(k, m, BT); gmskframegen_assemble(fg, header, payload, payload_len, check, fec0, fec1); // create frame synchronizer gmskframesync fs = gmskframesync_create_set(k, m, BT, callback, NULL); // allocate buffer for storing entire frame unsigned int num_samples = gmskframegen_getframelen(fg) + 800; float complex buf[num_samples]; memset(buf, 0x00, num_samples*sizeof(float complex)); // generate frame in one shot with sample offset gmskframegen_write(fg, buf+250, num_samples-250); // add channel gain and noise for (i=0; i #include #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("modem_example [options]\n"); printf(" -h : print help\n"); } int main(int argc, char*argv[]) { // simulation parameters unsigned int k = 4; // filter samples/symbol unsigned int m = 3; // filter delay (symbols) float BT = 0.3f; // bandwidth-time product float SNRdB_min = -5.0f; // starting SNR value float SNRdB_max = 15.0f; // maximum SNR value float SNRdB_step = 1.0f; // step size unsigned int num_trials = 1e6; // number of symbols char filename[] = "gmskmodem_ber_example.m"; int dopt; while ((dopt = getopt(argc,argv,"h")) != EOF) { switch (dopt) { case 'h': usage(); return 0; default: exit(1); } } // create modem objects gmskmod mod = gmskmod_create(k, m, BT); // modulator gmskdem dem = gmskdem_create(k, m, BT); // demodulator // derived values and buffers unsigned int delay = 2*m; unsigned int symbol_buffer[delay]; // delay between tx/rx unsigned int symbol_index = 0; float complex buf[k]; // sample buffer unsigned int i, j, sym_in, sym_out, sym_buf; // iterate through SNR values printf("# GMSK, k=%u, m=%u, BT=%.3f\n", k, m, BT); printf("# %8s %8s %8s %12s %12s\n", "SNR [dB]", "errors", "trials", "BER", "theory"); float SNRdB = SNRdB_min; // set SNR value FILE * fid = fopen(filename,"w"); fprintf(fid,"%% %s : auto-generated file\n", filename); fprintf(fid,"clear all; close all; SNRdB=[]; BER=[]; theory=[];\n"); while (1) { // compute noise standard deviation, compensating for over-sampling float nstd = powf(10.0f, -SNRdB/20.0f) * sqrtf((float)k); // reset modem objects (only necessary for differential schemes) gmskmod_reset(mod); gmskdem_reset(dem); // run trials unsigned int num_bit_errors = 0; for (i=0; i delay) num_bit_errors += count_bit_errors(sym_buf, sym_out); } // compute results and print formatted results to screen unsigned int num_bit_trials = m * num_trials; float ber = (float)num_bit_errors / (float)(num_bit_trials); float gamma = powf(10.0f, SNRdB/10.0f); float theory = liquid_Qf(sqrtf(2*gamma)); printf(" %8.2f %8u %8u %12.4e %12.4e\n", SNRdB, num_bit_errors, num_bit_trials, ber, theory); if (num_bit_errors > 0) { fprintf(fid,"SNRdB(end+1)=%12.3f; BER(end+1)=%12.4e; theory(end+1)=%12.4e;\n", SNRdB, ber, theory); } // stop iterating if SNR exceed maximum or no errors were detected SNRdB += SNRdB_step; if (SNRdB > SNRdB_max) break; } fprintf(fid,"figure; semilogy(SNRdB,BER,'-x',SNRdB,theory,'-x');grid on;\n"); fprintf(fid,"axis([-5 15 1e-6 1]);xlabel('SNR [dB]'); ylabel('BER'); legend('sim','theory');\n"); fclose(fid); printf("results written to %s\n", filename); // destroy modem objects and return gmskmod_destroy(mod); gmskdem_destroy(dem); return 0; } liquid-dsp-1.7.0/examples/gmskmodem_example.c000066400000000000000000000111711474751757600213020ustar00rootroot00000000000000// // gmskmodem_example.c // #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskmodem_example.m" // print usage/help message void usage() { printf("gmskmodem_example -- Gaussian minimum-shift keying modem example\n"); printf("options (default values in <>):\n"); printf(" u/h : print usage/help\n"); printf(" k : samples/symbol, default: 4\n"); printf(" m : filter delay [symbols], default: 3\n"); printf(" n : number of data symbols, default: 200\n"); printf(" b : bandwidth-time product, 0 <= b <= 1, default: 0.3\n"); printf(" s : SNR [dB], default: 30\n"); } int main(int argc, char*argv[]) { // options unsigned int k=4; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.3f; // bandwidth-time product unsigned int num_data_symbols=200; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] float phi = 0.0f; // carrier phase offset float dphi = 0.0f; // carrier frequency offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:s:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 'b': BT = atof(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } // validate input if (BT <= 0.0f || BT >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_data_symbols + 2*m; unsigned int num_samples = k*num_symbols; float nstd = powf(10.0f,-SNRdB/20.0f); // noise standard deviation // create modulator gmskmod mod = gmskmod_create(k, m, BT); gmskmod_print(mod); // create demodulator gmskdem demod = gmskdem_create(k, m, BT); gmskdem_set_eq_bw(demod, 0.01f); gmskdem_print(demod); unsigned int i; unsigned int s[num_symbols]; float complex x[num_samples]; float complex y[num_samples]; unsigned int sym_out[num_symbols]; // generate random data sequence for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "gradsearch_datafit_example.m" // gradient search data set struct gsdataset { float * x; float * y; unsigned int n; }; // gradient search curve-fit error float gserror(void * _dataset, float * _v, unsigned int _n); // parameterized function float gsfunc(float _x, float * _v) { float c0 = _v[0]; float c1 = _v[1]; float c2 = _v[2]; return c0 + sincf(c1*(_x-c2)); } int main() { // options unsigned int num_samples = 400; // number of samples float sig = 0.1f; // noise variance unsigned int num_iterations = 1000; // number of iterations to run float v[3] = {1, 1, 1}; unsigned int i; // range float xmin = 0.0f; float xmax = 6.0f; float dx = (xmax - xmin) / (num_samples-1); // generate data set float x[num_samples]; float y[num_samples]; for (i=0; in; i++) { // compute function estimate float y_hat = gsfunc(p->x[i], _v); // compute error float e = p->y[i] - y_hat; // accumulate RMS error rmse += e*e; } // normalize error and return rmse = sqrtf(rmse / (float)(p->n)); return rmse; } liquid-dsp-1.7.0/examples/gradsearch_example.c000066400000000000000000000064141474751757600214260ustar00rootroot00000000000000// // gradsearch_example.c // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gradsearch_example.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" h : print help\n"); printf(" n : number of parameters, default: 6\n"); printf(" t : number of iterations, default: 2000\n"); printf(" u : utility function: {rosenbrock, invgauss, multimodal, spiral}\n"); } int main(int argc, char*argv[]) { unsigned int num_parameters = 6; // dimensionality of search (minimum 2) unsigned int num_iterations = 2000; // number of iterations to run utility_function func = liquid_rosenbrock; int dopt; while ((dopt = getopt(argc,argv,"hn:t:u:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_parameters = atoi(optarg); break; case 't': num_iterations = atoi(optarg); break; case 'u': if (strcmp(optarg,"rosenbrock")==0) func = liquid_rosenbrock; else if (strcmp(optarg,"invgauss")==0) func = liquid_invgauss; else if (strcmp(optarg,"multimodal")==0) func = liquid_multimodal; else if (strcmp(optarg,"spiral")==0) func = liquid_spiral; else { fprintf(stderr,"error: %s, unknown/unsupported utility '%s'\n", argv[0], optarg); exit(1); } break; default: exit(1); } } float optimum_vect[num_parameters]; unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdecim_crcf_example.m" // print usage/help message void usage() { printf("iirdecim_crcf_example:\n"); printf(" u/h : print usage/help\n"); printf(" M : decimation factor, M > 1, default: 4\n"); printf(" n : number of input samples, default: 400\n"); } int main(int argc, char*argv[]) { // options unsigned int M=4; // decimation rate unsigned int num_samples=400; // number of input samples int dopt; while ((dopt = getopt(argc,argv,"uhM:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'M': M = atoi(optarg); break; case 'n': num_samples = atoi(optarg); break; default: exit(1); } } // validate options if (M < 2) { fprintf(stderr,"error: %s, decim factor must be greater than 1\n", argv[0]); exit(1); } else if (num_samples < 1) { fprintf(stderr,"error: %s, must have at least one sample\n", argv[0]); usage(); return 1; } // ensure number of samples is divisible by M num_samples += (num_samples % M); // create decimator from prototype unsigned int order = 8; iirdecim_crcf q = iirdecim_crcf_create_default(M,order); // compute group delay float delay = iirdecim_crcf_groupdelay(q,0.0f); // generate input signal and decimate float complex x[num_samples]; // input samples float complex y[num_samples/M]; // output samples unsigned int i; unsigned int w_len = num_samples > 4*delay ? num_samples - 4*delay : num_samples; for (i=0; i= M*m) && ((i%M)==0)) printf(" **\n"); else printf("\n"); } #endif // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"M = %u;\n", M); fprintf(fid,"delay = %f;\n", delay); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples/M);\n"); for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdes_analog_example.m" // print usage/help message void usage() { printf("iirdes_analog_example -- infinite impulse response filter design\n"); printf("options (default values in []):\n"); printf(" u/h : print usage/help\n"); printf(" t : filter type: [butter], cheby1, cheby2, ellip, bessel\n"); // printf(" b : filter transformation: [LP], HP, BP, BS\n"); printf(" n : filter order, n > 0 [5]\n"); printf(" r : passband ripple in dB (cheby1, ellip), r > 0 [3.0]\n"); printf(" s : stopband attenuation in dB (cheby2, ellip), s > 0 [60.0]\n"); printf(" f : angular passband cut-off frequency, f > 0 [1.0]\n"); // printf(" c : center frequency (BP, BS cases), 0 < c < 0.5 [0.25]\n"); // printf(" o : format [sos], tf\n"); // printf(" sos : second-order sections form\n"); // printf(" tf : regular transfer function form (potentially\n"); // printf(" unstable for large orders\n"); } int main(int argc, char*argv[]) { // options unsigned int order=3; // filter order float wc=1.0f; // angular cutoff frequency float Ap=3.0f; // pass-band Ap float As=60.0f; // stop-band attenuation // filter type liquid_iirdes_filtertype ftype = LIQUID_IIRDES_BUTTER; int dopt; while ((dopt = getopt(argc,argv,"uht:n:r:s:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"butter")==0) { ftype = LIQUID_IIRDES_BUTTER; } else if (strcmp(optarg,"cheby1")==0) { ftype = LIQUID_IIRDES_CHEBY1; } else if (strcmp(optarg,"cheby2")==0) { ftype = LIQUID_IIRDES_CHEBY2; } else if (strcmp(optarg,"ellip")==0) { ftype = LIQUID_IIRDES_ELLIP; } else if (strcmp(optarg,"bessel")==0) { ftype = LIQUID_IIRDES_BESSEL; } else { fprintf(stderr,"error: %s, unknown filter type \"%s\"\n", argv[0], optarg); usage(); exit(1); } break; case 'n': order = atoi(optarg); break; case 'r': Ap = atof(optarg); break; case 's': As = atof(optarg); break; case 'f': wc = atof(optarg); break; default: exit(1); } } // validate input if (wc <= 0) { fprintf(stderr,"error: %s, cutoff frequency out of range\n", argv[0]); usage(); exit(1); } else if (Ap <= 0) { fprintf(stderr,"error: %s, pass-band ripple out of range\n", argv[0]); usage(); exit(1); } else if (As <= 0) { fprintf(stderr,"error: %s, stop-band ripple out of range\n", argv[0]); usage(); exit(1); } // number of analog poles/zeros unsigned int npa = order; unsigned int nza = 0; // complex analog zeros, poles, gain float complex za[order]; float complex pa[order]; float complex ka; unsigned int i; unsigned int r = order % 2; unsigned int L = (order-r)/2; float Gp, Gs; float ep = sqrtf( powf(10.0f, Ap / 10.0f) - 1.0f ); float es = powf(10.0f, -As / 20.0f); switch (ftype) { case LIQUID_IIRDES_BUTTER: printf("Butterworth filter design:\n"); nza = 0; butter_azpkf(order,za,pa,&ka); break; case LIQUID_IIRDES_CHEBY1: printf("Cheby-I filter design:\n"); nza = 0; cheby1_azpkf(order,ep,za,pa,&ka); break; case LIQUID_IIRDES_CHEBY2: printf("Cheby-II filter design:\n"); nza = 2*L; float epsilon = powf(10.0f, -As/20.0f); cheby2_azpkf(order,epsilon,za,pa,&ka); break; case LIQUID_IIRDES_ELLIP: printf("elliptic filter design:\n"); nza = 2*L; Gp = powf(10.0f, -Ap / 20.0f); Gs = powf(10.0f, -As / 20.0f); printf(" Gp = %12.8f\n", Gp); printf(" Gs = %12.8f\n", Gs); // epsilon values ep = sqrtf(1.0f/(Gp*Gp) - 1.0f); es = sqrtf(1.0f/(Gs*Gs) - 1.0f); ellip_azpkf(order,ep,es,za,pa,&ka); break; case LIQUID_IIRDES_BESSEL: printf("Bessel filter design:\n"); bessel_azpkf(order,za,pa,&ka); nza = 0; break; default: fprintf(stderr,"error: %s: unknown filter type\n", argv[0]); exit(1); } // transform zeros, poles, gain for (i=0; i 0,\n"); fprintf(fid," hold on; plot(real(za),imag(za),'ob'); hold off;\n"); fprintf(fid," legend('(\\omega_c)','poles','zeros',0);\n"); fprintf(fid,"else,\n"); fprintf(fid," legend('(\\omega_c)','poles',0);\n"); fprintf(fid,"end;\n"); fprintf(fid," axis([-1 1 -1 1]*1.2*max([wc abs(pa) abs(za)]));\n"); //fprintf(fid," real(za),imag(za),'x');\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('real');\n"); fprintf(fid,"ylabel('imag');\n"); fprintf(fid,"\n"); // plot group delay fprintf(fid,"figure;\n"); fprintf(fid,"gd = gradient(unwrap(arg(h)))./gradient(w);\n"); fprintf(fid,"semilogx(w,gd);\n"); fprintf(fid,"xlabel('Angular frequency, \\omega [rad/s]');\n"); fprintf(fid,"ylabel('group delay [s]');\n"); fprintf(fid,"gd_min = min(gd); if gd_min < 0, gd_min=0; end;\n"); fprintf(fid,"axis([wc/100 wc*100 gd_min 1.1*max(gd)]);\n"); fprintf(fid,"grid on;\n"); // plot magnitude response fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," semilogx(w,H,'-'); grid on;\n"); fprintf(fid," axis([wc/100 wc*100 -5 1]);\n"); fprintf(fid," xlabel('Angular frequency, \\omega [rad/s]');\n"); fprintf(fid," ylabel('PSD [dB]');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," semilogx(w,H,'-'); grid on;\n"); fprintf(fid," axis([wc/100 wc*100 -100 10]);\n"); fprintf(fid," xlabel('Angular frequency, \\omega [rad/s]');\n"); fprintf(fid," ylabel('PSD [dB]');\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/iirdes_example.c000066400000000000000000000225771474751757600206120ustar00rootroot00000000000000// // iirdes_example.c // // Tests infinite impulse response (IIR) digital filter design. // SEE ALSO: iirdes_analog_example.c // iir_filter_crcf_example.c // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdes_example.m" // print usage/help message void usage() { printf("iirdes_example -- infinite impulse response filter design\n"); printf("options (default values in []):\n"); printf(" u/h : print usage/help\n"); printf(" t : filter type: [butter], cheby1, cheby2, ellip, bessel\n"); printf(" b : filter transformation: [LP], HP, BP, BS\n"); printf(" n : filter order, n > 0 [5]\n"); printf(" r : passband ripple in dB (cheby1, ellip), r > 0 [1.0]\n"); printf(" s : stopband attenuation in dB (cheby2, ellip), s > 0 [60.0]\n"); printf(" f : passband cut-off, 0 < f < 0.5 [0.2]\n"); printf(" c : center frequency (BP, BS cases), 0 < c < 0.5 [0.25]\n"); printf(" o : format [sos], tf\n"); printf(" sos : second-order sections form\n"); printf(" tf : regular transfer function form (potentially\n"); printf(" unstable for large orders\n"); } int main(int argc, char*argv[]) { // options unsigned int order=5; // filter order float fc = 0.20f; // cutoff frequency (low-pass prototype) float f0 = 0.25f; // center frequency (band-pass, band-stop) float As = 60.0f; // stopband attenuation [dB] float Ap = 1.0f; // passband ripple [dB] // filter type liquid_iirdes_filtertype ftype = LIQUID_IIRDES_BUTTER; // band type liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; // output format: second-order sections or transfer function liquid_iirdes_format format = LIQUID_IIRDES_SOS; int dopt; while ((dopt = getopt(argc,argv,"uht:b:n:r:s:f:c:o:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"butter")==0) { ftype = LIQUID_IIRDES_BUTTER; } else if (strcmp(optarg,"cheby1")==0) { ftype = LIQUID_IIRDES_CHEBY1; } else if (strcmp(optarg,"cheby2")==0) { ftype = LIQUID_IIRDES_CHEBY2; } else if (strcmp(optarg,"ellip")==0) { ftype = LIQUID_IIRDES_ELLIP; } else if (strcmp(optarg,"bessel")==0) { ftype = LIQUID_IIRDES_BESSEL; } else { fprintf(stderr,"error: iirdes_example, unknown filter type \"%s\"\n", optarg); usage(); exit(1); } break; case 'b': if (strcmp(optarg,"LP")==0) { btype = LIQUID_IIRDES_LOWPASS; } else if (strcmp(optarg,"HP")==0) { btype = LIQUID_IIRDES_HIGHPASS; } else if (strcmp(optarg,"BP")==0) { btype = LIQUID_IIRDES_BANDPASS; } else if (strcmp(optarg,"BS")==0) { btype = LIQUID_IIRDES_BANDSTOP; } else { fprintf(stderr,"error: iirdes_example, unknown band type \"%s\"\n", optarg); usage(); exit(1); } break; case 'n': order = atoi(optarg); break; case 'r': Ap = atof(optarg); break; case 's': As = atof(optarg); break; case 'f': fc = atof(optarg); break; case 'c': f0 = atof(optarg); break; case 'o': if (strcmp(optarg,"sos")==0) { format = LIQUID_IIRDES_SOS; } else if (strcmp(optarg,"tf")==0) { format = LIQUID_IIRDES_TF; } else { fprintf(stderr,"error: iirdes_example, unknown output format \"%s\"\n", optarg); usage(); exit(1); } break; default: exit(1); } } // validate input if (fc <= 0 || fc >= 0.5) { fprintf(stderr,"error: %s, cutoff frequency out of range\n", argv[0]); usage(); exit(1); } else if (f0 < 0 || f0 > 0.5) { fprintf(stderr,"error: %s, center frequency out of range\n", argv[0]); usage(); exit(1); } else if (Ap <= 0) { fprintf(stderr,"error: %s, pass-band ripple out of range\n", argv[0]); usage(); exit(1); } else if (As <= 0) { fprintf(stderr,"error: %s, stop-band ripple out of range\n", argv[0]); usage(); exit(1); } // derived values : compute filter length unsigned int N = order; // effective order // filter order effectively doubles for band-pass, band-stop // filters due to doubling the number of poles and zeros as // a result of filter transformation if (btype == LIQUID_IIRDES_BANDPASS || btype == LIQUID_IIRDES_BANDSTOP) { N *= 2; } unsigned int r = N % 2; // odd/even order unsigned int L = (N-r)/2; // filter semi-length // allocate memory for filter coefficients unsigned int h_len = (format == LIQUID_IIRDES_SOS) ? 3*(L+r) : N+1; float b[h_len]; float a[h_len]; // design filter liquid_iirdes(ftype, btype, format, order, fc, f0, Ap, As, b, a); // open output file FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"n=%u;\n", order); fprintf(fid,"r=%u;\n", r); fprintf(fid,"L=%u;\n", L); fprintf(fid,"nfft=1024;\n"); unsigned int i; if (format == LIQUID_IIRDES_TF) { // print coefficients for (i=0; i<=N; i++) printf("a[%3u] = %12.8f;\n", i, a[i]); for (i=0; i<=N; i++) printf("b[%3u] = %12.8f;\n", i, b[i]); fprintf(fid,"a = zeros(1,n+1);\n"); fprintf(fid,"b = zeros(1,n+1);\n"); for (i=0; i<=N; i++) { fprintf(fid,"a(%3u) = %12.4e;\n", i+1, a[i]); fprintf(fid,"b(%3u) = %12.4e;\n", i+1, b[i]); } fprintf(fid,"\n"); fprintf(fid,"H = fft(b,nfft)./fft(a,nfft);\n"); fprintf(fid,"H = fftshift(H);\n"); fprintf(fid,"%% group delay\n"); fprintf(fid,"c = conv(b,fliplr(conj(a)));\n"); fprintf(fid,"cr = c.*[0:(length(c)-1)];\n"); fprintf(fid,"t0 = fftshift(fft(cr,nfft));\n"); fprintf(fid,"t1 = fftshift(fft(c, nfft));\n"); fprintf(fid,"polebins = find(abs(t1)<1e-6);\n"); fprintf(fid,"t0(polebins)=0;\n"); fprintf(fid,"t1(polebins)=1;\n"); fprintf(fid,"gd = real(t0./t1) - length(a) + 1;\n"); } else { float * B = b; float * A = a; // print coefficients printf("B [%u x 3] :\n", L+r); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdes_pll_example.m" // print usage/help message void usage() { printf("iirdes_pll_example [options]\n"); printf(" u/h : print usage\n"); printf(" b : pll bandwidth, default: 0.01\n"); printf(" z : zeta (damping factor), default 0.70711\n"); printf(" K : loop filter gain, default: 1000\n"); printf(" n : number of samples, default: 512\n"); printf(" p : phase offset (radians), default: pi/4\n"); printf(" f : frequency offset (radians), default: 0.3\n"); } int main(int argc, char*argv[]) { srand( time(NULL) ); // options float phase_offset = M_PI / 4.0f; // phase offset float frequency_offset = 0.3f; // frequency offset float pll_bandwidth = 0.01f; // PLL bandwidth float zeta = 1/sqrtf(2.0f); // PLL damping factor float K = 1000.0f; // PLL loop gain unsigned int n=512; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhb:z:K:n:p:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': pll_bandwidth = atof(optarg); break; case 'z': zeta = atof(optarg); break; case 'K': K = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } unsigned int d=n/32; // print every "d" lines // validate input if (pll_bandwidth <= 0.0f) { fprintf(stderr,"error: bandwidth must be greater than 0\n"); exit(1); } else if (zeta <= 0.0f) { fprintf(stderr,"error: damping factor must be greater than 0\n"); exit(1); } else if (K <= 0.0f) { fprintf(stderr,"error: loop gain must be greater than 0\n"); exit(1); } // data arrays float complex x[n]; // input complex sinusoid float complex y[n]; // output complex sinusoid float phase_error[n]; // output phase error // generate PLL filter float b[3]; float a[3]; iirdes_pll_active_lag(pll_bandwidth, zeta, K, b, a); iirfilt_rrrf pll = iirfilt_rrrf_create(b,3,a,3); iirfilt_rrrf_print(pll); unsigned int i; float phi; for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirfilt_cccf_example.m" // print usage/help message void usage() { printf("iirfilt_cccf_example -- infinite impulse response filter example\n"); printf("options (default values in []):\n"); printf(" h : print help\n"); printf(" t : filter type: [butter], cheby1, cheby2, ellip, bessel\n"); printf(" b : filter transformation: [LP], HP, BP, BS\n"); printf(" n : filter order, n > 0 [5]\n"); printf(" r : passband ripple in dB (cheby1, ellip), r > 0 [1.0]\n"); printf(" s : stopband attenuation in dB (cheby2, ellip), s > 0 [40.0]\n"); printf(" f : passband cut-off, 0 < f < 0.5 [0.2]\n"); printf(" c : center frequency (BP, BS cases), 0 < c < 0.5 [0.25]\n"); printf(" o : format [sos], tf\n"); printf(" sos : second-order sections form\n"); printf(" tf : regular transfer function form (potentially\n"); printf(" unstable for large orders\n"); } int main(int argc, char*argv[]) { // options unsigned int order=4; // filter order float fc=0.1f; // cutoff frequency float f0=0.0f; // center frequency float Ap=1.0f; // pass-band ripple float As=40.0f; // stop-band attenuation unsigned int n=128; // number of samples liquid_iirdes_filtertype ftype = LIQUID_IIRDES_ELLIP; liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; liquid_iirdes_format format = LIQUID_IIRDES_SOS; int dopt; while ((dopt = getopt(argc,argv,"ht:b:n:r:s:f:c:o:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': if (strcmp(optarg,"butter")==0) ftype = LIQUID_IIRDES_BUTTER; else if (strcmp(optarg,"cheby1")==0) ftype = LIQUID_IIRDES_CHEBY1; else if (strcmp(optarg,"cheby2")==0) ftype = LIQUID_IIRDES_CHEBY2; else if (strcmp(optarg,"ellip") ==0) ftype = LIQUID_IIRDES_ELLIP; else if (strcmp(optarg,"bessel")==0) ftype = LIQUID_IIRDES_BESSEL; else { fprintf(stderr,"error: iirdes_example, unknown filter type '%s'\n", optarg); exit(1); } break; case 'b': if (strcmp(optarg,"LP")==0) btype = LIQUID_IIRDES_LOWPASS; else if (strcmp(optarg,"HP")==0) btype = LIQUID_IIRDES_HIGHPASS; else if (strcmp(optarg,"BP")==0) btype = LIQUID_IIRDES_BANDPASS; else if (strcmp(optarg,"BS")==0) btype = LIQUID_IIRDES_BANDSTOP; else { fprintf(stderr,"error: iirdes_example, unknown band type '%s'\n", optarg); exit(1); } break; case 'n': order = atoi(optarg); break; case 'r': Ap = atof(optarg); break; case 's': As = atof(optarg); break; case 'f': fc = atof(optarg); break; case 'c': f0 = atof(optarg); break; case 'o': if (strcmp(optarg,"sos")==0) format = LIQUID_IIRDES_SOS; else if (strcmp(optarg,"tf") ==0) format = LIQUID_IIRDES_TF; else { fprintf(stderr,"error: iirdes_example, unknown output format '%s'\n", optarg); exit(1); } break; default: exit(1); } } // design filter from prototype iirfilt_cccf q = iirfilt_cccf_create_prototype(ftype, btype, format, order, fc, f0, Ap, As); iirfilt_cccf_print(q); unsigned int i; // allocate memory for data arrays float complex x[n]; float complex y[n]; // generate input signal (noisy sine wave with decaying amplitude) unsigned int wlen = (3*n)/4; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirfilt_crcf_dcblocker_example.m" int main() { // options unsigned int num_samples = 1200; // number of samples float alpha = 0.10f; // filter cut-off // design filter from prototype iirfilt_crcf q = iirfilt_crcf_create_dc_blocker(alpha); iirfilt_crcf_print(q); // allocate memory for data arrays float complex x[num_samples]; // original input float complex y[num_samples]; // input with DC offset float complex z[num_samples]; // DC-blocked result // generate signals unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirfilt_crcf_example.m" int main() { // options unsigned int order = 4; // filter order float fc = 0.1f; // cutoff frequency float f0 = 0.0f; // center frequency float Ap = 1.0f; // pass-band ripple float As = 40.0f; // stop-band attenuation unsigned int n = 128; // number of samples liquid_iirdes_filtertype ftype = LIQUID_IIRDES_ELLIP; liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; liquid_iirdes_format format = LIQUID_IIRDES_SOS; // design filter from prototype iirfilt_crcf q = iirfilt_crcf_create_prototype( ftype, btype, format, order, fc, f0, Ap, As); iirfilt_crcf_print(q); unsigned int i; // allocate memory for data arrays float complex x[n]; float complex y[n]; // generate input signal (noisy sine wave with decaying amplitude) for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "iirfilt_rrrf_integrator_example.m" int main() { // options unsigned int num_samples = 1200; // number of samples // allocate memory for data arrays float buf_0[num_samples]; // filter input float buf_1[num_samples]; // filter output // generate input signal unsigned int i; for (i=0; i 200 && i < 800 ? 1 : 0) + 0.1*randnf(); // design filter from prototype iirfilt_rrrf q = iirfilt_rrrf_create_integrator(); iirfilt_rrrf_print(q); // run filter iirfilt_rrrf_execute_block(q, buf_0, num_samples, buf_1); // destroy filter object iirfilt_rrrf_destroy(q); // plot results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"\n"); fprintf(fid,"num_samples=%u;\n",num_samples); fprintf(fid,"x=zeros(1,num_samples);\n"); fprintf(fid,"y=zeros(1,num_samples);\n"); // save input, output arrays for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirhilb_example.m" int main() { int ftype = LIQUID_IIRDES_BUTTER; // filter prototype unsigned int n = 7; // Hilbert filter order float Ap = 0.1f; // pass-band ripple [dB] float As = 60.0f; // stop-band attenuation [dB] float fc = 0.123456; // signal center frequency unsigned int num_input_samples=180; // number of samples // derived values unsigned int num_total_samples = num_input_samples + 50; // allow for filter settling // create Hilbert transform objects iirhilbf qi = iirhilbf_create(ftype,n,Ap,As); // interpolator iirhilbf qd = iirhilbf_create(ftype,n,Ap,As); // decimator iirhilbf_print(qi); // data arrays float complex x[ num_total_samples]; // complex input float y[2*num_total_samples]; // real output float complex z[ num_total_samples]; // complex output // initialize input array unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirhilb_filter_example.m" int main() { unsigned int order = 7; // Hilbert filter order unsigned int n = 128; // number of input samples // derived values unsigned int num_samples = n + 50; // create Hilbert transform objects iirhilbf q0 = iirhilbf_create_default(order); iirhilbf q1 = iirhilbf_create_default(order); iirhilbf_print(q0); // data arrays float complex x[num_samples]; // complex input float y[num_samples]; // real output float complex z[num_samples]; // complex output // run transform unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirinterp_crcf_example.m" // print usage/help message void usage() { printf("iirinterp_crcf_example:\n"); printf(" h : print help\n"); printf(" k : samples/symbol (interp factor), k > 1, default: 4\n"); printf(" n : number of input samples, default: 64\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 4; // interpolation factor unsigned int num_samples = 64; // number of input samples int dopt; while ((dopt = getopt(argc,argv,"uhk:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'n': num_samples = atoi(optarg); break; default: exit(1); } } // validate options if (k < 2) { fprintf(stderr,"error: %s, interp factor must be greater than 1\n", argv[0]); exit(1); } else if (num_samples < 1) { fprintf(stderr,"error: %s, must have at least one data symbol\n", argv[0]); usage(); return 1; } // create interpolator from prototype unsigned int order = 8; iirinterp_crcf q = iirinterp_crcf_create_default(k,order); // derived values float delay = iirinterp_crcf_groupdelay(q,0.0f); // generate input signal and interpolate float complex x[ num_samples]; // input samples float complex y[k*num_samples]; // output samples unsigned int i; for (i=0; i #include // for rand() #include "liquid.h" int main() { // options unsigned int n=9; // message length // create the interleaver interleaver q = interleaver_create(n); interleaver_set_depth(q, 4); interleaver_print(q); // create arrays unsigned char x[n]; // original message data unsigned char y[n]; // interleaved data unsigned char z[n]; // de-interleaved data // generate random data sequence unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "interleaver_scatterplot_example.m" // print usage/help message void usage() { printf("interleaver_scatterplot_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : number of bytes, default: 8\n"); printf(" d : interleaver depth, default: 4\n"); } // find most significant bit in array (starting from left) unsigned int interleaver_find_bit(unsigned char * _x, unsigned int _n); int main(int argc, char*argv[]) { // options unsigned int n=8; // message length unsigned int depth = 4; int dopt; while ((dopt = getopt(argc,argv,"uhn:d:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; case 'd': depth = atoi(optarg); break; default: exit(1); } } // create the interleaver interleaver q = interleaver_create(n); interleaver_set_depth(q, depth); // create arrays unsigned char x[n]; // original message data unsigned char y[n]; // interleaved data unsigned int index[8*n]; unsigned int i; unsigned int j; unsigned int k=0; // initialize data memset(x, 0, n*sizeof(unsigned char)); for (i=0; i #include // for rand() #include "liquid.h" int main() { // options unsigned int n=9; // message length (bits) // create the interleaver interleaver q = interleaver_create(n); interleaver_print(q); // create arrays unsigned char msg_org[n]; // original message data (bytes) unsigned char msg_int[n]; // interleaved data (bytes) unsigned char msg_rec[8*n]; // interleaved data (soft bits) unsigned char msg_dec[8*n]; // de-interleaved data (soft bits) unsigned char msg_ppp[n]; // de-interleaved data (bytes) // generate random data sequence unsigned int i; for (i=0; i> 7) & 0x01 ) ? 255 : 0; msg_rec[8*i+1] = ( (msg_int[i] >> 6) & 0x01 ) ? 255 : 0; msg_rec[8*i+2] = ( (msg_int[i] >> 5) & 0x01 ) ? 255 : 0; msg_rec[8*i+3] = ( (msg_int[i] >> 4) & 0x01 ) ? 255 : 0; msg_rec[8*i+4] = ( (msg_int[i] >> 3) & 0x01 ) ? 255 : 0; msg_rec[8*i+5] = ( (msg_int[i] >> 2) & 0x01 ) ? 255 : 0; msg_rec[8*i+6] = ( (msg_int[i] >> 1) & 0x01 ) ? 255 : 0; msg_rec[8*i+7] = ( (msg_int[i] >> 0) & 0x01 ) ? 255 : 0; } // de-interleave the soft bits interleaver_decode_soft(q, msg_rec, msg_dec); // pack the bits for (i=0; i 127) ? 0x80 : 0; msg_ppp[i] |= (msg_dec[8*i+1] > 127) ? 0x40 : 0; msg_ppp[i] |= (msg_dec[8*i+2] > 127) ? 0x20 : 0; msg_ppp[i] |= (msg_dec[8*i+3] > 127) ? 0x10 : 0; msg_ppp[i] |= (msg_dec[8*i+4] > 127) ? 0x08 : 0; msg_ppp[i] |= (msg_dec[8*i+5] > 127) ? 0x04 : 0; msg_ppp[i] |= (msg_dec[8*i+6] > 127) ? 0x02 : 0; msg_ppp[i] |= (msg_dec[8*i+7] > 127) ? 0x01 : 0; } // compute errors and print results unsigned int num_errors=0; printf("%6s %6s %6s\n", "org", "int", "dec"); for (i=0; i 127) ? 0x80 : 0; byte_int |= (msg_rec[8*i+1] > 127) ? 0x40 : 0; byte_int |= (msg_rec[8*i+2] > 127) ? 0x20 : 0; byte_int |= (msg_rec[8*i+3] > 127) ? 0x10 : 0; byte_int |= (msg_rec[8*i+4] > 127) ? 0x08 : 0; byte_int |= (msg_rec[8*i+5] > 127) ? 0x04 : 0; byte_int |= (msg_rec[8*i+6] > 127) ? 0x02 : 0; byte_int |= (msg_rec[8*i+7] > 127) ? 0x01 : 0; printf("%6u %6u %6u\n", msg_org[i], byte_int, msg_ppp[i]); //printf("y[%u] = %u\n", i, (unsigned int) (y[i])); //printf("y[%u] = %#0x\n", i, (unsigned int) (y[i])); num_errors += (msg_org[i] == msg_ppp[i]) ? 0 : 1; } printf("errors: %u / %u\n", num_errors, n); // destroy the interleaver object interleaver_destroy(q); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/kaiser_window_example.c000066400000000000000000000032341474751757600221650ustar00rootroot00000000000000// // kaiser_window_example.c // // Kaiser-Bessel window example // #include #include "liquid.h" #define OUTPUT_FILENAME "kaiser_window_example.m" int main() { // options unsigned int n=51; // window length float beta = 10.0f; // Kaiser beta factor float w[n]; unsigned int i; for (i=0; i #include "liquid.h" #define OUTPUT_FILENAME "kbd_window_example.m" int main() { // options unsigned int n=64; // window length float beta = 20.0f; // Kaiser beta factor unsigned int i; float w[n]; liquid_kbd_window(n,beta,w); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n=%u;\n",n); for (i=0; i #include #include "liquid.h" int main() { // LIQUID_VALIDATE_LIBVERSION printf("liquid version : %s\n", liquid_version); printf("liquid libversion : %s\n", liquid_libversion()); printf("liquid libversion number : 0x%.6x\n", liquid_libversion_number()); return 0; } liquid-dsp-1.7.0/examples/lpc_example.c000066400000000000000000000105111474751757600200720ustar00rootroot00000000000000// // lpc_example.c // // This example demonstrates linear prediction in liquid. An input signal // is generated which exhibits a strong temporal correlation. The linear // predictor generates an approximating all-pole filter which minimizes // the squared error between the prediction and the actual output. // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "lpc_example.m" int main() { // options unsigned int n = 200; // input sequence length unsigned int p = 4; // prediction filter order // create low-pass filter object iirfilt_rrrf f = iirfilt_rrrf_create_lowpass(2, 0.05f); iirfilt_rrrf_print(f); unsigned int i; // allocate memory for data arrays float y[n]; // input signal (filtered noise) float a_hat[p+1]; // lpc output float g_hat[p+1]; // lpc output // generate input signal (filtered noise) for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "matched_filter_example.m" // print usage/help message void usage() { printf("matched_filter_example options:\n"); printf(" u/h : print usage/help\n"); printf(" t : filter type: [rrcos], rkaiser, arkaiser, hm3, gmsk, fexp, fsech, farcsech\n"); printf(" k : filter samples/symbol, k >= 2, default: 2\n"); printf(" m : filter delay (symbols), m >= 1, default: 3\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.5\n"); printf(" n : number of symbols, default: 16\n"); } int main(int argc, char*argv[]) { // options unsigned int k=2; // samples/symbol unsigned int m=3; // symbol delay float beta=0.7f; // excess bandwidth factor unsigned int num_symbols=16; int ftype_tx = LIQUID_FIRFILT_RRC; int ftype_rx = LIQUID_FIRFILT_RRC; int dopt; while ((dopt = getopt(argc,argv,"uht:k:m:b:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"gmsk")==0) { ftype_tx = LIQUID_FIRFILT_GMSKTX; ftype_rx = LIQUID_FIRFILT_GMSKRX; } else { ftype_tx = liquid_getopt_str2firfilt(optarg); ftype_rx = liquid_getopt_str2firfilt(optarg); } if (ftype_tx == LIQUID_FIRFILT_UNKNOWN) { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int num_samples = num_symbols*k; unsigned int h_len = 2*k*m+1; // transmit/receive filter length unsigned int hc_len = 4*k*m+1; // composite filter length // arrays float ht[h_len]; // transmit filter float hr[h_len]; // receive filter float hc[hc_len]; // composite filter // design the filter(s) liquid_firdes_prototype(ftype_tx, k, m, beta, 0, ht); liquid_firdes_prototype(ftype_rx, k, m, beta, 0, hr); for (i=0; i=2*m) printf(" *\n"); else printf("\n"); } // clean up objects firinterp_rrrf_destroy(interp); firdecim_rrrf_destroy(decim); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %12.8f;\n", beta); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include #define OUTPUT_FILENAME "math_lngamma_example.m" int main() { unsigned int n = 256; // number of steps float zmin = 1e-3f; // minimum value float zmax = 6.00f; // maximum value unsigned int d = n/32; // print every d values to screen // log scale values float xmin = logf(zmin); float xmax = logf(zmax); float dx = (xmax-xmin)/(n-1); FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); unsigned int i; float z; float g; float x = xmin; // log(z) for (i=0; i #include #include "liquid.h" int main(int argc, char*argv[]) { // maximum number unsigned int n = 140; unsigned int i; printf("primitive roots of prime numbers up to %u:\n", n); for (i=3; i<=n; i++) { if (!liquid_is_prime(i)) continue; unsigned int root = liquid_primitive_root_prime(i); printf(" %4u : %4u\n", i, root); } return 0; } liquid-dsp-1.7.0/examples/modem_arb_example.c000066400000000000000000000067611474751757600212550ustar00rootroot00000000000000// This example demonstrates the functionality of the arbitrary // modem, a digital modulator/demodulator object with signal // constellation points chosen arbitrarily. A simple bit-error // rate simulation is then run to test the performance of the // modem. The results are written to a file. #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_arb_example.m" // print usage/help message void usage() { printf("modem_arb_example [options]\n"); printf(" u/h : print usage\n"); printf(" p : modulation depth (default 4 bits/symbol)\n"); } int main(int argc, char*argv[]) { // options unsigned int bps=6; // bits per symbol unsigned int n=1024; // number of data points to evaluate int dopt; while ((dopt = getopt(argc,argv,"uhp:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'p': bps = atoi(optarg); break; default: exit(1); } } // validate input if (bps == 0) { fprintf(stderr,"error: %s, bits/symbol must be greater than zero\n", argv[0]); exit(1); } // derived values unsigned int i; unsigned int M = 1< #include #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("modem_example [options]\n"); printf(" -h : print help\n"); printf(" -m : modulation scheme\n"); liquid_print_modulation_schemes(); } int main(int argc, char*argv[]) { // simulation parameters modulation_scheme ms = LIQUID_MODEM_QPSK; // modulation scheme float SNRdB_min = -5.0f; // starting SNR value float SNRdB_max = 40.0f; // maximum SNR value float SNRdB_step = 1.0f; // step size unsigned int num_trials = 1e6; // number of symbols char filename[] = "modem_ber_example.m"; int dopt; while ((dopt = getopt(argc,argv,"hm:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // create modem objects modem mod = modem_create(ms); // modulator modem dem = modem_create(ms); // demodulator // compute derived values and initialize counters unsigned int m = modem_get_bps(mod); // modulation bits/symbol unsigned int M = 1 << m; // constellation size: 2^m unsigned int i, sym_in, sym_out; float complex sample; // iterate through SNR values printf("# modulation scheme : %s\n", modulation_types[ms].name); printf("# %8s %8s %8s %12s\n", "SNR [dB]", "errors", "trials", "BER"); float SNRdB = SNRdB_min; // set SNR value FILE * fid = fopen(filename,"w"); fprintf(fid,"%% %s : auto-generated file\n", filename); fprintf(fid,"clear all; close all; SNRdB=[]; BER=[]; ms='%s';\n", modulation_types[ms].name); while (1) { // compute noise standard deviation float nstd = powf(10.0f, -SNRdB/20.0f); // reset modem objects (only necessary for differential schemes) modem_reset(mod); modem_reset(dem); // run trials unsigned int num_bit_errors = 0; for (i=0; i 0) fprintf(fid,"SNRdB(end+1)=%12.3f; BER(end+1)=%12.4e;\n", SNRdB, ber); // stop iterating if SNR exceed maximum or no errors were detected SNRdB += SNRdB_step; if (SNRdB > SNRdB_max || num_bit_errors == 0) break; } fprintf(fid,"figure; semilogy(SNRdB,BER,'-x'); grid on; axis([SNRdB(1) SNRdB(end) 1e-6 1]);\n"); fprintf(fid,"xlabel('SNR [dB]'); ylabel('BER'); title(ms)\n"); fclose(fid); printf("results written to %s\n", filename); // destroy modem objects and return modem_destroy(mod); modem_destroy(dem); return 0; } liquid-dsp-1.7.0/examples/modem_example.c000066400000000000000000000066071474751757600204300ustar00rootroot00000000000000// This example demonstrates the digital modulator/demodulator // (modem) object. Data symbols are modulated into complex // samples which are then demodulated without noise or phase // offsets. The user may select the modulation scheme via // the command-line interface. #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_example.m" // print usage/help message void usage() { printf("modem_example [options]\n"); printf(" h : print help\n"); printf(" v/q : verbose/quiet\n"); printf(" m : modulation scheme (qam16 default)\n"); liquid_print_modulation_schemes(); } int main(int argc, char*argv[]) { // create mod/demod objects modulation_scheme ms = LIQUID_MODEM_QAM16; int verbose = 1; int dopt; while ((dopt = getopt(argc,argv,"hvqm:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbose = 1; break; case 'q': verbose = 0; break; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // create the modem objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); // ensure bits/symbol matches modem description (only // applicable to certain specific modems) unsigned int bps = modemcf_get_bps(mod); modemcf_print(mod); // open output file FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"m = %u;\n", bps); fprintf(fid,"M = %u;\n", 1< #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_pi4dqpsk_example.m" int main() { // options float SNRdB = 25.0f; unsigned int num_symbols = 800; // create the modem objects modemcf mod = modemcf_create(LIQUID_MODEM_PI4DQPSK); modemcf demod = modemcf_create(LIQUID_MODEM_PI4DQPSK); modemcf_print(mod); // open output file FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"n=%u; sym_rx=zeros(1,n); sym_rec=zeros(1,n);\n", num_symbols); unsigned int i, index, s; float complex sym_tx, sym_rx; unsigned int num_sym_errors = 0, num_bit_errors = 0; float nstd = powf(10.0f, -SNRdB/20.0f); float r_prime = 0.0f; float complex s_prime; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_soft_example.m" // print usage/help message void usage() { printf("modem_soft_example [options]\n"); printf(" h : print help\n"); printf(" m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); } // print a string of bits to the standard output // _x : input symbol // _bps : bits/symbol // _n : number of characters to print (zero-padding) void print_bitstring(unsigned int _x, unsigned int _bps, unsigned int _n) { unsigned int i; for (i=0; i<_bps; i++) printf("%1u", (_x >> (_bps-i-1)) & 1); for (i=_bps; i<_n; i++) printf(" "); } int main(int argc, char*argv[]) { // create mod/demod objects modulation_scheme ms = LIQUID_MODEM_QPSK; int dopt; while ((dopt = getopt(argc,argv,"uhm:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; default: exit(1); } } // create the modem objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); // ensure bits/symbol matches modem description (only // applicable to certain specific modems) unsigned int bps = modemcf_get_bps(mod); modemcf_print(mod); unsigned int i; // modulated symbol unsigned int s_hard; // demodulated symbol (hard) unsigned char soft_bits[bps]; unsigned int s_soft; // demodulated symbol (soft, compacted) unsigned int num_symbols = 1< #include "liquid.h" int main() { unsigned int n=280; unsigned int factors[LIQUID_MAX_FACTORS]; unsigned int num_factors=0; // compute factors of n liquid_factor(n,factors,&num_factors); printf("factors of %u:\n", n); unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msequence_autocorr_example.m" int main(int argc, char*argv[]) { // options unsigned int m=5; // shift register length, n=2^m - 1 // create and initialize m-sequence msequence ms = msequence_create_default(m); msequence_print(ms); unsigned int n = msequence_get_length(ms); signed int rxx[n]; // auto-correlation // create and initialize first binary sequence on m-sequence bsequence bs1 = bsequence_create(n); bsequence_init_msequence(bs1, ms); // create and initialize second binary sequence on same m-sequence bsequence bs2 = bsequence_create(n); bsequence_init_msequence(bs2, ms); // when sequences are aligned, autocorrelation is equal to length rxx[0] = 2*bsequence_correlate(bs1, bs2) - n; // when sequences are misaligned, autocorrelation is equal to -1 unsigned int i; for (i=0; i #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // create and initialize m-sequence msequence q = msequence_create_default(5); msequence_print(q); // cycle through values and print state unsigned int i; for (i=0; i 0 && msequence_get_state(q)==1) { printf("invalid state!\n"); break; } printf("%u\n",msequence_get_state(q)); msequence_advance(q); } // ensure final state is 1 (circled all the way back around) printf("final state (should be 1): %u\n", msequence_get_state(q)); msequence_destroy(q); return 0; } liquid-dsp-1.7.0/examples/msequence_generator_example.c000066400000000000000000000025251474751757600233550ustar00rootroot00000000000000// msequence_generator_example.c // // This example demonstrates finding maximal-length sequence // (m-sequence) generator polynomials of a certain length. #include #include #include #include "liquid.h" void usage() { printf("msequence_generator_example [options]\n"); printf(" -h : print usage\n"); printf(" -d : degree of polynomial, default: 2\n"); } int main(int argc, char *argv[]) { unsigned int degree = 2; // get options int dopt; while((dopt = getopt(argc,argv,"uhd:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'd': degree = atol(optarg); break; default: exit(-1); } } unsigned int maxpoly = (1 << degree) - 1; unsigned int expected_sum = ((maxpoly + 1) / 2) * maxpoly; unsigned int i; unsigned int poly; for (poly = 0; poly <= maxpoly; ++poly) { unsigned int g = (poly << 1) + 1; msequence seq = msequence_create(degree, g, 1); unsigned int sum = 0; for (i = 0; i < maxpoly; ++i) { sum += msequence_get_state(seq); msequence_advance(seq); } if (sum == expected_sum) { printf("degree %d poly: %#06x\n", degree, g); } msequence_destroy(seq); } return 0; } liquid-dsp-1.7.0/examples/msourcecf_example.c000066400000000000000000000070011474751757600213020ustar00rootroot00000000000000// // msourcecf_example.c // // This example demonstrates generating multiple signal sources simultaneously // for testing using the msource (multi-source) family of objects. // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msourcecf_example.m" // user-defined callback; generate tones int callback(void * _userdata, float complex * _v, unsigned int _n) { unsigned int * counter = (unsigned int*)_userdata; unsigned int i; for (i=0; i<_n; i++) { _v[i] = *counter==0 ? 1 : 0; *counter = (*counter+1) % 8; } return 0; } int main() { // msource parameters int ms = LIQUID_MODEM_QPSK; // linear modulation scheme unsigned int m = 12; // modulation filter semi-length float beta = 0.30f; // modulation filter excess bandwidth factor float bt = 0.35f; // GMSK filter bandwidth-time factor // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 48000; // number of samples // create spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); unsigned int buf_len = 1024; float complex buf[buf_len]; // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // add signals (gen, fc, bw, gain, {options}) msourcecf_add_noise(gen, 0.0f, 1.00f, -40); // wide-band noise msourcecf_add_noise(gen, 0.0f, 0.20f, 0); // narrow-band noise msourcecf_add_tone (gen, -0.4f, 0.00f, 20); // tone msourcecf_add_modem(gen, 0.2f, 0.10f, 0, ms, m, beta); // modulated data (linear) msourcecf_add_gmsk (gen, -0.2f, 0.05f, 0, m, bt); // modulated data (GMSK) unsigned int counter = 0; msourcecf_add_user (gen, 0.4f, 0.15f, -10, (void*)&counter, callback); // tones // print source generator object msourcecf_print(gen); unsigned int total_samples = 0; while (total_samples < num_samples) { // write samples to buffer msourcecf_write_samples(gen, buf, buf_len); // push resulting sample through periodogram spgramcf_write(periodogram, buf, buf_len); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); // compute power spectral density output float psd[nfft]; spgramcf_get_psd(periodogram, psd); // destroy objects msourcecf_destroy(gen); spgramcf_destroy(periodogram); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msresamp2_crcf_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf(" -h : print help\n"); printf(" -r : resampling rate (output/input), default: 0.25\n"); printf(" -s : stop-band attenuation [dB], default: 60\n"); printf(" -n : number of low-rate samples, default: 256\n"); printf(" -f : pass-band cut-off frequency, default: 0.45\n"); } int main(int argc, char*argv[]) { // options float r = 0.25f; // resampling rate (output/input) float As = 60.0f; // resampling filter stop-band attenuation [dB] unsigned int n = 128; // number of low-rate samples float fc = 0.45f; // filter pass-band cut-off frequency int dopt; while ((dopt = getopt(argc,argv,"hr:s:n:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 's': As = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; default: exit(1); } } // validate input if (n == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } else if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]); exit(1); } else if ( roundf(fabsf(log2f(r))) > 10 ) { fprintf(stderr,"error: %s, resampling rate unreasonable\n", argv[0]); exit(1); } // determine type and compute number of stages unsigned int num_stages = (unsigned int) roundf(fabsf(log2f(r))); int type = r < 1. ? LIQUID_RESAMP_DECIM : LIQUID_RESAMP_INTERP; printf("msresamp2:\n"); printf(" rate : %12.8f\n", r); printf(" log2(r) : %12.8f\n", log2f(r)); printf(" type : %s\n", type == LIQUID_RESAMP_DECIM ? "decim" : "interp"); printf(" stages : %u\n", num_stages); unsigned int i; // create multi-stage arbitrary resampler object msresamp2_crcf q = msresamp2_crcf_create(type, num_stages, fc, 0.0f, As); msresamp2_crcf_print(q); float delay = msresamp2_crcf_get_delay(q); r = msresamp2_crcf_get_rate(q); // number of input samples (zero-padded) unsigned int M = (1 << num_stages); // integer resampling rate unsigned int nx = (type == LIQUID_RESAMP_DECIM) ? n * M : n; unsigned int ny = (type == LIQUID_RESAMP_DECIM) ? n : n * M; unsigned int wlen = round(0.75 * nx); // allocate memory for arrays float complex x[nx]; float complex y[ny]; // generate input signal: tone just before the edge of filter band float ftone = 0.95 * fc * ((type == LIQUID_RESAMP_DECIM) ? r : 1); float wsum = 0.0f; for (i=0; i Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } // print results and check frequency location printf("output results:\n"); printf(" output delay : %12.8f samples\n", delay); printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n",OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"delay=%f;\n", delay); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'LineWidth',1, 'Color',[0.5 0.5 0.5],...\n"); fprintf(fid," fy,Y,'LineWidth',1.5,'Color',[0.1 0.3 0.5]);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('Frequency (normalized to original sample rate)');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/msresamp_crcf_example.c000066400000000000000000000174721474751757600221550ustar00rootroot00000000000000// // msresamp_crcf_example.c // // Demonstration of the multi-stage arbitrary resampler // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msresamp_crcf_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf(" h : print help\n"); printf(" r : resampling rate (output/input), default: 0.23175\n"); printf(" s : stop-band attenuation [dB], default: 60\n"); printf(" n : number of input samples, default: 400\n"); printf(" f : input signal frequency, default: 0.017\n"); } int main(int argc, char*argv[]) { // options float r=0.23175f; // resampling rate (output/input) float As=60.0f; // resampling filter stop-band attenuation [dB] unsigned int n=400; // number of input samples float fc=0.017f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:s:n:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 's': As = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; default: exit(1); } } // validate input if (n == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } else if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]); exit(1); } else if ( fabsf(log2f(r)) > 10 ) { fprintf(stderr,"error: %s, resampling rate unreasonable\n", argv[0]); exit(1); } unsigned int i; // create multi-stage arbitrary resampler object msresamp_crcf q = msresamp_crcf_create(r,As); msresamp_crcf_print(q); float delay = msresamp_crcf_get_delay(q); // number of input samples (zero-padded) unsigned int nx = n + (int)ceilf(delay) + 10; // output buffer with extra padding for good measure unsigned int ny_alloc = (unsigned int) (2*(float)nx * r); // allocation for output // allocate memory for arrays float complex x[nx]; float complex y[ny_alloc]; // generate input signal float wsum = 0.0f; for (i=0; i Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } // print results and check frequency location printf("output results:\n"); printf(" output delay : %12.8f samples\n", delay); printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n",OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"delay=%f;\n", delay); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'LineWidth',1, 'Color',[0.5 0.5 0.5],...\n"); fprintf(fid," fy,Y,'LineWidth',1.5,'Color',[0.1 0.3 0.5]);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 20]);\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/msresamp_crcf_noise_example.c000066400000000000000000000104371474751757600233440ustar00rootroot00000000000000// // msresamp_crcf_noise_example.c // // Demonstration of mulsti-stage resamp object whereby an input noise signal // is resampled at a rate 'r'. // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msresamp_crcf_noise_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf(" -h : print help\n"); printf(" -r : resampling rate, default: 0.3\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); } int main(int argc, char*argv[]) { // options float rate= 0.30f; // resampling rate float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hr:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': rate = atof(optarg); break; case 's': As = atof(optarg); break; default: exit(1); } } // validate input if (rate >= 1.0f) { fprintf(stderr,"error: %s, input rate r must be less than 1\n", argv[0]); exit(1); } // create resampler object msresamp_crcf q = msresamp_crcf_create(rate,As); msresamp_crcf_print(q); // number of sample blocks unsigned int num_blocks = 1000; // arrays unsigned int buf_len = 1024; float complex buf_x[ buf_len]; float complex buf_y[2*buf_len]; // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // wide-band noise msourcecf_add_noise(gen, 0.0f, 1.00f, -60); // in-band signal msourcecf_add_noise(gen, 0.0f, 0.5f*rate, 0); // high-power signal just out of band msourcecf_add_noise(gen, (0.5*rate + 0.12f), 0.10f, 10); // create spectral periodogram objects unsigned int nfft = 2400; spgramcf px = spgramcf_create_default(nfft); spgramcf py = spgramcf_create_default(nfft); // generate input signal (filtered noise) unsigned int i; for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "nco_crcf_mix_example.m" int main() { // options int type = LIQUID_NCO; // nco type float fc = 0.05f; // signal offset frequency unsigned int num_samples = 240000; // number of samples to run unsigned int nfft = 1200; // spectral periodogram FFT size // create stream generator and add some sources msourcecf gen = msourcecf_create_default(); msourcecf_add_noise(gen, 0.0f, 1.00f, -60); // wide-band noise msourcecf_add_noise(gen, 0.0f, 0.20f, -40); // narrow-band noise msourcecf_add_tone (gen, -0.4f, 0.0f, -20); // tone msourcecf_add_modem(gen, 0.2f, 0.1f, -30, LIQUID_MODEM_QPSK, 12, 0.25f); // modem // create the NCO object nco_crcf q = nco_crcf_create(type); nco_crcf_set_frequency(q, 2*M_PI*fc); nco_crcf_print(q); // create spectral periodograms spgramcf p0 = spgramcf_create_default(nfft); // before mixing down spgramcf p1 = spgramcf_create_default(nfft); // after mixing down // unsigned int buf_len = 1024; float complex buf[buf_len]; unsigned int total_samples = 0; while (total_samples < num_samples) { // write samples to buffer msourcecf_write_samples(gen, buf, buf_len); // push resulting sample through periodogram spgramcf_write(p0, buf, buf_len); // mix signal down (in place) nco_crcf_mix_block_down(q, buf, buf, buf_len); // push resulting sample through periodogram spgramcf_write(p1, buf, buf_len); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); // compute power spectral density output float psd0[nfft]; float psd1[nfft]; spgramcf_get_psd(p0, psd0); spgramcf_get_psd(p1, psd1); // destroy objects spgramcf_destroy(p0); spgramcf_destroy(p1); nco_crcf_destroy(q); msourcecf_destroy(gen); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"psd0 = zeros(1,nfft);\n"); fprintf(fid,"psd1 = zeros(1,nfft);\n"); unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "nco_crcf_tone_example.m" int main() { // options int type = LIQUID_NCO; // nco type float fc = 0.000241852307f; // frequency unsigned int num_samples = 2400; // number of samples to run // create the NCO object nco_crcf q = nco_crcf_create(type); nco_crcf_set_frequency(q, 2*M_PI*fc); nco_crcf_print(q); unsigned int i; float complex x[num_samples]; for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "nco_example.m" int main() { // options int type = LIQUID_NCO; // nco type float fc = 0.1f*M_SQRT1_2; // nco tone frequency unsigned int num_samples = 240000; // number of samples to run unsigned int nfft = 4000; // spectral periodogram FFT size // create the NCO object nco_crcf q = nco_crcf_create(type); nco_crcf_set_frequency(q, 2*M_PI*fc); nco_crcf_print(q); // create spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); spgramcf_print(periodogram); unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "nco_pll_example.m" // print usage/help message void usage() { printf("nco_pll_example [options]\n"); printf(" u/h : print usage\n"); printf(" b : pll bandwidth, default: 0.01\n"); printf(" n : number of samples, default: 512\n"); printf(" p : phase offset (radians), default: pi/4\n"); printf(" f : frequency offset (radians), default: 0.3\n"); } int main(int argc, char*argv[]) { // set random seed srand( time(NULL) ); // parameters float phase_offset = 0.0f; // initial phase offset float frequency_offset = 0.40f; // initial frequency offset float pll_bandwidth = 0.003f; // phase-locked loop bandwidth unsigned int n = 512; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhb:n:p:f:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': pll_bandwidth = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); // initialize objects nco_crcf_set_phase(nco_tx, phase_offset); nco_crcf_set_frequency(nco_tx, frequency_offset); nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth); // generate input float complex x[n]; float complex y[n]; float phase_error[n]; unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "nco_pll_modem_example.m" // print usage/help message void usage() { printf("nco_pll_modem_example [options]\n"); printf(" u/h : print usage\n"); printf(" s : signal-to-noise ratio, default: 30dB\n"); printf(" b : pll bandwidth, default: 0.002\n"); printf(" n : number of symbols, default: 1200\n"); printf(" P : phase offset (radians), default: pi/10 ~ 0.3146\n"); printf(" F : frequency offset (radians), default: 0.1\n"); printf(" m : modulation scheme, default: qpsk\n"); liquid_print_modulation_schemes(); } int main(int argc, char*argv[]) { srand( time(NULL) ); // parameters float phase_offset = M_PI/10; float frequency_offset = 0.10f; float SNRdB = 30.0f; float pll_bandwidth = 0.002f; modulation_scheme ms = LIQUID_MODEM_QPSK; unsigned int n=1200; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhs:b:n:P:F:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'b': pll_bandwidth = atof(optarg); break; case 'n': n = atoi(optarg); break; case 'P': phase_offset = atof(optarg); break; case 'F': frequency_offset= atof(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme \"%s\"\n", argv[0], optarg); return 1; } break; default: exit(1); } } unsigned int d=n/32; // print every "d" lines FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid, "%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid, "clear all; close all;\n"); fprintf(fid, "phi=zeros(1,%u);\n",n); fprintf(fid, "r=zeros(1,%u);\n",n); // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); unsigned int bps = modemcf_get_bps(mod); // initialize objects nco_crcf_set_phase(nco_tx, phase_offset); nco_crcf_set_frequency(nco_tx, frequency_offset); nco_crcf_pll_set_bandwidth(nco_rx, pll_bandwidth); float noise_power = powf(10.0f, -SNRdB/20.0f); // print parameters printf("PLL example :\n"); printf("modem : %u-%s\n", 1<theta - nco_rx->theta; // print every line in a format that octave can read fprintf(fid, "phi(%u) = %10.6E;\n", i+1, phase_error); fprintf(fid, "dphi(%u) = %10.6E;\n", i+1, nco_crcf_get_frequency(nco_rx)); fprintf(fid, "r(%u) = %10.6E + j*%10.6E;\n", i+1, crealf(v), cimagf(v)); if ((i+1)%d == 0 || i==n-1) { printf(" %4u: e_hat : %6.3f, phase error : %6.3f, freq error : %12.9f\n", i+1, // iteration phase_error, // estimated phase error nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx),// true phase error nco_crcf_get_frequency(nco_tx) - nco_crcf_get_frequency(nco_rx)// true frequency error ); } // update tx nco object nco_crcf_step(nco_tx); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update rx nco object nco_crcf_step(nco_rx); } fprintf(fid, "figure('color','white','position',[100 100 1200 400]);\n"); fprintf(fid, "subplot(1,3,1:2);\n"); fprintf(fid, "plot(1:length(phi),phi,'LineWidth',2,'Color',[0 0.25 0.5]);\n"); fprintf(fid, "xlabel('Symbol Index');\n"); fprintf(fid, "ylabel('Phase Error [radians]');\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "t0 = round(0.25*length(r));\n"); fprintf(fid, "subplot(1,3,3);\n"); fprintf(fid, "plot(r(1:t0),'.','Color',[0.6 0.6 0.6],r(t0:end),'.','Color',[0 0.25 0.5]);\n"); fprintf(fid, "grid on;\n"); fprintf(fid, "axis([-1 1 -1 1]*1.5);\n"); fprintf(fid, "axis('square');\n"); fprintf(fid, "xlabel('In-Phase');\n"); fprintf(fid, "ylabel('Quadrature');\n"); //fprintf(fid, "legend(['first 25%%'],['last 75%%'],1);\n"); fclose(fid); printf("results written to %s.\n",OUTPUT_FILENAME); nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); modemcf_destroy(mod); modemcf_destroy(demod); printf("bit errors: %u / %u\n", num_errors, bps*n); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/nco_pll_real_example.c000066400000000000000000000061301474751757600217470ustar00rootroot00000000000000// nco_pll_real_example.c : simulation of a real-valued phase-locked loop #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "nco_pll_real_example.m" int main() { // parameters and simulation options float alpha = 0.002f; // PLL bandwidth unsigned int n = 500; // number of samples // objects nco_crcf nco_tx = nco_crcf_create(LIQUID_VCO); nco_crcf nco_rx = nco_crcf_create(LIQUID_VCO); // initialize objects nco_crcf_set_frequency(nco_tx, 0.40); nco_crcf_set_frequency(nco_rx, 0.30); nco_crcf_set_phase (nco_rx, 3.00); nco_crcf_pll_set_bandwidth(nco_rx, alpha); // write output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"n = %u; x = zeros(1,n); y = zeros(1,n); e = zeros(1,n);\n", n); // run basic simulation unsigned int i; float x, y, e; // input, output, phase error for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "nyquist_filter_example.m" // print usage/help message void usage() { printf("nyquist_filter_example options:\n"); printf(" u/h : print usage/help\n"); printf(" t : filter type: [kaiser], pm, rcos, fexp, fsech, farcsech\n"); printf(" k : filter samples/symbol, k >= 2, default: 2\n"); printf(" m : filter delay (symbols), m >= 1, default: 4\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.33\n"); } int main(int argc, char*argv[]) { // options unsigned int k=2; // samples/symbol unsigned int m=4; // symbol delay float beta=0.33f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_RCOS; int dopt; while ((dopt = getopt(argc,argv,"uht:k:m:b:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"kaiser")==0) { ftype = LIQUID_FIRFILT_KAISER; } else if (strcmp(optarg,"pm")==0) { ftype = LIQUID_FIRFILT_PM; } else if (strcmp(optarg,"rcos")==0) { ftype = LIQUID_FIRFILT_RCOS; } else if (strcmp(optarg,"fexp")==0) { ftype = LIQUID_FIRFILT_FEXP; } else if (strcmp(optarg,"fsech")==0) { ftype = LIQUID_FIRFILT_FSECH; } else if (strcmp(optarg,"farcsech")==0) { ftype = LIQUID_FIRFILT_FARCSECH; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; default: exit(1); } } if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } // initialize objects unsigned int h_len = 2*k*m+1; float h[h_len]; // design the filter liquid_firdes_prototype(ftype,k,m,beta,0,h); // print the coefficients to the screen unsigned int i; for (i=0; i #include #include #include #include #include #include "liquid.h" void usage() { printf("ofdmflexframesync_example [options]\n"); printf(" -h : print usage\n"); printf(" -s : signal-to-noise ratio [dB], default: 20\n"); printf(" -F : carrier frequency offset, default: 0.002\n"); printf(" -M : number of subcarriers (must be even), default: 64\n"); printf(" -C : cyclic prefix length, default: 16\n"); printf(" -n : payload length [bytes], default: 120\n"); printf(" -m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); printf(" -v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" -c : coding scheme (inner): h74 default\n"); printf(" -k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); printf(" -d : enable debugging\n"); } // callback function int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata); int main(int argc, char*argv[]) { //srand(time(NULL)); // options unsigned int M = 64; // number of subcarriers unsigned int cp_len = 16; // cyclic prefix length unsigned int taper_len = 4; // taper length unsigned int payload_len = 120; // length of payload (bytes) modulation_scheme ms = LIQUID_MODEM_QPSK; // modulation scheme fec_scheme fec0 = LIQUID_FEC_NONE; // inner code fec_scheme fec1 = LIQUID_FEC_HAMMING128; // outer code crc_scheme check = LIQUID_CRC_32; // validity check float noise_floor = -80.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi = 0.02f; // carrier frequency offset int debug = 0; // enable debugging? // get options int dopt; while((dopt = getopt(argc,argv,"uhds:F:M:C:n:m:v:c:k:")) != EOF){ switch (dopt) { case 'u': case 'h': usage(); return 0; case 'd': debug = 1; break; case 's': SNRdB = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'n': payload_len = atol(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); break; case 'c': fec0 = liquid_getopt_str2fec(optarg); break; case 'k': fec1 = liquid_getopt_str2fec(optarg); break; default: exit(-1); } } unsigned int i; // TODO : validate options // derived values unsigned int buf_len = 256; float complex buf[buf_len]; // time-domain buffer // allocate memory for header, payload unsigned char header[8]; unsigned char payload[payload_len]; // create frame generator ofdmflexframegenprops_s fgprops; ofdmflexframegenprops_init_default(&fgprops); fgprops.check = check; fgprops.fec0 = fec0; fgprops.fec1 = fec1; fgprops.mod_scheme = ms; ofdmflexframegen fg = ofdmflexframegen_create(M, cp_len, taper_len, NULL, &fgprops); // create frame synchronizer ofdmflexframesync fs = ofdmflexframesync_create(M, cp_len, taper_len, NULL, callback, (void*)payload); if (debug) ofdmflexframesync_debug_enable(fs); // initialize header/payload and assemble frame for (i=0; i<8; i++) header[i] = i & 0xff; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmframegen_example.m" int main() { // options unsigned int num_subcarriers=64;// unsigned int cp_len=16; // cyclic prefix length //unsigned int num_symbols=2; // number of ofdm symbols // unsigned int frame_len = num_subcarriers + cp_len; //unsigned int num_samples = num_subcarriers * num_frames; // create synthesizer/analyzer objects ofdmframegen fg = ofdmframegen_create(num_subcarriers, cp_len); ofdmframegen_print(fg); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_subcarriers=%u;\n", num_subcarriers); fprintf(fid,"cp_len=%u;\n", cp_len); fprintf(fid,"frame_len=%u;\n", frame_len); fprintf(fid,"X = zeros(1,num_subcarriers);\n"); fprintf(fid,"x = zeros(1,frame_len);\n"); unsigned int i; float complex X[num_subcarriers]; // channelized symbols float complex x[frame_len]; // time-domain samples for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmframesync_example.m" void usage() { printf("Usage: ofdmframesync_example [OPTION]\n"); printf(" h : print help\n"); printf(" M : number of subcarriers (must be even), default: 1200\n"); printf(" C : cyclic prefix length, default: 60\n"); printf(" T : taper length, default: 50\n"); printf(" s : signal-to-noise ratio [dB], default: 30\n"); } // forward declaration of callback function; this will be invoked for every // OFDM symbol received by the parent ofdmframesync object. The object will // reset when something other than a zero is returned. // _X : array of received subcarrier samples [size: _M x 1] // _p : subcarrier allocation array [size: _M x 1] // _M : number of subcarriers // _userdata : user-defined data pointer static int callback(float complex * _X, unsigned char * _p, unsigned int _M, void * _userdata); // custom data type to pass to callback function struct rx_symbols { float complex syms_bpsk[2000]; // even subcarrier symbols float complex syms_qpsk[2000]; // odd subcarrier symbols unsigned int num_bpsk; // counter unsigned int num_qpsk; // counter }; // main function int main(int argc, char*argv[]) { // set the random seed differently for each run srand(time(NULL)); // options unsigned int M = 1200; // number of subcarriers unsigned int cp_len = 60; // cyclic prefix length unsigned int taper_len = 50; // taper length unsigned int num_symbols = 20; // number of data symbols float noise_floor = -120.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] // get options int dopt; while((dopt = getopt(argc,argv,"hdM:C:T:s:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'T': taper_len = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int frame_len = M + cp_len; unsigned int num_samples = (3+num_symbols)*frame_len; float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); unsigned char p[M]; float complex X[M]; // channelized symbols float complex y[num_samples]; // output time series // initialize subcarrier allocation ofdmframe_init_default_sctype(M, p); // create subcarrier notch in upper half of band unsigned int n0 = (unsigned int) (0.13 * M); // lower edge of notch unsigned int n1 = (unsigned int) (0.21 * M); // upper edge of notch for (i=n0; inum_bpsk < 2000) { // save at most 2000 BPSK symbols data->syms_bpsk[data->num_bpsk] = _X[i]; data->num_bpsk++; } else if ( (i % 2) == 1 && data->num_qpsk < 2000) { // save at most 2000 QPSK symbols data->syms_qpsk[data->num_qpsk] = _X[i]; data->num_qpsk++; } } // return return 0; } liquid-dsp-1.7.0/examples/ordfilt_rrrf_example.c000066400000000000000000000034551474751757600220230ustar00rootroot00000000000000// // ordfilt_rrrf_example.c // #include #include #include "liquid.h" #define OUTPUT_FILENAME "ordfilt_rrrf_example.m" int main() { // options unsigned int num_samples = 2400; // number of random input samples unsigned int n = 101; // filter length unsigned int k = 5; // order statistic index // arrays float x[num_samples]; // filter input float y[num_samples]; // filter output // generate input tone with noise unsigned int i; for (i=0; i #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("packetizer_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : input data size (number of uncoded bytes): 8 default\n"); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): h74 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); } int main(int argc, char*argv[]) { // options unsigned int n=8; // original data message length crc_scheme check = LIQUID_CRC_32; // data integrity check fec_scheme fec0 = LIQUID_FEC_HAMMING74; // inner code fec_scheme fec1 = LIQUID_FEC_NONE; // outer code // read command-line options int dopt; while((dopt = getopt(argc,argv,"uhn:v:c:k:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': n = atoi(optarg); if (n < 1) { printf("error: packet length must be positive\n"); usage(); exit(-1); } break; case 'v': // data integrity check check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'c': // inner FEC scheme fec0 = liquid_getopt_str2fec(optarg); if (fec0 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported inner FEC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'k': // outer FEC scheme fec1 = liquid_getopt_str2fec(optarg); if (fec1 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported outer FEC scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } unsigned int i; unsigned int k = packetizer_compute_enc_msg_len(n,check,fec0,fec1); packetizer p = packetizer_create(n,check,fec0,fec1); packetizer_print(p); // initialize arrays unsigned char msg_org[n]; // original message unsigned char msg_enc[k]; // encoded message unsigned char msg_rec[k]; // received message unsigned char msg_dec[n]; // decoded message int crc_pass; // initialize original data message for (i=0; i #include #include #include #include "liquid.h" // print usage/help message void usage() { printf("packetizer_example [options]\n"); printf(" u/h : print usage\n"); printf(" n : input data size (number of uncoded bytes): 8 default\n"); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): h74 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); } int main(int argc, char*argv[]) { // options unsigned int n=8; // original data message length crc_scheme check = LIQUID_CRC_32; // data integrity check fec_scheme fec0 = LIQUID_FEC_HAMMING74; // inner code fec_scheme fec1 = LIQUID_FEC_NONE; // outer code // read command-line options int dopt; while((dopt = getopt(argc,argv,"uhn:v:c:k:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 'n': n = atoi(optarg); if (n < 1) { printf("error: packet length must be positive\n"); usage(); exit(-1); } break; case 'v': // data integrity check check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'c': // inner FEC scheme fec0 = liquid_getopt_str2fec(optarg); if (fec0 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported inner FEC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'k': // outer FEC scheme fec1 = liquid_getopt_str2fec(optarg); if (fec1 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported outer FEC scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } unsigned int i; unsigned int k = packetizer_compute_enc_msg_len(n,check,fec0,fec1); packetizer p = packetizer_create(n,check,fec0,fec1); packetizer_print(p); // initialize arrays unsigned char msg_org[n]; // original message unsigned char msg_enc[k]; // encoded message unsigned char msg_rec[8*k]; // received message (soft bits) unsigned char msg_dec[n]; // decoded message int crc_pass; // initialize original data message for (i=0; i 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; msg_rec[i] = soft_bit; } // decode packet crc_pass = packetizer_decode_soft(p,msg_rec,msg_dec); // clean up allocated objects packetizer_destroy(p); // print results printf("original message: [%3u] ",n); for (i=0; i 127) ? 1<<(8-j-1) : 0; unsigned int bit_enc = (msg_enc[i] >> (8-j-1)) & 0x01; unsigned int bit_rec = (msg_rec[8*i+j] > 127) ? 1 : 0; //printf("%1u %3u (%1u) %c", bit_enc, msg_rec[i], bit_rec, bit_enc != bit_rec ? '*' : ' '); printf("%4u%c", msg_rec[8*i+j], bit_enc != bit_rec ? '*' : ' '); } printf(" : %c%.2X\n", msg_cor_hard==msg_enc[i] ? ' ' : '*', (unsigned int) (msg_cor_hard)); } } // verbose printf("decoded message: [%3u] ",n); for (i=0; i #include #include #include "liquid.h" int main() { // create mod/demod objects modulation_scheme ms = LIQUID_MODEM_QAM16; // create the modem objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); // ensure bits/symbol matches modem description (only // applicable to certain specific modems) unsigned int bps = modemcf_get_bps(mod); modemcf_print(mod); unsigned int i; // modulated symbol unsigned int s; // demodulated symbol unsigned int num_symbols = 1< #include #include #include #include #include "liquid.h" // output to octave-friendly format #define OUTPUT_FILENAME "pll_example.m" int main() { // parameters float phase_offset = 0.8f; // carrier phase offset float frequency_offset = 0.01f; // carrier frequency offset float wn = 0.05f; // pll bandwidth float zeta = 0.707f; // pll damping factor float K = 1000; // pll loop gain unsigned int n = 256; // number of samples unsigned int d = n/32; // print every "d" lines // float theta[n]; // input phase float complex x[n]; // input sinusoid float phi[n]; // output phase float complex y[n]; // output sinusoid // generate iir loop filter object iirfilt_rrrf H = iirfilt_rrrf_create_pll(wn, zeta, K); iirfilt_rrrf_print(H); unsigned int i; // generate input float t=phase_offset; float dt = frequency_offset; for (i=0; i #include #include "liquid.h" int main() { unsigned int n=6; // polynomial length (order+1) unsigned int i; // generate polynomial float p[6] = {6,11,-33,-33,11,6}; float complex roots[n-1]; // print polynomial printf("polynomial:\n"); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "polyfit_comparison_example.m" int main() { float x[3] = {-1.0, 0.0, 1.0}; float y[3] = { 2.0, 7.0, 4.0}; float p0[3], p1[3]; // conventional polyf_fit (x,y,3,p0,3); polyf_fit_lagrange(x,y,3,p1); // evaluate unsigned int n = 51; float x_eval[n], y0[n], y1[n]; unsigned int i; for (i=0; i #include "liquid.h" #define OUTPUT_FILENAME "polyfit_example.m" int main() { unsigned int n= 25; // number of samples unsigned int order=2; // polynomial order // initialize data vectors float x[n]; float y[n]; unsigned int i; for (i=0; i %12.6f\n", x[i],y[i],polyf_val(p,order+1,x[i])); for (i=0; i<=order; i++) printf("p[%3u] = %12.8f\n", i, p[i]); // plot results FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"n = %u; order = %u;\n", n, order); fprintf(fid,"x = zeros(1,n); y = zeros(1,n); p = zeros(1,order+1);\n"); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "polyfit_lagrange_example.m" int main() { unsigned int n=15; // number of samples FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); // initialize data vectors float x[n]; float y[n]; unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "qdetector_cccf_example.m" // print usage/help message void usage() { printf("qdetector_cccf_example\n"); printf("options:\n"); printf(" h : print usage/help\n"); printf(" n : number of sync symbols, default: 80\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter delay, default: 7 sybmols\n"); printf(" b : excess bandwidth factor, default: 0.3\n"); printf(" F : carrier frequency offset, default: -0.01\n"); printf(" T : fractional sample offset, default: 0\n"); printf(" S : SNR [dB], default: 20 dB\n"); printf(" t : detection threshold, default: 0.3\n"); printf(" r : carrier offset search range,default: 0.05\n"); } int main(int argc, char*argv[]) { // options unsigned int sequence_len = 80; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float tau = -0.3f; // fractional sample timing offset float dphi = -0.01f; // carrier frequency offset float phi = 0.5f; // carrier phase offset float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] float threshold = 0.5f; // detection threshold float range = 0.05f; // carrier offset search range [radians/sample] int dopt; while ((dopt = getopt(argc,argv,"hn:k:m:b:F:T:S:t:r:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': sequence_len = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'T': tau = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': threshold = atof(optarg); break; case 'r': range = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (tau < -0.5f || tau > 0.5f) { fprintf(stderr,"error: %s, fractional sample offset must be in [-0.5,0.5]\n", argv[0]); exit(1); } // derived values float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); // generate synchronization sequence (QPSK symbols) float complex sequence[sequence_len]; for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "qdsync_cccf_example.m" // synchronization callback, return 0:continue, 1:reset int callback(float complex * _buf, unsigned int _buf_len, void * _context) { printf("callback got %u samples\n", _buf_len); unsigned int i; for (i=0; i<_buf_len; i++) fprintf((FILE*)_context, "y(end+1) = %12.8f + %12.8fj;\n", crealf(_buf[i]), cimagf(_buf[i])); return 0; } int main(int argc, char*argv[]) { // options unsigned int seq_len = 80; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float nstd = 0.01f; // generate synchronization sequence (QPSK symbols) float complex seq[seq_len]; unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "qdsync_cccf_performance_example.m" int main(int argc, char*argv[]) { // options unsigned int seq_len = 1024; // number of sync symbols unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float threshold = 0.10f;// unsigned int min_trials = 10; // unsigned int max_trials = 100; // unsigned int min_missed = 4; // float SNRdB = -25.0f; // generate synchronization sequence (QPSK symbols) float complex seq[seq_len]; unsigned int i; for (i=0; i= min_missed) break; if (num_trials >= max_trials) break; } float pmd = (float)num_missed / (float)num_trials; printf("SNR: %8.3f dB, missed %3u / %3u (%5.1f%%)\n", SNRdB, num_missed, num_trials, pmd*100); if (num_missed < min_missed) break; SNRdB += 1.0f; } qdsync_cccf_destroy(q); #if 0 // open file for storing results FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all;\n"); // export results fprintf(fid,"seq_len = %u;\n", seq_len); fprintf(fid,"figure('color','white','position',[100 100 800 800]);\n"); fprintf(fid,"hold on;\n"); fprintf(fid,"hold off;\n"); fprintf(fid,"legend('Preamble','Payload');\n"); fprintf(fid,"grid on; xlabel('real'); ylabel('imag');\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); #endif return 0; } liquid-dsp-1.7.0/examples/qnsearch_example.c000066400000000000000000000033551474751757600211300ustar00rootroot00000000000000// // qnsearch_example.c // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "qnsearch_example.m" int main() { unsigned int num_parameters = 8; // dimensionality of search (minimum 2) unsigned int num_iterations = 4000; // number of iterations to run float optimum_vect[num_parameters]; unsigned int i; for (i=0; i #include #include #include #include #include #include #include "liquid.h" void usage() { printf("ofdmflexframesync_example [options]\n"); printf(" h : print usage\n"); printf(" n : payload length [bytes], default: 400\n"); printf(" m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner): g2412 default\n"); printf(" k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); printf(" s : signal-to-noise ratio [dB], default: 6\n"); } int main(int argc, char *argv[]) { //srand( time(NULL) ); // options modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_GOLAY2412; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) unsigned int payload_len = 400; // payload length float SNRdB = 6.0f; // SNR [dB] const char filename[] = "qpacketmodem_example.m"; // output filename // get options int dopt; while((dopt = getopt(argc,argv,"hn:m:v:c:k:s:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'n': payload_len = atol(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); break; case 'c': fec0 = liquid_getopt_str2fec(optarg); break; case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(-1); } } unsigned int i; // derived values float nstd = powf(10.0f, -SNRdB/20.0f); // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, payload_len, check, fec0, fec1, ms); qpacketmodem_print(q); // initialize payload unsigned char payload_tx[payload_len]; unsigned char payload_rx[payload_len]; // initialize payload for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "qpacketmodem_performance_example.m" void usage() { printf("qpacketmodem_performance_example [options]\n"); printf(" -h : print usage\n"); printf(" -p : payload length [bytes], default: 400\n"); printf(" -m : modulation scheme (qpsk default)\n"); liquid_print_modulation_schemes(); printf(" -v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" -c : coding scheme (inner): g2412 default\n"); printf(" -k : coding scheme (outer): none default\n"); liquid_print_fec_schemes(); printf(" -s : SNR start [dB], default: -5\n"); printf(" -x : SNR max [dB], default: 20\n"); printf(" -d : SNR step [dB], default: 0.5\n"); printf(" -e : minimum number of packet errors per step, default: 50\n"); printf(" -t : minimum number of packet trials per step, default: 2000\n"); printf(" -T : maximum number of packet trials per step, default: 40000\n"); } int main(int argc, char *argv[]) { // options (defaults to frame64 parameters) modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme crc_scheme check = LIQUID_CRC_24; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_GOLAY2412; // fec (outer) unsigned int payload_len = 72; // payload length float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) float SNRdB_max = 20.0f; // signal-to-noise ratio (maximum) float SNRdB_step = 0.5f; // signal-to-noise ratio (maximum) unsigned int min_packet_errors = 50; // minimum errors to observe for each step unsigned int min_packet_trials = 2000; // minimum number of packets for each step unsigned int max_packet_trials =40000; // maximum number of packets for each step // get options int dopt; while((dopt = getopt(argc,argv,"hp:m:v:c:k:s:x:d:e:t:T:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'p': payload_len = atol(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); break; case 'v': check = liquid_getopt_str2crc(optarg); break; case 'c': fec0 = liquid_getopt_str2fec(optarg); break; case 'k': fec1 = liquid_getopt_str2fec(optarg); break; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; case 'd': SNRdB_step = atof(optarg); break; case 'e': min_packet_errors = atoi(optarg); break; case 't': min_packet_trials = atoi(optarg); break; case 'T': max_packet_trials = atoi(optarg); break; default: exit(-1); } } unsigned int i; // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, payload_len, check, fec0, fec1, ms); qpacketmodem_print(q); // get frame length unsigned int frame_len = qpacketmodem_get_frame_len(q); // initialize payload unsigned char payload_tx [payload_len]; // payload (transmitted) unsigned char payload_rx [payload_len]; // payload (received) float complex frame_tx [frame_len]; // frame samples (transmitted) float complex frame_rx [frame_len]; // frame samples (received) // output file FILE* fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s: auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all; close all; SNR=[]; ber=[]; per=[];\n"); printf(" %8s %8s %8s %12s %8s %8s %6s\n", "SNR [dB]", "errors", "bits", "BER", "errors", "packets", "PER"); float SNRdB = SNRdB_min; while (SNRdB < SNRdB_max) { // reset counters float nstd = powf(10.0f, -SNRdB/20.0f); // noise standard deviation unsigned int num_packet_trials = 0, num_packet_errors = 0; unsigned int num_bit_trials = 0, num_bit_errors = 0; while (1) { // initialize payload for (i=0; i= min_packet_errors) break; if (num_packet_trials >= max_packet_trials) break; } float BER = (float)num_bit_errors / (float)num_bit_trials; float PER = (float)num_packet_errors / (float)num_packet_trials; printf(" %8.2f %8u %8u %12.4e %8u %8u %6.2f%%\n", SNRdB, num_bit_errors, num_bit_trials, BER, num_packet_errors, num_packet_trials, PER*100.0f); fprintf(fid,"SNR(end+1)=%g; ber(end+1)=%g; per(end+1)=%g;\n", SNRdB, BER, PER); if (num_packet_errors < min_packet_errors) break; SNRdB += SNRdB_step; } // destroy allocated objects qpacketmodem_destroy(q); fprintf(fid,"figure('position',[100 100 500 720]);\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," gamma = 10.^(SNR/10);\n"); fprintf(fid," ber_qpsk = 0.5*(1 - erf(sqrt(gamma)/sqrt(2)));\n"); fprintf(fid," hold on;\n"); fprintf(fid," semilogy(SNR, ber, '-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid," semilogy(SNR, ber_qpsk,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid," hold off;\n"); fprintf(fid," xlabel('SNR [dB]');\n"); fprintf(fid," ylabel('Bit Error Rate');\n"); fprintf(fid," axis([%f SNR(end)+5 1e-6 1]);\n", SNRdB_min); fprintf(fid," grid on;\n"); fprintf(fid," legend('Measured','Uncoded QPSK','location','southwest');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," semilogy(SNR, per,'-o', 'LineWidth',2, 'MarkerSize',2);\n"); fprintf(fid," xlabel('SNR [dB]');\n"); fprintf(fid," ylabel('Packet Error Rate');\n"); fprintf(fid," axis([%f SNR(end)+5 1e-3 1]);\n", SNRdB_min); fprintf(fid," grid on;\n"); fclose(fid); printf("results written to %s\n", OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/qpilotsync_example.c000066400000000000000000000133511474751757600215260ustar00rootroot00000000000000// Demonstrate using qpilotsync for carrier recovery. #include #include #include #include #include #include #include #include "liquid.h" void usage() { printf("%s [options]\n", __FILE__); printf(" h : print usage\n"); printf(" n : payload length [symbols], default: 400\n"); printf(" p : pilot spacing [symbols], default: 20\n"); printf(" s : SNR [dB], default: 20\n"); printf(" m : modulation scheme, default: qam16\n"); liquid_print_modulation_schemes(); } int main(int argc, char *argv[]) { //srand( time(NULL) ); // options int ms = LIQUID_MODEM_QAM16; // mod. scheme unsigned int payload_len = 400; // payload length unsigned int pilot_spacing = 20; // pilot spacing float SNRdB = 20.0f; // signal-to-noise ratio [dB] const char filename[] = "qpilotsync_example.m"; // output filename float dphi = -0.0075f; // carrier frequency offset float phi = 2.1800f; // carrier phase offset float gain = 0.5f; // channel gain // get options int dopt; while((dopt = getopt(argc,argv,"hn:p:s:m:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'n': payload_len = atoi(optarg); break; case 'p': pilot_spacing = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); break; default: exit(-1); } } unsigned int i; // derived values float nstd = powf(10.0f, -SNRdB/20.0f); // create pilot generator and synchronizer objects qpilotgen pg = qpilotgen_create( payload_len, pilot_spacing); qpilotsync ps = qpilotsync_create(payload_len, pilot_spacing); qpilotgen_print(pg); // get frame length unsigned int frame_len = qpilotgen_get_frame_len(pg); // allocate arrays unsigned char payload_sym_tx[payload_len]; // transmitted payload symbols float complex payload_tx [payload_len]; // transmitted payload samples float complex frame_tx [frame_len]; // transmitted frame samples float complex frame_rx [frame_len]; // received frame samples float complex payload_rx [payload_len]; // received payload samples unsigned char payload_sym_rx[payload_len]; // received payload symbols // create modem objects for payload modemcf mod = modemcf_create(ms); modemcf dem = modemcf_create(ms); // assemble payload symbols for (i=0; i #include #include #include "liquid.h" float utility(float _v, void * _context) { float v_opt = *(float*)(_context); float v = _v - v_opt; return tanhf(v)*tanhf(v); } int main() { // create qs1dsearch object float v_opt = 0.0f; qs1dsearch q = qs1dsearch_create(utility, &v_opt, LIQUID_OPTIM_MINIMIZE); //qs1dsearch_init_bounds(q, -20, 10); qs1dsearch_init(q, -50); // run search unsigned int i; for (i=0; i<32; i++) { qs1dsearch_step(q); qs1dsearch_print(q); } // print results printf("%3u : u(%12.8f) = %12.4e, v_opt=%12.4e (error=%12.4e)\n", i, qs1dsearch_get_opt_v(q), qs1dsearch_get_opt_u(q), v_opt, v_opt - qs1dsearch_get_opt_v(q)); qs1dsearch_destroy(q); return 0; } liquid-dsp-1.7.0/examples/quantize_example.c000066400000000000000000000067741474751757600211740ustar00rootroot00000000000000// // quantize_example.c // // Demonstrates the quantizer/compander combo. // #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "quantize_example.m" // print usage/help message void usage() { printf("quantize_example [options]\n"); printf(" u/h : print usage\n"); printf(" b : number of bits, 0 < b <= 16 [default: 4]\n"); printf(" m : mu, compression factor, mu > 0 [default: 255.0]\n"); } int main(int argc, char*argv[]) { unsigned int num_bits=4; float mu = 255.0f; unsigned int num_samples = 64; int dopt; while ((dopt = getopt(argc,argv,"uhb:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'b': num_bits = atoi(optarg); break; case 'm': mu = atof(optarg); break; default: exit(1); } } // validate input if (num_bits > 16 || num_bits < 1) { fprintf(stderr,"error: %s, quantizer bits must be in [1,16]\n", argv[0]); exit(1); } else if (mu < 0.0f) { fprintf(stderr,"error: %s, mu must be greater than 0\n", argv[0]); exit(1); } unsigned int i; float x[num_samples]; float y[num_samples]; float v; // compressed sample unsigned int q; // quantized sample float u; // uncompressed sample float e; // error float rmse = 0.0f; printf(" input ADC output\n"); printf(" ----- --- ------\n"); float phi = 0.0f; float dphi = 0.02f * 256.0f / (float) num_samples; for (i=0; i 0x%4.4x > %12.8f\n", i, x[i], q, y[i]); } rmse = sqrtf(rmse / (float)num_samples); printf("-----------------------\n"); printf("rmse : %12.4e\n", rmse); // open debug file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"num_samples = %u;\n", num_samples); for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "random_histogram_example.m" // print usage/help message void usage() { printf("random_histogram_example [options]\n"); printf(" -h : print usage\n"); printf(" -N : number of trials\n"); printf(" -n : number of histogram bins\n"); printf(" -d : distribution: {uniform, normal, exp, weib, gamma, nak, rice}\n"); printf(" -u : u UNIFORM: lower edge\n"); printf(" -v : v UNIFORM: upper edge\n"); printf(" -e : eta NORMAL: mean\n"); printf(" -s : sigma NORMAL: standard deviation\n"); printf(" -l : lambda EXPONENTIAL: decay factor\n"); printf(" -a : alpha WEIBULL: shape\n"); printf(" -b : beta WEIBULL: spread\n"); printf(" -g : gamma WEIBULL: threshold\n"); printf(" -A : alpha GAMMA: shape\n"); printf(" -B : beta GAMMA: spread\n"); printf(" -m : m NAKAGAMI: shape\n"); printf(" -o : omega NAKAGAMI: spread\n"); printf(" -K : K RICE-K: spread\n"); printf(" -O : omega RICE-K: spread\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); unsigned long int num_trials = 100000; // number of trials unsigned int num_bins = 30; enum { UNIFORM=0, NORMAL, EXPONENTIAL, WEIBULL, GAMMA, NAKAGAMIM, RICEK } distribution=NORMAL; // distribution parameters float u = 0.0f; // UNIFORM: lower edge float v = 1.0f; // UNIFORM: upper edge float eta = 0.0f; // NORMAL: mean float sigma = 1.0f; // NORMAL: standard deviation float lambda = 3.0f; // EXPONENTIAL: decay factor float alphaw = 1.0f; // WEIBULL: shape float betaw = 1.0f; // WEIBULL: spread float gammaw = 1.0f; // WEIBULL: threshold float alphag = 4.5f; // GAMMA: shape float betag = 1.0f; // GAMMA: spread float m = 4.5f; // NAKAGAMI: shape factor float omeganak = 1.0f; // NAKAGMAI: spread factor float K = 4.0f; // RICE-K: K-factor (shape) float omegarice = 1.0f; // RICE-K: spread factor int dopt; while ((dopt = getopt(argc,argv,"hN:n:d:u:v:e:s:l:a:b:g:A:B:m:o:K:O:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'N': num_trials = atoi(optarg); break; case 'n': num_bins = atoi(optarg); break; case 'd': if (strcmp(optarg,"uniform")==0) distribution = UNIFORM; else if (strcmp(optarg,"normal")==0) distribution = NORMAL; else if (strcmp(optarg,"exp")==0) distribution = EXPONENTIAL; else if (strcmp(optarg,"weib")==0) distribution = WEIBULL; else if (strcmp(optarg,"gamma")==0) distribution = GAMMA; else if (strcmp(optarg,"nak")==0) distribution = NAKAGAMIM; else if (strcmp(optarg,"rice")==0) distribution = RICEK; else { fprintf(stderr,"error: %s, unknown/unsupported distribution '%s'\n", argv[0], optarg); exit(1); } case 'u': u = atof(optarg); break; case 'v': v = atof(optarg); break; case 'e': eta = atof(optarg); break; case 's': sigma = atof(optarg); break; case 'l': lambda = atof(optarg); break; case 'a': alphaw = atof(optarg); break; case 'b': betaw = atof(optarg); break; case 'g': gammaw = atof(optarg); break; case 'A': alphag = atof(optarg); break; case 'B': betag = atof(optarg); break; case 'm': m = atof(optarg); break; case 'o': omeganak = atof(optarg); break; case 'K': K = atof(optarg); break; case 'O': omegarice = atof(optarg); break; default: exit(1); } } // validate input if (num_bins == 0) { fprintf(stderr,"error: %s, number of bins must be greater than zero\n", argv[0]); exit(1); } else if (num_trials == 0) { fprintf(stderr,"error: %s, number of trials must be greater than zero\n", argv[0]); exit(1); } float xmin = 0.0f; float xmax = 1.0f; unsigned long int i; // make a guess at the histogram range so we don't need to // store all the generated random variables in a giant array. if (distribution == UNIFORM) { xmin = u - 0.08*(v-u); // lower edge less 8% range xmax = v + 0.08*(v-u); // upper edge plus 8% range } else if (distribution == NORMAL) { xmin = eta - 4.0f*sigma; xmax = eta + 4.0f*sigma; } else if (distribution == EXPONENTIAL) { xmin = 0.0f; xmax = 7.0f / lambda; } else if (distribution == WEIBULL) { xmin = gammaw; xmax = gammaw + betaw*powf( -logf(1e-3f), 1.0f/alphaw ); } else if (distribution == GAMMA) { xmin = 0.0f; xmax = 6.5 * betag + 2.0*alphag; } else if (distribution == NAKAGAMIM) { xmin = 0.0f; xmax = 1.5f*( powf(omeganak, 0.8f) + 1.0f/m ); } else if (distribution == RICEK) { xmin = 0.0f; xmax = 3.0f*logf(omegarice+1.0f) + 1.5f/(K+1.0f); } else { fprintf(stderr, "error: %s, unknown/unsupported distribution\n", argv[0]); exit(1); } // //float xspan = xmax - xmin; float bin_width = (xmax - xmin) / (num_bins); // initialize histogram unsigned int hist[num_bins]; for (i=0; i= num_bins) index = num_bins-1; hist[index]++; // update statistics m1 += x; // first moment m2 += x*x; // second moment } // m1 /= (float)num_trials; m2 /= (float)num_trials; // compute expected distribution unsigned int num_steps = 100; float xstep = (xmax - xmin) / (num_steps - 1); float f[num_steps]; float F[num_steps]; for (i=0; i hist_max ? hist[i] : hist_max; printf("%8s : %6s [%6s]\n", "x", "count", "prob."); for (i=0; i #include "liquid.h" // print symbol to screen, one bit at a time void print_symbol(unsigned char _sym, unsigned int _bits_per_symbol) { unsigned int i; unsigned int n; // shift amount for (i=0; i<_bits_per_symbol; i++) { n = _bits_per_symbol - i - 1; printf("%c", (_sym >> n) & 0x01 ? '1' : '0'); } } // print symbol array to screen void print_symbol_array(unsigned char * _sym, unsigned int _bits_per_symbol, unsigned int _num_symbols) { unsigned int i; for (i=0; i<_num_symbols; i++) { print_symbol(_sym[i], _bits_per_symbol); printf("%c", i < _num_symbols-1 ? ',' : '\n'); } } int main() { // input symbols: 111 000 111 // expected output: 11 10 00 11 1(0) unsigned char input[3] = { 0x07, // 111 0x00, // 000 0x07 // 111(0) }; // allocate memory for output array unsigned char output[5]; unsigned int N; // print input symbol array printf("input symbols: "); print_symbol_array(input,3,3); // repack bytes into output array liquid_repack_bytes( input, 3, 3, output, 2, 5, &N ); // print output array printf("output symbols: "); print_symbol_array(output,2,5); return 0; } liquid-dsp-1.7.0/examples/resamp2_cccf_example.c000066400000000000000000000117651474751757600216570ustar00rootroot00000000000000// // resamp2_cccf_example.c // // This example demonstrates the halfband resampler cenetered at the // quarter sample rate to split the signal into positive and negative // frequency bands. Two distinct narrow-band signals are generated; one // at a positive frequency and one at a negative frequency. The resamp2 // object is run as a filter to separate the two about the zero- // frequency center point. // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_cccf_example.m" int main() { unsigned int m = 12; // filter semi-length (actual length: 4*m+1) float As = 60.0f; // stop-band attenuation [dB] unsigned int num_samples = 400; // number of input samples unsigned int i; // allocate memory for data arrays float complex x [num_samples]; // input signal float complex y0[num_samples]; // float complex y1[num_samples]; // // generate the two signals iirfilt_crcf lowpass = iirfilt_crcf_create_lowpass(6,0.02); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_decim_example.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" h : print help\n"); printf(" m : filter semi-length, default: 5\n"); printf(" s : filter stop-band attenuation, default: 60 dB\n"); printf(" w : pulse bandwidth, default: 0.4\n"); } int main(int argc, char*argv[]) { unsigned int m = 12; // filter semi-length float As = 60.0f; // stop-band attenuation [dB] float bw = 0.1f; // pulse bandwidth int dopt; while ((dopt = getopt(argc,argv,"hm:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'w': bw = atof(optarg); break; default: exit(1); } } unsigned int i; // allocate arrays unsigned int w_len = 43; // pulse length unsigned int num_samples = w_len + 2*m; float complex x[2*num_samples]; // input array float complex y[ num_samples]; // output array // generate input float w[w_len]; liquid_firdes_kaiser(w_len,bw,60.0f,0.0f,w); for (i=0; i<2*num_samples; i++) x[i] = i < w_len ? w[i] : 0.0f; // create/print the half-band resampler resamp2_crcf q = resamp2_crcf_create(m,0,As); resamp2_crcf_print(q); unsigned int delay = resamp2_crcf_get_delay(q); // run the resampler for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_example.m" int main() { unsigned int m=5; // filter semi-length (actual length: 4*m+1) float bw=0.13f; // input signal bandwidth float fc=-0.597f; // input signal carrier frequency (radians/sample) unsigned int num_samples=37; // number of input samples float As=60.0f; // stop-band attenuation [dB] unsigned int i; // derived values unsigned int n = num_samples + 2*m + 1; // adjusted input sequence length // allocate memory for data arrays float complex x[ n]; float complex y[2*n]; float complex z[ n]; // generate the baseband signal (filter pulse) float h[num_samples]; liquid_firdes_kaiser(num_samples,bw,60.0f,0.0f,h); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_filter_example.m" int main() { unsigned int m=9; // filter semi-length unsigned int num_samples=128; // number of input samples float As=60.0f; // stop-band attenuation [dB] // derived values unsigned int h_len = 4*m+1; // half-band filter length unsigned int N = num_samples + h_len; // arrays float complex x[N]; // input time series float complex y0[N]; // output time series (lower band) float complex y1[N]; // output time series (upper band) // generate input sequence unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_interp_example.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" h : print help\n"); printf(" m : filter semi-length, default: 5\n"); printf(" s : filter stop-band attenuation, default: 60 dB\n"); printf(" w : pulse bandwidth, default: 0.4\n"); } int main(int argc, char*argv[]) { unsigned int m = 12; // filter semi-length float As = 60.0f; // stop-band attenuation [dB] float bw = 0.2f; // pulse bandwidth int dopt; while ((dopt = getopt(argc,argv,"hm:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 's': As = atof(optarg); break; case 'w': bw = atof(optarg); break; default: exit(1); } } unsigned int i; // allocate arrays unsigned int w_len = 37; // pulse length unsigned int num_samples = w_len + 2*m; float complex x[ num_samples]; // input array float complex y[2*num_samples]; // output array // generate input float w[w_len]; liquid_firdes_kaiser(w_len,bw,60.0f,0.0f,w); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp_crcf_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf(" -h : print help\n"); printf(" -r : resampling rate (output/input), default: 1.1\n"); printf(" -m : filter semi-length (delay), default: 13\n"); printf(" -b : filter bandwidth, 0 < b < 0.5, default: 0.4\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); printf(" -p : filter bank size, default: 64\n"); printf(" -n : number of input samples, default: 400\n"); printf(" -f : input signal frequency, default: 0.044\n"); } int main(int argc, char*argv[]) { // options float r = 1.1f; // resampling rate (output/input) unsigned int m = 13; // resampling filter semi-length (filter delay) float As = 60.0f; // resampling filter stop-band attenuation [dB] float bw = 0.45f; // resampling filter bandwidth unsigned int npfb = 64; // number of filters in bank (timing resolution) unsigned int n = 400; // number of input samples float fc = 0.044f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:m:b:s:p:n:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 'm': m = atoi(optarg); break; case 'b': bw = atof(optarg); break; case 's': As = atof(optarg); break; case 'p': npfb = atoi(optarg); break; case 'n': n = atoi(optarg); break; case 'f': fc = atof(optarg); break; default: exit(1); } } // validate input if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]); exit(1); } else if (m == 0) { fprintf(stderr,"error: %s, filter semi-length must be greater than zero\n", argv[0]); exit(1); } else if (bw == 0.0f || bw >= 0.5f) { fprintf(stderr,"error: %s, filter bandwidth must be in (0,0.5)\n", argv[0]); exit(1); } else if (As < 0.0f) { fprintf(stderr,"error: %s, filter stop-band attenuation must be greater than zero\n", argv[0]); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: %s, filter bank size must be greater than zero\n", argv[0]); exit(1); } else if (n == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // number of input samples (zero-padded) unsigned int nx = n + m; // output buffer with extra padding for good measure unsigned int y_len = (unsigned int) ceilf(1.1 * nx * r) + 4; // arrays float complex x[nx]; float complex y[y_len]; // create resampler resamp_crcf q = resamp_crcf_create(r,m,bw,As,npfb); resamp_crcf_print(q); // generate input signal float wsum = 0.0f; for (i=0; i Ypeak || i==0) { Ypeak = Ymag; fpeak = f; } // find peak side-lobe value, ignoring frequencies // within a certain range of signal frequency if ( fabsf(f-fy) > main_lobe_width ) max_sidelobe = Ymag > max_sidelobe ? Ymag : max_sidelobe; } // print results and check frequency location printf(" desired resampling rate : %12.8f\n", r); printf(" measured resampling rate : %12.8f (%u/%u)\n", r_actual, ny, nx); printf(" peak spectrum : %12.8f dB (expected 0.0 dB)\n", Ypeak); printf(" peak frequency : %12.8f (expected %-12.8f)\n", fpeak, fy); printf(" max sidelobe : %12.8f dB (expected at least %.2f dB)\n", max_sidelobe, -As); // export results FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n",OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"m=%u;\n", m); fprintf(fid,"npfb=%u;\n", npfb); fprintf(fid,"r=%12.8f;\n", r); fprintf(fid,"n=%u;\n", n); fprintf(fid,"nx = %u;\n", nx); fprintf(fid,"x = zeros(1,nx);\n"); for (i=0; i1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"subplot(4,1,3:4);\n"); fprintf(fid," plot(fx,X,'Color',[0.5 0.5 0.5],fy,Y,'LineWidth',2);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('normalized frequency');\n"); fprintf(fid," ylabel('PSD [dB]');\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," axis([-0.5 0.5 -120 20]);\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/resamp_crcf_noise_example.c000066400000000000000000000113611474751757600230010ustar00rootroot00000000000000// // resamp_crcf_noise_example.c // // Demonstration of resamp object whereby an input noise signal // is resampled at a rate 'r'. // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp_crcf_noise_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf(" -h : print help\n"); printf(" -r : resampling rate, default: 0.6\n"); printf(" -m : filter semi-length (delay), default: 25\n"); printf(" -w : filter bandwidth, default: 0.51*rate\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); } int main(int argc, char*argv[]) { // options float rate= 0.60f; // resampling rate unsigned int m = 25; // resampling filter semi-length (filter delay) float bw = -1; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hr:m:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': rate = atof(optarg); break; case 'm': m = atoi(optarg); break; case 'w': bw = atof(optarg); break; case 's': As = atof(optarg); break; default: exit(1); } } // validate input if (rate >= 1.0f) { fprintf(stderr,"error: %s, input rate r must be less than 1\n", argv[0]); exit(1); } // set default bandwidth if not otherwise specified if (bw < 0) bw = 0.35f*rate; // create resampler object resamp_crcf q = resamp_crcf_create(rate,m,bw,As,256); //resamp_crcf_print(q); // number of sample blocks unsigned int num_blocks = 1000; // arrays unsigned int buf_len = 1024; float complex buf_x[ buf_len]; float complex buf_y[2*buf_len]; // create signal generator (wide-band noise) msourcecf gen = msourcecf_create_default(); // in-band signal msourcecf_add_noise(gen, 0.0f, 0.5f*rate, 0); // high-power signal just out of band msourcecf_add_noise(gen, (0.5f*rate+0.04f), 0.02f, 10); // create spectral periodogram objects unsigned int nfft = 2400; spgramcf px = spgramcf_create_default(nfft); spgramcf py = spgramcf_create_default(nfft); // generate input signal (filtered noise) unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options float r = 1.618034; // true resampling rate (output/input) offset unsigned int num_blocks = 400; // number of blocks to simulate unsigned int block_len = 256; // number of samples in block float alpha = 0.1f; // loop bandwidth factor const char filename[] = "resamp_crcf_rate_match_example.m"; // output filename // buffers float complex buf_0[2*block_len]; // original float complex buf_1[2*block_len]; // resampled float complex buf_2[2*block_len]; // recovered memset(buf_0, 0x00, block_len*sizeof(float complex)); // create resamplers resamp_crcf resamp_0 = resamp_crcf_create_default(r); resamp_crcf resamp_1 = resamp_crcf_create_default(1); // run loop and print results unsigned int i; float log_error = 0.0f; // accumulated log error float rate = 1.0f; char buf_str[200]; FILE * fid = fopen(filename,"w"); fprintf(fid,"clear all; close all;\nv=[\n"); printf("# %8s %8s %8s %12s %12s %12s\n", "blk len", "num in", "num out", "rate in", "rate out", "rate all"); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ricek_channel_example.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" h : print help\n"); printf(" n : number of samples\n"); printf(" f : maximum doppler frequency (0,0.5)\n"); printf(" K : Rice K factor, linear, greater than zero\n"); printf(" O : mean power, linear (Rice-K distribution 'omega')\n"); } int main(int argc, char*argv[]) { // options unsigned int h_len = 51; // doppler filter length float fd = 0.1f; // maximum doppler frequency float K = 2.0f; // Rice fading factor float omega = 1.0f; // mean power float theta = 0.0f; // angle of arrival unsigned int num_samples=1200; // number of samples int dopt; while ((dopt = getopt(argc,argv,"hn:f:K:O:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': num_samples = atoi(optarg); break; case 'f': fd = atof(optarg); break; case 'K': K = atof(optarg); break; case 'O': omega = atof(optarg); break; default: exit(1); } } // validate input if (K < 0.0f) { fprintf(stderr,"error: %s, fading factor K must be greater than zero\n", argv[0]); exit(1); } else if (omega < 0.0f) { fprintf(stderr,"error: %s, signal power Omega must be greater than zero\n", argv[0]); exit(1); } else if (fd <= 0.0f || fd >= 0.5f) { fprintf(stderr,"error: %s, Doppler frequency must be in (0,0.5)\n", argv[0]); exit(1); } else if (h_len < 4) { fprintf(stderr,"error: %s, Doppler filter length too small\n", argv[0]); exit(1); } else if (num_samples == 0) { fprintf(stderr,"error: %s, number of samples must be greater than zero\n", argv[0]); exit(1); } unsigned int i; // allocate array for output samples float complex * y = (float complex*) malloc(num_samples*sizeof(float complex)); // generate Doppler filter coefficients float h[h_len]; liquid_firdes_doppler(h_len, fd, K, theta, h); // normalize filter coefficients such that output Gauss random // variables have unity variance float std = 0.0f; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "rresamp_crcf_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf("Resample a signal at a rate interp/decim\n"); printf(" -h : print help\n"); printf(" -P : interpolation rate, default: 5\n"); printf(" -Q : decimation rate, default: 3\n"); printf(" -m : filter semi-length (delay), default: 12\n"); printf(" -w : filter bandwidth, default: -1\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); } int main(int argc, char*argv[]) { // options unsigned int interp = 3; // output rate (interpolation factor) unsigned int decim = 5; // input rate (decimation factor) unsigned int m = 20; // resampling filter semi-length (filter delay) float bw = -1.0f; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hP:Q:m:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'P': interp = atoi(optarg); break; case 'Q': decim = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'w': bw = atof(optarg); break; case 's': As = atof(optarg); break; default: exit(1); } } // validate input if (interp == 0 || interp > 1000) { fprintf(stderr,"error: %s, interpolation rate must be in [1,1000]\n", argv[0]); exit(1); } else if (decim == 0 || decim > 1000) { fprintf(stderr,"error: %s, decimation rate must be in [1,1000]\n", argv[0]); exit(1); } // create resampler object rresamp_crcf q = rresamp_crcf_create_kaiser(interp,decim,m,bw,As); if (q == NULL) return -1; rresamp_crcf_print(q); float rate = rresamp_crcf_get_rate(q); // number of sample blocks (limit by large interp/decim rates) unsigned int n = 120e3 / (interp > decim ? interp : decim); // input/output buffers float complex buf_x[decim ]; // input float complex buf_y[interp]; // output // create signal generator (wide-band noise and tone) float noise_bw = 0.7f * (rate > 1.0 ? 1.0 : rate); msourcecf gen = msourcecf_create_default(); msourcecf_add_noise(gen, 0.0f, noise_bw, 0); msourcecf_add_tone (gen, rate > 1.0 ? 0.4 : noise_bw, 0.00f, 20); // create spectral periodogram objects unsigned int nfft = 2400; spgramcf px = spgramcf_create_default(nfft); spgramcf py = spgramcf_create_default(nfft); // generate input signal (filtered noise) unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "rresamp_crcf_partition_example.m" int main(int argc, char*argv[]) { // options unsigned int P = 4; // output rate (interpolation factor) unsigned int Q = 5; // input rate (decimation factor) unsigned int m = 8; // resampling filter semi-length (filter delay) float bw = 0.5f; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] unsigned int n = 10; // block size // create two identical resampler objects rresamp_crcf q0 = rresamp_crcf_create_kaiser(P,Q,m,bw,As); rresamp_crcf q1 = rresamp_crcf_create_kaiser(P,Q,m,bw,As); // full input, output buffers float complex buf_in [2*Q*n]; // input buffer float complex buf_out_0[2*P*n]; // output, normal resampling operation float complex buf_out_1[2*P*n]; // output, partitioned into 2 blocks // generate input signal (pulse) unsigned int i; for (i=0; i<2*Q*n; i++) buf_in[i] = liquid_hamming(i,2*Q*n) * cexpf(_Complex_I*2*M_PI*0.037f*i); // run resampler normally in one large block (2*Q*n inputs, 2*P*n outputs) rresamp_crcf_execute_block(q0, buf_in, 2*n, buf_out_0); // reset and run with separate resamplers (e.g. in two threads) rresamp_crcf_reset(q0); // first block runs as normal rresamp_crcf_execute_block(q0, buf_in, n, buf_out_1); // initialize second block with Q*m samples to account for delay for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "rresamp_crcf_rnyquist_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf("Resample a signal at a rate P/Q\n"); printf(" -h : print help\n"); printf(" -P : decimation (output) rate, default: 3\n"); printf(" -Q : interpolation (input) rate, default: 5\n"); printf(" -m : filter semi-length (delay), default: 12\n"); printf(" -b : filter excess bandwidth factor, default: 0.2\n"); } int main(int argc, char*argv[]) { // options unsigned int P = 5; // output rate (interpolation factor) unsigned int Q = 4; // input rate (decimation factor) unsigned int m = 15; // resampling filter semi-length (filter delay) float beta= 0.15f; // filter excess bandwidth factor unsigned int num_symbols = 800; // number of symbols to generate int dopt; while ((dopt = getopt(argc,argv,"hP:Q:m:b:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'P': P = atoi(optarg); break; case 'Q': Q = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; default: exit(1); } } // validate input if (P == 0 || P > 1000) { fprintf(stderr,"error: %s, input rate P must be in [1,1000]\n", argv[0]); exit(1); } else if (Q == 0 || Q > 1000) { fprintf(stderr,"error: %s, output rate Q must be in [1,1000]\n", argv[0]); exit(1); } else if (Q > P) { fprintf(stderr,"error: %s, this example requires P > Q (interpolation)\n", argv[0]); exit(1); } // create resampler objects rresamp_crcf q0 = rresamp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,P,Q,m,beta); rresamp_crcf q1 = rresamp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,Q,P,m,beta); rresamp_crcf_print(q0); // input/output buffers float complex buf_x[Q]; // input float complex buf_y[P]; // interp float complex buf_z[Q]; // decim // generate input symbols unsigned int i, n = 0; FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"x = []; y = []; z = [];\n"); float g = M_SQRT1_2; while (n < num_symbols) { n += Q; if (n > num_symbols-2*m) g = 0; // generate symbols for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "rresamp_rrrf_example.m" // print usage/help message void usage() { printf("Usage: %s [OPTION]\n", __FILE__); printf("Resample a signal at a rate P/Q\n"); printf(" -h : print help\n"); printf(" -P : decimation (output) rate, default: 3\n"); printf(" -Q : interpolation (input) rate, default: 5\n"); printf(" -m : filter semi-length (delay), default: 12\n"); printf(" -w : filter bandwidth, default: 0.5f\n"); printf(" -s : filter stop-band attenuation [dB], default: 60\n"); } int main(int argc, char*argv[]) { // options unsigned int P = 3; // output rate (interpolation factor) unsigned int Q = 5; // input rate (decimation factor) unsigned int m = 12; // resampling filter semi-length (filter delay) float bw = 0.5f; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] int dopt; while ((dopt = getopt(argc,argv,"hP:Q:m:s:w:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'P': P = atoi(optarg); break; case 'Q': Q = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'w': bw = atof(optarg); break; case 's': As = atof(optarg); break; default: exit(1); } } // validate input if (P == 0 || P > 1000) { fprintf(stderr,"error: %s, input rate P must be in [1,1000]\n", argv[0]); exit(1); } else if (Q == 0 || Q > 1000) { fprintf(stderr,"error: %s, output rate Q must be in [1,1000]\n", argv[0]); exit(1); } // create resampler object rresamp_rrrf q = rresamp_rrrf_create_kaiser(P,Q,m,bw,As); rresamp_rrrf_print(q); float rate = rresamp_rrrf_get_rate(q); // number of sample blocks (limit by large interp/decim rates) unsigned int n = 120e3 / (P > Q ? P : Q); // input/output buffers float buf_x[Q]; // input float buf_y[P]; // output // create wide-band noise source with one-sided cut-off frequency iirfilt_rrrf lowpass = iirfilt_rrrf_create_lowpass(15, 0.7f*0.5f*(rate > 1.0 ? 1.0 : rate)); // create spectral periodogram objects unsigned int nfft = 2400; spgramf px = spgramf_create_default(nfft); spgramf py = spgramf_create_default(nfft); // generate input signal (filtered noise) unsigned int i, j; for (i=0; i #include #include #include #include "liquid.h" float compute_entropy(unsigned char * _x, unsigned int _n); int main() { unsigned int n=32; // number of data bytes unsigned char x[n]; // input data unsigned char y[n]; // scrambled data unsigned char z[n]; // unscrambled data unsigned int i; // generate data for (i=0; i> j) & 0x01 ]++; // b:2 for (j=0; j<8; j+=2) c2[ (_x[i] >> j) & 0x03 ]++; // b:4 for (j=0; j<8; j+=4) c4[ (_x[i] >> j) & 0x0f ]++; // b:8 c8[ _x[i] ]++; } // compute entropy float H1 = 0.0f; float H2 = 0.0f; float H4 = 0.0f; float H8 = 0.0f; float p; for (i=0; i<2; i++) { p = (float) c1[i] / (float)(8*_n); H1 -= p * log2f(p+1e-12f); } H1 /= 1.0f; for (i=0; i<4; i++) { p = (float) c2[i] / (float)(4*_n); H2 -= p * log2f(p+1e-12f); } H2 /= 2.0f; for (i=0; i<16; i++) { p = (float) c4[i] / (float)(2*_n); H4 -= p * log2f(p+1e-12f); } H4 /= 4.0f; for (i=0; i<256; i++) { p = (float) c8[i] / (float)(_n); H8 -= p * log2f(p+1e-12f); } H8 /= 8.0f; #if 0 printf("H1 : %12.8f\n", H1); printf("H2 : %12.8f\n", H2); printf("H4 : %12.8f\n", H4); printf("H8 : %12.8f\n", H8); #endif // not sure if product is truly the entropy, but // it is a fair assessment return H1 * H2 * H4 * H8; } liquid-dsp-1.7.0/examples/smatrix_example.c000066400000000000000000000111041474751757600210020ustar00rootroot00000000000000// test sparse matrix operations #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { #if 0 unsigned int M = 12; unsigned int N = 16; // create empty list smatrixb q = smatrixb_create(M,N); // set value(s) smatrixb_set(q,1,2, 1); smatrixb_set(q,2,2, 1); smatrixb_set(q,2,3, 1); smatrixb_set(q,2,7, 1); smatrixb_set(q,2,8, 1); smatrixb_set(q,2,11, 1); smatrixb_delete(q,2,2); printf("\ncompact form:\n"); smatrixb_print(q); printf("\nexpanded form:\n"); smatrixb_print_expanded(q); printf("\ncertain values:\n"); printf(" A[%2u,%2u] = %1u\n", 1, 1, smatrixb_get(q,1,1)); printf(" A[%2u,%2u] = %1u\n", 1, 2, smatrixb_get(q,1,2)); // generate vectors unsigned char x[N]; unsigned char y[M]; unsigned int i; unsigned int j; for (j=0; j #include #include #include "liquid.h" #define OUTPUT_FILENAME "spgramcf_example.m" int main() { // spectral periodogram options unsigned int nfft = 1024; // spectral periodogram FFT size unsigned int num_samples = 2e6; // number of samples float noise_floor = -60.0f; // noise floor [dB] unsigned int i; // derived values float nstd = powf(10.0f, noise_floor/20.0f); // create spectral periodogram spgramcf q = spgramcf_create_default(nfft); spgramcf_print(q); // generate signal (band-pass filter with Hilbert transform) iirfilt_rrrf filter = iirfilt_rrrf_create_prototype( LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, 9, 0.17f, 0.20f, 0.1f, 60.0f); firhilbf ht = firhilbf_create(13,60.0f); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "spgramf_example.m" int main() { // spectral periodogram options unsigned int nfft = 1024; // spectral periodogram FFT size unsigned int num_samples = 1e6; // number of samples float noise_floor = -60.0f; // noise floor [dB] unsigned int i; // derived values float nstd = powf(10.0f, noise_floor/20.0f); // create spectral periodogram spgramf q = spgramf_create_default(nfft); spgramf_print(q); // generate signal (band-pass filter) iirfilt_rrrf filter = iirfilt_rrrf_create_prototype( LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_SOS, 9, 0.17f, 0.20f, 0.1f, 60.0f); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "spwaterfallcf_waterfall_example.gnu" int main() { // spectral periodogram options unsigned int nfft = 1800; // spectral periodogram FFT size unsigned int time = 1000; // minimum time buffer unsigned int num_samples = 2e6; // number of samples // create spectral waterfall object spwaterfallcf periodogram = spwaterfallcf_create_default(nfft,time); spwaterfallcf_print(periodogram); // create stream generator msourcecf gen = msourcecf_create_default(); // add noise source (wide band) msourcecf_add_noise(gen, 0.0f, 1.00f, -40); // add noise source (narrow-band, pulsed) int id_noise = msourcecf_add_noise(gen, 0.4f, 0.10f, -20); // add tone msourcecf_add_tone(gen, -0.4f, 0.0f, 0); // add fsk modem msourcecf_add_fsk(gen, -0.35f, 0.03f, -30.0f, 2, 500); // add chirp signal msourcecf_add_chirp(gen, 0.17f, 0.10f, -50, 250e3, 0, 0); // add modulated data msourcecf_add_modem(gen, -0.1f, 0.15f, -10, LIQUID_MODEM_QPSK, 12, 0.25); // create buffers unsigned int buf_len = 64; float complex buf[buf_len]; // generate signals and push through spwaterfall object unsigned int total_samples = 0; int state = 1; while (total_samples < num_samples) { // write samples to buffer msourcecf_write_samples(gen, buf, buf_len); // push resulting samples through waterfall object spwaterfallcf_write(periodogram, buf, buf_len); // accumulated samples total_samples += buf_len; // update state for noise source if (state == 0 && randf() < 1e-3f) { state = 1; msourcecf_enable(gen, id_noise); //printf("turning noise on\n"); } else if (state == 1 && randf() < 3e-3f) { state = 0; msourcecf_disable(gen, id_noise); //printf("turning noise off\n"); } } // export output files spwaterfallcf_set_rate (periodogram,100e6); spwaterfallcf_set_freq (periodogram,750e6); spwaterfallcf_set_dims (periodogram,1200, 800); spwaterfallcf_set_commands(periodogram,"set cbrange [-45:25]; set title 'waterfall'"); spwaterfallcf_export(periodogram,"spwaterfallcf_example"); // destroy objects msourcecf_destroy(gen); spwaterfallcf_destroy(periodogram); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/symstreamcf_delay_example.c000066400000000000000000000035361474751757600230400ustar00rootroot00000000000000// show delay in symstream object #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symstreamcf_delay_example.m" int main() { // symstream parameters int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int k = 4; unsigned int m = 9; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); unsigned int delay = symstreamcf_get_delay(gen); unsigned int buf_len = 100; float complex buf[2*buf_len]; // write samples to buffer symstreamcf_write_samples(gen, buf, buf_len); symstreamcf_set_gain(gen, 0.0f); symstreamcf_write_samples(gen, buf+buf_len, buf_len); // destroy objects symstreamcf_destroy(gen); // measure approximate delay; index of first sample with abs > 1 unsigned int i; for (i=0; i<2*buf_len; i++) { if (cabsf(buf[i]) > 1.0f) break; } printf("expected delay: %u, approximate delay: %u\n", delay, i); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u; delay = %u;\n", buf_len, delay); fprintf(fid,"t = [0:(2*n-1)] - delay;\n"); for (i=0; i<2*buf_len; i++) fprintf(fid,"v(%6u) = %12.4e + %12.4ej;\n", i+1, crealf(buf[i]), cimagf(buf[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t, real(v), t, imag(v));\n"); fprintf(fid,"xlabel('Sample Index');\n"); fprintf(fid,"ylabel('Signal Output');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/symstreamcf_example.c000066400000000000000000000044601474751757600216570ustar00rootroot00000000000000// // symstreamcf_example.c // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symstreamcf_example.m" int main() { // symstream parameters int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int k = 4; unsigned int m = 9; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 80000; // number of samples unsigned int i; // create spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); unsigned int buf_len = 1024; float complex buf[buf_len]; // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); symstreamcf_print(gen); unsigned int total_samples = 0; while (total_samples < num_samples) { // write samples to buffer symstreamcf_write_samples(gen, buf, buf_len); // push resulting sample through periodogram spgramcf_write(periodogram, buf, buf_len); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); // compute power spectral density output float psd[nfft]; spgramcf_get_psd(periodogram, psd); // destroy objects symstreamcf_destroy(gen); spgramcf_destroy(periodogram); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "symstreamrcf_delay_example.m" int main() { // symstream parameters int ftype = LIQUID_FIRFILT_ARKAISER; float bw = 0.23456789f; unsigned int m = 8; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; // create stream generator symstreamrcf gen = symstreamrcf_create_linear(ftype,bw,m,beta,ms); float delay = symstreamrcf_get_delay(gen); unsigned int buf_len = 100; float complex buf[2*buf_len]; // write samples to buffer symstreamrcf_write_samples(gen, buf, buf_len); symstreamrcf_set_gain(gen, 0.0f); symstreamrcf_write_samples(gen, buf+buf_len, buf_len); // destroy objects symstreamrcf_destroy(gen); // measure approximate delay; index of first sample with abs > 1 unsigned int i; for (i=0; i<2*buf_len; i++) { if (cabsf(buf[i]) > 1.0f) break; } printf("expected delay: %.3f, approximate delay: %u\n", delay, i); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u; delay = %.6f;\n", buf_len, delay); fprintf(fid,"t = [0:(2*n-1)] - delay;\n"); for (i=0; i<2*buf_len; i++) fprintf(fid,"v(%6u) = %12.4e + %12.4ej;\n", i+1, crealf(buf[i]), cimagf(buf[i])); fprintf(fid,"figure;\n"); fprintf(fid,"plot(t, real(v), t, imag(v));\n"); fprintf(fid,"xlabel('Sample Index');\n"); fprintf(fid,"ylabel('Signal Output');\n"); fprintf(fid,"legend('real','imag');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/symstreamrcf_example.c000066400000000000000000000046051474751757600220420ustar00rootroot00000000000000// demonstrate arbitrary rate symstreamrcf object #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symstreamrcf_example.m" int main() { // symstream parameters int ftype = LIQUID_FIRFILT_ARKAISER; float bw = 0.23456789f; unsigned int m = 9; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 80000; // number of samples spgramcf periodogram = spgramcf_create_default(nfft); // create stream generator symstreamrcf gen = symstreamrcf_create_linear(ftype,bw,m,beta,ms); symstreamrcf_set_gain(gen, sqrtf(bw)); symstreamrcf_print(gen); // create buffer for storing output unsigned int buf_len = 1024; float complex buf[buf_len]; // generate samples unsigned int total_samples = 0; while (total_samples < num_samples) { // write samples to buffer symstreamrcf_write_samples(gen, buf, buf_len); // push resulting sample through periodogram spgramcf_write(periodogram, buf, buf_len); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); // compute power spectral density output float psd[nfft]; spgramcf_get_psd(periodogram, psd); // destroy objects symstreamrcf_destroy(gen); spgramcf_destroy(periodogram); // export output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"H = zeros(1,nfft);\n"); unsigned int i; for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symsync_crcf_example.m" // print usage/help message void usage() { printf("symsync_crcf_example [options]\n"); printf(" h : print help\n"); printf(" k : filter samples/symbol, default: 2\n"); printf(" m : filter delay (symbols), default: 5\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" B : filter polyphase banks, default: 32\n"); printf(" n : number of symbols, default: 400\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k = 2; // samples/symbol (input) unsigned int m = 5; // filter delay (symbols) float beta = 0.5f; // filter excess bandwidth factor unsigned int num_filters = 32; // number of filters in the bank unsigned int num_symbols = 400; // number of data symbols int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:B:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': num_filters = atoi(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (num_filters == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } unsigned int i; // static values liquid_firfilt_type ftype = LIQUID_FIRFILT_ARKAISER; float bandwidth = 0.02f; // loop filter bandwidth float dt = -0.5f; // fractional sample offset // derived values unsigned int num_samples = k*num_symbols; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_symbols + 64]; // synchronized symbols // generate random QPSK symbols for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symsync_crcf_full_example.m" // print usage/help message void usage() { printf("symsync_crcf_full_example [options]\n"); printf(" h : print usage\n"); printf(" T : filter type: [rrcos], rkaiser, arkaiser, hM3, gmsk\n"); printf(" k : filter samples/symbol, default: 2\n"); printf(" K : output samples/symbol, default: 2\n"); printf(" m : filter delay (symbols), default: 5\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" B : filter polyphase banks, default: 32\n"); printf(" s : signal-to-noise ratio, default: 30dB\n"); printf(" w : timing pll bandwidth, default: 0.02\n"); printf(" n : number of symbols, default: 400\n"); printf(" t : timing phase offset [%% symbol], t in [-0.5,0.5], default: -0.2\n"); printf(" r : timing freq. offset [%% symbol], default: 1.000\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k = 2; // samples/symbol (input) unsigned int k_out = 2; // samples/symbol (output) unsigned int m = 5; // filter delay (symbols) float beta = 0.5f; // filter excess bandwidth factor unsigned int num_filters = 32; // number of filters in the bank unsigned int num_symbols = 400; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio // transmit/receive filter types liquid_firfilt_type ftype_tx = LIQUID_FIRFILT_RRC; liquid_firfilt_type ftype_rx = LIQUID_FIRFILT_RRC; float bt = 0.02f; // loop filter bandwidth float tau = -0.2f; // fractional symbol offset float r = 1.00f; // resampled rate // use random data or 101010 phasing pattern int random_data=1; int dopt; while ((dopt = getopt(argc,argv,"hT:k:K:m:b:B:s:w:n:t:r:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'T': if (strcmp(optarg,"gmsk")==0) { ftype_tx = LIQUID_FIRFILT_GMSKTX; ftype_rx = LIQUID_FIRFILT_GMSKRX; } else { ftype_tx = liquid_getopt_str2firfilt(optarg); ftype_rx = liquid_getopt_str2firfilt(optarg); } if (ftype_tx == LIQUID_FIRFILT_UNKNOWN) { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'K': k_out = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': num_filters = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; case 'r': r = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (num_filters == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } else if (r < 0.5f || r > 2.0f) { fprintf(stderr,"error: timing frequency offset must be in [0.5,2]\n"); exit(1); } // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset if (dt > 0.5f) { // force dt to be in [0.5,0.5] dt -= 1.0f; ds++; } unsigned int i, n=0; unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*r*1.1f) + 4; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples_resamp]; // resampled data (resamp_crcf) float complex z[k_out*num_symbols + 64];// synchronized samples float complex sym_out[num_symbols + 64];// synchronized symbols for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symsync_crcf_kaiser_example.m" // print usage/help message void usage(void); void usage(void) { printf("symsync_crcf_example [options]\n"); printf(" -h : print help\n"); printf(" -k : filter samples/symbol, default: 2\n"); printf(" -m : filter delay (symbols), default: 3\n"); printf(" -b : filter excess bandwidth, default: 0.5\n"); printf(" -B : filter polyphase banks, default: 32\n"); printf(" -s : signal-to-noise ratio, default: 30 dB\n"); printf(" -w : timing pll bandwidth, default: 0.02\n"); printf(" -n : number of symbols, default: 400\n"); printf(" -t : timing offset, default: -0.2\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k = 2; // samples/symbol (input) unsigned int m = 3; // filter delay (symbols) float beta = 0.5f; // filter excess bandwidth factor unsigned int num_filters = 32; // number of filters in the bank float SNRdB = 30.0f; // signal-to-noise ratio float bt = 0.02f; // loop filter bandwidth unsigned int num_symbols = 400; // number of data symbols float tau = -0.20f; // fractional symbol offset // Nyquist filter type liquid_firfilt_type ftype = LIQUID_FIRFILT_KAISER; int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:B:s:w:n:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': num_filters = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be at least 2\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (num_filters == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } // derived values unsigned int num_samples = k*num_symbols; float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // received signal (with noise) float tau_hat[num_samples]; // instantaneous timing offset estimate float complex sym_out[num_symbols + 64];// synchronized symbols // create sequence of Nyquist-interpolated QPSK symbols firinterp_crcf interp = firinterp_crcf_create_prototype(ftype,k,m,beta,tau); for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symtrack_cccf_example.m" // print usage/help message void usage() { printf("symtrack_cccf_example [options]\n"); printf(" h : print this help file\n"); printf(" k : filter samples/symbol, default: 2\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" s : signal-to-noise ratio, default: 30 dB\n"); printf(" w : timing pll bandwidth, default: 0.02\n"); printf(" n : number of symbols, default: 4000\n"); } int main(int argc, char*argv[]) { // options int ftype = LIQUID_FIRFILT_ARKAISER; int ms = LIQUID_MODEM_QAM16; unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay (symbols) float beta = 0.20f; // filter excess bandwidth factor unsigned int num_symbols = 4000; // number of data symbols unsigned int hc_len = 4; // channel filter length float noise_floor = -60.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.10f; // loop filter bandwidth float dphi = 0.02f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 200000; // number of samples int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:s:w:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: k (samples/symbol) must be greater than 1\n"); exit(1); } else if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (bandwidth <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } unsigned int i; // buffers unsigned int buf_len = 800; // buffer size float complex x [buf_len]; // original signal float complex y [buf_len]; // channel output float complex syms[buf_len]; // recovered symbols // window for saving last few symbols windowcf sym_buf = windowcf_create(buf_len); // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,k,m,beta,ms); // create channel emulator and add impairments channel_cccf channel = channel_cccf_create(); channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); channel_cccf_add_multipath (channel, NULL, hc_len); // create symbol tracking synchronizer symtrack_cccf symtrack = symtrack_cccf_create(ftype,k,m,beta,ms); symtrack_cccf_set_bandwidth(symtrack,bandwidth); //symtrack_cccf_set_eq_off(symtrack); // disable equalization symtrack_cccf_print(symtrack); // create spectral periodogram for estimating spectrum spgramcf periodogram = spgramcf_create_default(nfft); unsigned int total_samples = 0; unsigned int total_symbols = 0; while (total_samples < num_samples) { // write samples to buffer symstreamcf_write_samples(gen, x, buf_len); // apply channel channel_cccf_execute_block(channel, x, buf_len, y); // push resulting sample through periodogram spgramcf_write(periodogram, y, buf_len); // run resulting stream through synchronizer unsigned int num_symbols_sync; symtrack_cccf_execute_block(symtrack, y, buf_len, syms, &num_symbols_sync); total_symbols += num_symbols_sync; // write resulting symbols to window buffer for plotting windowcf_write(sym_buf, syms, num_symbols_sync); // accumulated samples total_samples += buf_len; } printf("total samples: %u\n", total_samples); printf("total symbols: %u\n", total_symbols); // write accumulated power spectral density estimate float psd[nfft]; spgramcf_get_psd(periodogram, psd); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s, auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); // read buffer and write last symbols to file float complex * rc; windowcf_read(sym_buf, &rc); fprintf(fid,"syms = zeros(1,%u);\n", buf_len); for (i=0; i #include "liquid.h" #define OUTPUT_FILENAME "wdelayf_example.m" int main() { unsigned int delay = 10; unsigned int num_samples = 64; // create wdelay, all elements initialized to 0 wdelayf w = wdelayf_create(delay); float y; // output FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"delay = %u;\n", delay); // push several elements unsigned int i; float x; for (i=0; i #include #include "liquid.h" #define OUTPUT_FILENAME "window_enbw_example.m" int main() { // options unsigned int m = 20; // window semi-length float beta = 10.0f; // Kaiser beta factor unsigned int nfft = 1200; // transform size float th = 0.95f; // threshold for spectral energy // derived values unsigned int i; unsigned int wlen = 2*m+1; // window length float w[wlen]; float w2 = 0.0f; for (i=0; i th) i_threshold = i; e2_sum += e2; } float enbw = (float)i_threshold / (float)nfft; printf("equivalent noise bandwidth: %.6f Fs\n", enbw); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"m=%u;\n",m); fprintf(fid,"enbw=%f;\n",enbw); fprintf(fid,"th=%f;\n",th); fprintf(fid,"nfft=%u;\n",nfft); for (i=0; i #include "liquid.h" int main() { // initialize vector of data for testing float v[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; float *r; // reader unsigned int i; // create window: 10 elements, initialized to 0 // w: 0 0 0 0 0 0 0 0 0 0 windowf w = windowf_create(10); // push 4 elements // w: 0 0 0 0 0 0 1 1 1 1 windowf_push(w, 1); windowf_push(w, 1); windowf_push(w, 1); windowf_push(w, 1); // push 4 more elements // w: 0 0 1 1 1 1 9 8 7 6 windowf_write(w, v, 4); // push 4 more elements // w: 1 1 9 8 7 6 3 3 3 3 windowf_push(w, 3); windowf_push(w, 3); windowf_push(w, 3); windowf_push(w, 3); // read the buffer by assigning the pointer // appropriately windowf_read(w, &r); // manual print printf("manual output:\n"); for (i=0; i<10; i++) printf("%6u : %f\n", i, r[i]); windowf_debug_print(w); // clean it up windowf_destroy(w); printf("done.\n"); return 0; } liquid-dsp-1.7.0/examples/windowing_example.c000066400000000000000000000034061474751757600213260ustar00rootroot00000000000000// demonstrate windowing functions #include #include #include "liquid.h" #define OUTPUT_FILENAME "windowing_example.m" int main(int argc, char*argv[]) { // options liquid_window_type wtype = LIQUID_WINDOW_KAISER; unsigned int wlen = 51; // window size float arg = 10.0f; // generic argument // compute window coefficients float w[wlen]; unsigned int i; for (i=0; i #include #include // // Make sure the version and version number macros weren't defined by // some prevoiusly included header file. // #ifdef LIQUID_VERSION # undef LIQUID_VERSION #endif #ifdef LIQUID_VERSION_NUMBER # undef LIQUID_VERSION_NUMBER #endif // Compile-time version numbers // macros for expanding version numbers to string literals #define LIQUID_VERSION_STR_EX(num) #num #define LIQUID_VERSION_STR(num) LIQUID_VERSION_STR_EX(num) #define LIQUID_VERSION_MAJOR 1 #define LIQUID_VERSION_MINOR 7 #define LIQUID_VERSION_PATCH 0 #define LIQUID_VERSION_DEV 0 // final version string is constructed by concatenating inidividual string versions #define LIQUID_VERSION \ LIQUID_VERSION_STR(LIQUID_VERSION_MAJOR) "." \ LIQUID_VERSION_STR(LIQUID_VERSION_MINOR) "." \ LIQUID_VERSION_STR(LIQUID_VERSION_PATCH) // final version number is constructed from major, minor, patch #define LIQUID_VERSION_NUMBER ( \ (uint32_t) ( \ (LIQUID_VERSION_MAJOR << 16) | \ (LIQUID_VERSION_MINOR << 8) | \ (LIQUID_VERSION_PATCH ))) // // Run-time library version numbers // extern const char liquid_version[]; const char * liquid_libversion(void); int liquid_libversion_number(void); // run-time library validation #define LIQUID_VALIDATE_LIBVERSION \ if (LIQUID_VERSION_NUMBER != liquid_libversion_number()) { \ fprintf(stderr,"%s:%u: ", __FILE__,__LINE__); \ fprintf(stderr,"error: invalid liquid runtime library\n"); \ fprintf(stderr," header version : %d\n", LIQUID_VERSION_NUMBER); \ fprintf(stderr," library version : %d\n", liquid_libversion_number()); \ exit(1); \ } \ // basic error types #define LIQUID_NUM_ERRORS 14 typedef enum { // everything ok LIQUID_OK=0, // internal logic error; this is a bug with liquid and should be reported immediately LIQUID_EINT, // invalid object, examples: // - destroy() method called on NULL pointer LIQUID_EIOBJ, // invalid parameter, or configuration; examples: // - setting bandwidth of a filter to a negative number // - setting FFT size to zero // - create a spectral periodogram object with window size greater than nfft LIQUID_EICONFIG, // input out of range; examples: // - try to take log of -1 // - try to create an FFT plan of size zero LIQUID_EIVAL, // invalid vector length or dimension; examples // - trying to refer to the 17th element of a 2 x 2 matrix // - trying to multiply two matrices of incompatible dimensions LIQUID_EIRANGE, // invalid mode; examples: // - try to create a modem of type 'LIQUID_MODEM_XXX' which does not exit LIQUID_EIMODE, // unsupported mode (e.g. LIQUID_FEC_CONV_V27 with 'libfec' not installed) LIQUID_EUMODE, // object has not been created or properly initialized // - try to run firfilt_crcf_execute(NULL, ...) // - try to modulate using an arbitrary modem without initializing the constellation LIQUID_ENOINIT, // not enough memory allocated for operation; examples: // - try to factor 100 = 2*2*5*5 but only give 3 spaces for factors LIQUID_EIMEM, // file input/output; examples: // - could not open a file for writing because of insufficient permissions // - could not open a file for reading because it does not exist // - try to read more data than a file has space for // - could not parse line in file (improper formatting) LIQUID_EIO, // algorithm could not converge or no solution could be found // - try to find roots of polynomial can sometimes cause instability // - filter design using Parks-McClellan with extremely tight constraints LIQUID_ENOCONV, // method or function declared but not implemented or disabled LIQUID_ENOIMP, } liquid_error_code; // error descriptions extern const char * liquid_error_str[LIQUID_NUM_ERRORS]; const char * liquid_error_info(liquid_error_code _code); #define LIQUID_CONCAT(prefix, name) prefix ## name #define LIQUID_VALIDATE_INPUT /* * Compile-time complex data type definitions * * Default: use the C99 complex data type, otherwise * define complex type compatible with the C++ complex standard, * otherwise resort to defining binary compatible array. */ #if LIQUID_USE_COMPLEX_H==1 # include # define LIQUID_DEFINE_COMPLEX(R,C) typedef R _Complex C #elif defined _GLIBCXX_COMPLEX || defined _LIBCPP_COMPLEX # define LIQUID_DEFINE_COMPLEX(R,C) typedef std::complex C #else # define LIQUID_DEFINE_COMPLEX(R,C) typedef struct {R real; R imag;} C; #endif //# define LIQUID_DEFINE_COMPLEX(R,C) typedef R C[2] LIQUID_DEFINE_COMPLEX(float, liquid_float_complex); LIQUID_DEFINE_COMPLEX(double, liquid_double_complex); // external compile-time deprecation warnings with messages #ifdef __GNUC__ # define DEPRECATED(MSG,X) X __attribute__((deprecated (MSG))) #elif defined(_MSC_VER) # define DEPRECATED(MSG,X) __declspec(deprecated) X #else # define DEPRECATED(MSG,X) X #endif // // MODULE : agc (automatic gain control) // // available squelch modes typedef enum { LIQUID_AGC_SQUELCH_UNKNOWN=0, // unknown/unavailable squelch mode LIQUID_AGC_SQUELCH_ENABLED, // squelch enabled but signal not detected LIQUID_AGC_SQUELCH_RISE, // signal first hit/exceeded threshold LIQUID_AGC_SQUELCH_SIGNALHI, // signal level high (above threshold) LIQUID_AGC_SQUELCH_FALL, // signal first dropped below threshold LIQUID_AGC_SQUELCH_SIGNALLO, // signal level low (below threshold) LIQUID_AGC_SQUELCH_TIMEOUT, // signal level low (below threshold for a certain time) LIQUID_AGC_SQUELCH_DISABLED, // squelch not enabled } agc_squelch_mode; #define LIQUID_AGC_MANGLE_CRCF(name) LIQUID_CONCAT(agc_crcf, name) #define LIQUID_AGC_MANGLE_RRRF(name) LIQUID_CONCAT(agc_rrrf, name) // large macro // AGC : name-mangling macro // T : primitive data type // TC : input/output data type #define LIQUID_AGC_DEFINE_API(AGC,T,TC) \ \ /* Automatic gain control (agc) for level correction and signal */ \ /* detection */ \ typedef struct AGC(_s) * AGC(); \ \ /* Create automatic gain control object. */ \ AGC() AGC(_create)(void); \ \ /* Copy object including all internal objects and state */ \ AGC() AGC(_copy)(AGC() _q); \ \ /* Destroy object, freeing all internally-allocated memory. */ \ int AGC(_destroy)(AGC() _q); \ \ /* Print object properties to stdout, including received signal */ \ /* strength indication (RSSI), loop bandwidth, lock status, and squelch */ \ /* status. */ \ int AGC(_print)(AGC() _q); \ \ /* Reset internal state of agc object, including gain estimate, input */ \ /* signal level estimate, lock status, and squelch mode */ \ /* If the squelch mode is disabled, it stays disabled, but all enabled */ \ /* modes (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) resets to just */ \ /* LIQUID_AGC_SQUELCH_ENABLED. */ \ int AGC(_reset)(AGC() _q); \ \ /* Execute automatic gain control on an single input sample */ \ /* _q : automatic gain control object */ \ /* _x : input sample */ \ /* _y : output sample */ \ int AGC(_execute)(AGC() _q, \ TC _x, \ TC * _y); \ \ /* Execute automatic gain control on block of samples pointed to by _x */ \ /* and store the result in the array of the same length _y. */ \ /* _q : automatic gain control object */ \ /* _x : input data array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _y : output data array, [size: _n x 1] */ \ int AGC(_execute_block)(AGC() _q, \ TC * _x, \ unsigned int _n, \ TC * _y); \ \ /* Lock agc object. When locked, the agc object still makes an estimate */ \ /* of the signal level, but the gain setting is fixed and does not */ \ /* change. */ \ /* This is useful for providing coarse input signal level correction */ \ /* and quickly detecting a packet burst but not distorting signals with */ \ /* amplitude variation due to modulation. */ \ int AGC(_lock)(AGC() _q); \ \ /* Unlock agc object, and allow amplitude correction to resume. */ \ int AGC(_unlock)(AGC() _q); \ \ /* Get lock state of agc object */ \ int AGC(_is_locked)(AGC() _q); \ \ /* Set loop filter bandwidth: attack/release time. */ \ /* _q : automatic gain control object */ \ /* _bt : bandwidth-time constant, _bt > 0 */ \ int AGC(_set_bandwidth)(AGC() _q, float _bt); \ \ /* Get the agc object's loop filter bandwidth. */ \ float AGC(_get_bandwidth)(AGC() _q); \ \ /* Get the input signal's estimated energy level, relative to unity. */ \ /* The result is a linear value. */ \ float AGC(_get_signal_level)(AGC() _q); \ \ /* Set the agc object's estimate of the input signal by specifying an */ \ /* explicit linear value. This is useful for initializing the agc */ \ /* object with a preliminary estimate of the signal level to help gain */ \ /* convergence. */ \ /* _q : automatic gain control object */ \ /* _x2 : signal level of input, _x2 > 0 */ \ int AGC(_set_signal_level)(AGC() _q, \ float _x2); \ \ /* Get the agc object's estimated received signal strength indication */ \ /* (RSSI) on the input signal. */ \ /* This is similar to getting the signal level (above), but returns the */ \ /* result in dB rather than on a linear scale. */ \ float AGC(_get_rssi)(AGC() _q); \ \ /* Set the agc object's estimated received signal strength indication */ \ /* (RSSI) on the input signal by specifying an explicit value in dB. */ \ /* _q : automatic gain control object */ \ /* _rssi : signal level of input [dB] */ \ int AGC(_set_rssi)(AGC() _q, float _rssi); \ \ /* Get the gain value currently being applied to the input signal */ \ /* (linear). */ \ float AGC(_get_gain)(AGC() _q); \ \ /* Set the agc object's internal gain by specifying an explicit linear */ \ /* value. */ \ /* _q : automatic gain control object */ \ /* _gain : gain to apply to input signal, _gain > 0 */ \ int AGC(_set_gain)(AGC() _q, \ float _gain); \ \ /* Get the output scaling applied to each sample (linear). */ \ float AGC(_get_scale)(AGC() _q); \ \ /* Set the agc object's output scaling (linear). Note that this does */ \ /* affect the response of the AGC. */ \ /* _q : automatic gain control object */ \ /* _gain : gain to apply to input signal, _gain > 0 */ \ int AGC(_set_scale)(AGC() _q, \ float _scale); \ \ /* Estimate signal level and initialize internal gain on an input */ \ /* array. */ \ /* _q : automatic gain control object */ \ /* _x : input data array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ int AGC(_init)(AGC() _q, \ TC * _x, \ unsigned int _n); \ \ /* Enable squelch mode. */ \ int AGC(_squelch_enable)(AGC() _q); \ \ /* Disable squelch mode. */ \ int AGC(_squelch_disable)(AGC() _q); \ \ /* Return flag indicating if squelch is enabled or not. */ \ int AGC(_squelch_is_enabled)(AGC() _q); \ \ /* Set threshold for enabling/disabling squelch. */ \ /* _q : automatic gain control object */ \ /* _thresh : threshold for enabling squelch [dB] */ \ int AGC(_squelch_set_threshold)(AGC() _q, \ T _thresh); \ \ /* Get squelch threshold (value in dB) */ \ T AGC(_squelch_get_threshold)(AGC() _q); \ \ /* Set timeout before enabling squelch. */ \ /* _q : automatic gain control object */ \ /* _timeout : timeout before enabling squelch [samples] */ \ int AGC(_squelch_set_timeout)(AGC() _q, \ unsigned int _timeout); \ \ /* Get squelch timeout (number of samples) */ \ unsigned int AGC(_squelch_get_timeout)(AGC() _q); \ \ /* Get squelch status (e.g. LIQUID_AGC_SQUELCH_TIMEOUT) */ \ int AGC(_squelch_get_status)(AGC() _q); \ // Define agc APIs LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_CRCF, float, liquid_float_complex) LIQUID_AGC_DEFINE_API(LIQUID_AGC_MANGLE_RRRF, float, float) // // MODULE : audio // // CVSD: continuously variable slope delta typedef struct cvsd_s * cvsd; // create cvsd object // _num_bits : number of adjacent bits to observe (4 recommended) // _zeta : slope adjustment multiplier (1.5 recommended) // _alpha : pre-/post-emphasis filter coefficient (0.9 recommended) // NOTE: _alpha must be in [0,1] cvsd cvsd_create(unsigned int _num_bits, float _zeta, float _alpha); // destroy cvsd object int cvsd_destroy(cvsd _q); // print cvsd object parameters int cvsd_print(cvsd _q); // encode/decode single sample unsigned char cvsd_encode(cvsd _q, float _audio_sample); float cvsd_decode(cvsd _q, unsigned char _bit); // encode/decode 8 samples at a time int cvsd_encode8(cvsd _q, float * _audio, unsigned char * _data); int cvsd_decode8(cvsd _q, unsigned char _data, float * _audio); // // MODULE : buffer // // circular buffer #define LIQUID_CBUFFER_MANGLE_FLOAT(name) LIQUID_CONCAT(cbufferf, name) #define LIQUID_CBUFFER_MANGLE_CFLOAT(name) LIQUID_CONCAT(cbuffercf, name) // large macro // CBUFFER : name-mangling macro // T : data type #define LIQUID_CBUFFER_DEFINE_API(CBUFFER,T) \ \ /* Circular buffer object for storing and retrieving samples in a */ \ /* first-in/first-out (FIFO) manner using a minimal amount of memory */ \ typedef struct CBUFFER(_s) * CBUFFER(); \ \ /* Create circular buffer object of a particular maximum storage length */ \ /* _max_size : maximum buffer size, _max_size > 0 */ \ CBUFFER() CBUFFER(_create)(unsigned int _max_size); \ \ /* Create circular buffer object of a particular maximum storage size */ \ /* and specify the maximum number of elements that can be read at any */ \ /* any given time */ \ /* _max_size : maximum buffer size, _max_size > 0 */ \ /* _max_read : maximum size that will be read from buffer */ \ CBUFFER() CBUFFER(_create_max)(unsigned int _max_size, \ unsigned int _max_read); \ \ /* Copy object including all internal objects and state */ \ CBUFFER() CBUFFER(_copy)(CBUFFER() _q); \ \ /* Destroy cbuffer object, freeing all internal memory */ \ int CBUFFER(_destroy)(CBUFFER() _q); \ \ /* Print cbuffer object properties to stdout */ \ int CBUFFER(_print)(CBUFFER() _q); \ \ /* Clear internal buffer */ \ int CBUFFER(_reset)(CBUFFER() _q); \ \ /* Get the number of elements currently in the buffer */ \ unsigned int CBUFFER(_size)(CBUFFER() _q); \ \ /* Get the maximum number of elements the buffer can hold */ \ unsigned int CBUFFER(_max_size)(CBUFFER() _q); \ \ /* Get the maximum number of elements you may read at once */ \ unsigned int CBUFFER(_max_read)(CBUFFER() _q); \ \ /* Get the number of available slots (max_size - size) */ \ unsigned int CBUFFER(_space_available)(CBUFFER() _q); \ \ /* Return flag indicating if the buffer is empty or not */ \ int CBUFFER(_is_empty)(CBUFFER() _q); \ \ /* Return flag indicating if the buffer is full or not */ \ int CBUFFER(_is_full)(CBUFFER() _q); \ \ /* Write a single sample into the buffer */ \ /* _q : circular buffer object */ \ /* _v : input sample */ \ int CBUFFER(_push)(CBUFFER() _q, \ T _v); \ \ /* Write a block of samples to the buffer */ \ /* _q : circular buffer object */ \ /* _v : array of samples to write to buffer */ \ /* _n : number of samples to write */ \ int CBUFFER(_write)(CBUFFER() _q, \ T * _v, \ unsigned int _n); \ \ /* Remove and return a single element from the buffer by setting the */ \ /* value of the output sample pointed to by _v */ \ /* _q : circular buffer object */ \ /* _v : pointer to sample output */ \ int CBUFFER(_pop)(CBUFFER() _q, \ T * _v); \ \ /* Read buffer contents by returning a pointer to the linearized array; */ \ /* note that the returned pointer is only valid until another operation */ \ /* is performed on the circular buffer object */ \ /* _q : circular buffer object */ \ /* _num_requested : number of elements requested */ \ /* _v : output pointer */ \ /* _num_read : number of elements referenced by _v */ \ int CBUFFER(_read)(CBUFFER() _q, \ unsigned int _num_requested, \ T ** _v, \ unsigned int * _num_read); \ \ /* Release _n samples from the buffer */ \ /* _q : circular buffer object */ \ /* _n : number of elements to release */ \ int CBUFFER(_release)(CBUFFER() _q, \ unsigned int _n); \ // Define buffer APIs LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_FLOAT, float) LIQUID_CBUFFER_DEFINE_API(LIQUID_CBUFFER_MANGLE_CFLOAT, liquid_float_complex) // Windowing functions #define LIQUID_WINDOW_MANGLE_FLOAT(name) LIQUID_CONCAT(windowf, name) #define LIQUID_WINDOW_MANGLE_CFLOAT(name) LIQUID_CONCAT(windowcf, name) // large macro // WINDOW : name-mangling macro // T : data type #define LIQUID_WINDOW_DEFINE_API(WINDOW,T) \ \ /* Sliding window first-in/first-out buffer with a fixed size */ \ typedef struct WINDOW(_s) * WINDOW(); \ \ /* Create window buffer object of a fixed length. Samples may be pushed */ \ /* into the buffer which retains the most recent \(n\) samples. */ \ /* _n : length of the window buffer [samples] */ \ WINDOW() WINDOW(_create)(unsigned int _n); \ \ /* Recreate window buffer object with new length. */ \ /* This extends an existing window's size, similar to the standard C */ \ /* library's realloc() to n samples. */ \ /* If the size of the new window is larger than the old one, the newest */ \ /* values are retained at the beginning of the buffer and the oldest */ \ /* values are truncated. If the size of the new window is smaller than */ \ /* the old one, the oldest values are truncated. */ \ /* _q : old window object */ \ /* _n : new window length [samples] */ \ WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ WINDOW() WINDOW(_copy)(WINDOW() _q); \ \ /* Destroy window object, freeing all internally memory */ \ int WINDOW(_destroy)(WINDOW() _q); \ \ /* Print window object to stdout */ \ int WINDOW(_print)(WINDOW() _q); \ \ /* Print window object to stdout (with extra information) */ \ int WINDOW(_debug_print)(WINDOW() _q); \ \ /* Reset window object (initialize to zeros) */ \ int WINDOW(_reset)(WINDOW() _q); \ \ /* Read the contents of the window by returning a pointer to the */ \ /* aligned internal memory array. This method guarantees that the */ \ /* elements are linearized. This method should only be used for */ \ /* reading; writing values to the buffer has unspecified results. */ \ /* Note that the returned pointer is only valid until another operation */ \ /* is performed on the window buffer object */ \ /* _q : window object */ \ /* _v : output pointer (set to internal array) */ \ int WINDOW(_read)(WINDOW() _q, \ T ** _v); \ \ /* Index single element in buffer at a particular index */ \ /* This retrieves the \(i^{th}\) sample in the window, storing the */ \ /* output value in _v. */ \ /* This is equivalent to first invoking read() and then indexing on the */ \ /* resulting pointer; however the result is obtained much faster. */ \ /* Therefore setting the index to 0 returns the oldest value in the */ \ /* window. */ \ /* _q : window object */ \ /* _i : index of element to read */ \ /* _v : output value pointer */ \ int WINDOW(_index)(WINDOW() _q, \ unsigned int _i, \ T * _v); \ \ /* Shifts a single sample into the right side of the window, pushing */ \ /* the oldest (left-most) sample out of the end. Unlike stacks, the */ \ /* window object has no equivalent "pop" method, as values are retained */ \ /* in memory until they are overwritten. */ \ /* _q : window object */ \ /* _v : single input element */ \ int WINDOW(_push)(WINDOW() _q, \ T _v); \ \ /* Write array of elements onto window buffer */ \ /* Effectively, this is equivalent to pushing each sample one at a */ \ /* time, but executes much faster. */ \ /* _q : window object */ \ /* _v : input array of values to write */ \ /* _n : number of input values to write */ \ int WINDOW(_write)(WINDOW() _q, \ T * _v, \ unsigned int _n); \ // Define window APIs LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_FLOAT, float) LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_CFLOAT, liquid_float_complex) //LIQUID_WINDOW_DEFINE_API(LIQUID_WINDOW_MANGLE_UINT, unsigned int) // wdelay functions : windowed-delay // Implements an efficient z^-k delay with minimal memory #define LIQUID_WDELAY_MANGLE_FLOAT(name) LIQUID_CONCAT(wdelayf, name) #define LIQUID_WDELAY_MANGLE_CFLOAT(name) LIQUID_CONCAT(wdelaycf, name) //#define LIQUID_WDELAY_MANGLE_UINT(name) LIQUID_CONCAT(wdelayui, name) // large macro // WDELAY : name-mangling macro // T : data type #define LIQUID_WDELAY_DEFINE_API(WDELAY,T) \ \ /* Efficient digital delay line using a minimal amount of memory */ \ typedef struct WDELAY(_s) * WDELAY(); \ \ /* Create delay buffer object with a particular number of samples of */ \ /* delay */ \ /* _delay : number of samples of delay in the wdelay object */ \ WDELAY() WDELAY(_create)(unsigned int _delay); \ \ /* Copy object including all internal objects and state */ \ WDELAY() WDELAY(_copy)(WDELAY() _q); \ \ /* Re-create delay buffer object, adjusting the delay size, preserving */ \ /* the internal state of the object */ \ /* _q : old delay buffer object */ \ /* _delay : delay for new object */ \ WDELAY() WDELAY(_recreate)(WDELAY() _q, \ unsigned int _delay); \ \ /* Destroy delay buffer object, freeing internal memory */ \ int WDELAY(_destroy)(WDELAY() _q); \ \ /* Print delay buffer object's state to stdout */ \ int WDELAY(_print)(WDELAY() _q); \ \ /* Clear/reset state of object */ \ int WDELAY(_reset)(WDELAY() _q); \ \ /* Read delayed sample at the head of the buffer and store it to the */ \ /* output pointer */ \ /* _q : delay buffer object */ \ /* _v : value of delayed element */ \ int WDELAY(_read)(WDELAY() _q, \ T * _v); \ \ /* Push new sample into delay buffer object */ \ /* _q : delay buffer object */ \ /* _v : new value to be added to buffer */ \ int WDELAY(_push)(WDELAY() _q, \ T _v); \ // Define wdelay APIs LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_FLOAT, float) LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_CFLOAT, liquid_float_complex) //LIQUID_WDELAY_DEFINE_API(LIQUID_WDELAY_MANGLE_UINT, unsigned int) // // MODULE : channel // #define LIQUID_CHANNEL_MANGLE_CCCF(name) LIQUID_CONCAT(channel_cccf,name) // large macro // CHANNEL : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_CHANNEL_DEFINE_API(CHANNEL,TO,TC,TI) \ \ /* Channel emulation */ \ typedef struct CHANNEL(_s) * CHANNEL(); \ \ /* Create channel object with default parameters */ \ CHANNEL() CHANNEL(_create)(void); \ \ /* Copy object including all internal objects and state */ \ CHANNEL() CHANNEL(_copy)(CHANNEL() _q); \ \ /* Destroy channel object, freeing all internal memory */ \ int CHANNEL(_destroy)(CHANNEL() _q); \ \ /* Print channel object internals to standard output */ \ int CHANNEL(_print)(CHANNEL() _q); \ \ /* Include additive white Gausss noise impairment */ \ /* _q : channel object */ \ /* _noise_floor: noise floor power spectral density [dB] */ \ /* _snr : signal-to-noise ratio [dB] */ \ int CHANNEL(_add_awgn)(CHANNEL() _q, \ float _noise_floor, \ float _snr); \ \ /* Include carrier offset impairment */ \ /* _q : channel object */ \ /* _frequency : carrier frequency offset [radians/sample] */ \ /* _phase : carrier phase offset [radians] */ \ int CHANNEL(_add_carrier_offset)(CHANNEL() _q, \ float _frequency, \ float _phase); \ \ /* Include multi-path channel impairment */ \ /* _q : channel object */ \ /* _h : channel coefficients (NULL for random) */ \ /* _h_len : number of channel coefficients */ \ int CHANNEL(_add_multipath)(CHANNEL() _q, \ TC * _h, \ unsigned int _h_len); \ \ /* Include slowly-varying shadowing impairment */ \ /* _q : channel object */ \ /* _sigma : standard deviation for log-normal shadowing */ \ /* _fd : Doppler frequency, 0 <= _fd < 0.5 */ \ int CHANNEL(_add_shadowing)(CHANNEL() _q, \ float _sigma, \ float _fd); \ \ /* Apply channel impairments on single input sample */ \ /* _q : channel object */ \ /* _x : input sample */ \ /* _y : pointer to output sample */ \ int CHANNEL(_execute)(CHANNEL() _q, \ TI _x, \ TO * _y); \ \ /* Apply channel impairments on block of samples */ \ /* _q : channel object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : input array, length */ \ /* _y : output array, [size: _n x 1] */ \ int CHANNEL(_execute_block)(CHANNEL() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_CHANNEL_DEFINE_API(LIQUID_CHANNEL_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // time-varying multi-path channel // #define LIQUID_TVMPCH_MANGLE_CCCF(name) LIQUID_CONCAT(tvmpch_cccf,name) // large macro // TVMPCH : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_TVMPCH_DEFINE_API(TVMPCH,TO,TC,TI) \ \ /* Time-varying multipath channel emulation */ \ typedef struct TVMPCH(_s) * TVMPCH(); \ \ /* Create time-varying multi-path channel emulator object, specifying */ \ /* the number of coefficients, the standard deviation of coefficients, */ \ /* and the coherence time. The larger the standard deviation, the more */ \ /* dramatic the frequency response of the channel. The shorter the */ \ /* coeherent time, the faster the channel effects. */ \ /* _n : number of coefficients, _n > 0 */ \ /* _std : standard deviation, _std >= 0 */ \ /* _tau : normalized coherence time, 0 < _tau < 1 */ \ TVMPCH() TVMPCH(_create)(unsigned int _n, \ float _std, \ float _tau); \ \ /* Copy object including all internal objects and state */ \ TVMPCH() TVMPCH(_copy)(TVMPCH() _q); \ \ /* Destroy channel object, freeing all internal memory */ \ int TVMPCH(_destroy)(TVMPCH() _q); \ \ /* Reset object */ \ int TVMPCH(_reset)(TVMPCH() _q); \ \ /* Print channel object internals to standard output */ \ int TVMPCH(_print)(TVMPCH() _q); \ \ /* Push sample into emulator */ \ /* _q : channel object */ \ /* _x : input sample */ \ int TVMPCH(_push)(TVMPCH() _q, \ TI _x); \ \ /* Compute output sample */ \ /* _q : channel object */ \ /* _y : output sample */ \ int TVMPCH(_execute)(TVMPCH() _q, \ TO * _y); \ \ /* Execute filter on one sample, equivalent to push() and execute() */ \ /* _q : channel object */ \ /* _x : single input sample */ \ /* _y : pointer to single output sample */ \ int TVMPCH(_execute_one)(TVMPCH() _q, \ TI _x, \ TO * _y); \ \ /* Apply channel impairments on a block of samples */ \ /* _q : channel object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : input array length */ \ /* _y : output array, [size: _n x 1] */ \ int TVMPCH(_execute_block)(TVMPCH() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_TVMPCH_DEFINE_API(LIQUID_TVMPCH_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // MODULE : dotprod (vector dot product) // #define LIQUID_DOTPROD_MANGLE_RRRF(name) LIQUID_CONCAT(dotprod_rrrf,name) #define LIQUID_DOTPROD_MANGLE_CCCF(name) LIQUID_CONCAT(dotprod_cccf,name) #define LIQUID_DOTPROD_MANGLE_CRCF(name) LIQUID_CONCAT(dotprod_crcf,name) // large macro // DOTPROD : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_DOTPROD_DEFINE_API(DOTPROD,TO,TC,TI) \ \ /* Vector dot product operation */ \ typedef struct DOTPROD(_s) * DOTPROD(); \ \ /* Run dot product without creating object. This is less efficient than */ \ /* creating the object as it is an unoptimized portable implementation */ \ /* that doesn't take advantage of processor extensions. It is meant to */ \ /* provide a baseline for performance comparison and a convenient way */ \ /* to invoke a dot product operation when fast operation is not */ \ /* necessary. */ \ /* _v : coefficients array, [size: _n x 1] */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ /* _y : output sample pointer */ \ int DOTPROD(_run)( TC * _v, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* This provides the same unoptimized operation as the 'run()' method */ \ /* above, but with the loop unrolled by a factor of 4. It is marginally */ \ /* faster than 'run()' without unrolling the loop. */ \ /* _v : coefficients array, [size: _n x 1] */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ /* _y : output sample pointer */ \ int DOTPROD(_run4)(TC * _v, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Create vector dot product object */ \ /* _v : coefficients array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ DOTPROD() DOTPROD(_create)(TC * _v, \ unsigned int _n); \ \ /* Create vector dot product object with time-reversed coefficients */ \ /* _v : time-reversed coefficients array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ DOTPROD() DOTPROD(_create_rev)(TC * _v, \ unsigned int _n); \ \ /* Re-create dot product object of potentially a different length with */ \ /* different coefficients. If the length of the dot product object does */ \ /* not change, no memory reallocation is invoked. */ \ /* _q : old dotprod object */ \ /* _v : coefficients array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ DOTPROD() DOTPROD(_recreate)(DOTPROD() _q, \ TC * _v, \ unsigned int _n); \ \ /* Re-create dot product object of potentially a different length with */ \ /* different coefficients. If the length of the dot product object does */ \ /* not change, no memory reallocation is invoked. Filter coefficients */ \ /* are stored in reverse order. */ \ /* _q : old dotprod object */ \ /* _v : time-reversed coefficients array, [size: _n x 1] */ \ /* _n : dotprod length, _n > 0 */ \ DOTPROD() DOTPROD(_recreate_rev)(DOTPROD() _q, \ TC * _v, \ unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ DOTPROD() DOTPROD(_copy)(DOTPROD() _q); \ \ /* Destroy dotprod object, freeing all internal memory */ \ int DOTPROD(_destroy)(DOTPROD() _q); \ \ /* Print dotprod object internals to standard output */ \ int DOTPROD(_print)(DOTPROD() _q); \ \ /* Execute dot product on an input array */ \ /* _q : dotprod object */ \ /* _x : input array, [size: _n x 1] */ \ /* _y : output sample pointer */ \ int DOTPROD(_execute)(DOTPROD() _q, \ TI * _x, \ TO * _y); \ LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_RRRF, float, float, float) LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) LIQUID_DOTPROD_DEFINE_API(LIQUID_DOTPROD_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) // // sum squared methods // float liquid_sumsqf(float * _v, unsigned int _n); float liquid_sumsqcf(liquid_float_complex * _v, unsigned int _n); // // MODULE : equalization // // least mean-squares (LMS) #define LIQUID_EQLMS_MANGLE_RRRF(name) LIQUID_CONCAT(eqlms_rrrf,name) #define LIQUID_EQLMS_MANGLE_CCCF(name) LIQUID_CONCAT(eqlms_cccf,name) // large macro // EQLMS : name-mangling macro // T : data type #define LIQUID_EQLMS_DEFINE_API(EQLMS,T) \ \ /* Least mean-squares equalization object */ \ typedef struct EQLMS(_s) * EQLMS(); \ \ /* Create LMS EQ initialized with external coefficients */ \ /* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ /* _n : filter length */ \ EQLMS() EQLMS(_create)(T * _h, \ unsigned int _n); \ \ /* Create LMS EQ initialized with square-root Nyquist prototype filter */ \ /* as initial set of coefficients. This is useful for applications */ \ /* where the baseline matched filter is a good starting point, but */ \ /* where equalization is needed to properly remove inter-symbol */ \ /* interference. */ \ /* The filter length is \(2 k m + 1\) */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : samples/symbol */ \ /* _m : filter delay (symbols) */ \ /* _beta : rolloff factor (0 < beta <= 1) */ \ /* _dt : fractional sample delay */ \ EQLMS() EQLMS(_create_rnyquist)(int _type, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ float _dt); \ \ /* Create LMS EQ initialized with low-pass filter */ \ /* _n : filter length */ \ /* _fc : filter cut-off normalized to sample rate, 0 < _fc <= 0.5 */ \ EQLMS() EQLMS(_create_lowpass)(unsigned int _n, \ float _fc); \ \ /* Recreate LMS EQ initialized with external coefficients */ \ /* _q : old equalization object */ \ /* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ /* _n : filter length */ \ EQLMS() EQLMS(_recreate)(EQLMS() _q, \ T * _h, \ unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ EQLMS() EQLMS(_copy)(EQLMS() _q); \ \ /* Destroy equalizer object, freeing all internal memory */ \ int EQLMS(_destroy)(EQLMS() _q); \ \ /* Reset equalizer object, clearing internal state */ \ int EQLMS(_reset)(EQLMS() _q); \ \ /* Print equalizer internal state */ \ int EQLMS(_print)(EQLMS() _q); \ \ /* Get equalizer learning rate */ \ float EQLMS(_get_bw)(EQLMS() _q); \ \ /* Set equalizer learning rate */ \ /* _q : equalizer object */ \ /* _lambda : learning rate, _lambda > 0 */ \ int EQLMS(_set_bw)(EQLMS() _q, \ float _lambda); \ \ /* Get length of equalizer object (number of internal coefficients) */ \ unsigned int EQLMS(_get_length)(EQLMS() _q); \ \ /* Get pointer to coefficients array */ \ const T * EQLMS(_get_coefficients)(EQLMS() _q); \ \ /* Copy internal coefficients to external buffer */ \ /* _q : filter object */ \ /* _w : pointer to output coefficients array, [size: _n x 1] */ \ int EQLMS(_copy_coefficients)(EQLMS() _q, \ T * _w); \ \ /* Get equalizer's internal coefficients */ \ /* _q : filter object */ \ /* _w : pointer to output coefficients array, [size: _n x 1] */ \ DEPRECATED("use eqlms_xxxt_copy_coefficients(...) instead", \ void EQLMS(_get_weights)(EQLMS() _q, \ T * _w); \ ) \ \ /* Push sample into equalizer internal buffer */ \ /* _q : equalizer object */ \ /* _x : input sample */ \ int EQLMS(_push)(EQLMS() _q, \ T _x); \ \ /* Push block of samples into internal buffer of equalizer object */ \ /* _q : equalizer object */ \ /* _x : input sample array, [size: _n x 1] */ \ /* _n : input sample array length */ \ int EQLMS(_push_block)(EQLMS() _q, \ T * _x, \ unsigned int _n); \ \ /* Execute internal dot product and return result */ \ /* _q : equalizer object */ \ /* _y : output sample */ \ int EQLMS(_execute)(EQLMS() _q, \ T * _y); \ \ /* Execute equalizer as decimator */ \ /* _q : equalizer object */ \ /* _x : input sample array, [size: _k x 1] */ \ /* _y : output sample */ \ /* _k : down-sampling rate */ \ int EQLMS(_decim_execute)(EQLMS() _q, \ T * _x, \ T * _y, \ unsigned int _k); \ \ /* Execute equalizer with block of samples using constant */ \ /* modulus algorithm, operating on a decimation rate of _k */ \ /* samples. */ \ /* _q : equalizer object */ \ /* _k : down-sampling rate */ \ /* _x : input sample array, [size: _n x 1] */ \ /* _n : input sample array length */ \ /* _y : output sample array, [size: _n x 1] */ \ int EQLMS(_execute_block)(EQLMS() _q, \ unsigned int _k, \ T * _x, \ unsigned int _n, \ T * _y); \ \ /* Step through one cycle of equalizer training */ \ /* _q : equalizer object */ \ /* _d : desired output */ \ /* _d_hat : actual output */ \ int EQLMS(_step)(EQLMS() _q, \ T _d, \ T _d_hat); \ \ /* Step through one cycle of equalizer training (blind) */ \ /* _q : equalizer object */ \ /* _d_hat : actual output */ \ int EQLMS(_step_blind)(EQLMS() _q, \ T _d_hat); \ \ /* Train equalizer object on group of samples */ \ /* _q : equalizer object */ \ /* _w : input/output weights, [size: _p x 1] */ \ /* _x : received sample vector,[size: _n x 1] */ \ /* _d : desired output vector, [size: _n x 1] */ \ /* _n : input, output vector length */ \ DEPRECATED("method provides complexity with little benefit", \ int EQLMS(_train)(EQLMS() _q, \ T * _w, \ T * _x, \ T * _d, \ unsigned int _n); \ ) \ LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_RRRF, float) LIQUID_EQLMS_DEFINE_API(LIQUID_EQLMS_MANGLE_CCCF, liquid_float_complex) // recursive least-squares (RLS) #define LIQUID_EQRLS_MANGLE_RRRF(name) LIQUID_CONCAT(eqrls_rrrf,name) #define LIQUID_EQRLS_MANGLE_CCCF(name) LIQUID_CONCAT(eqrls_cccf,name) // large macro // EQRLS : name-mangling macro // T : data type #define LIQUID_EQRLS_DEFINE_API(EQRLS,T) \ \ /* Recursive least mean-squares equalization object */ \ typedef struct EQRLS(_s) * EQRLS(); \ \ /* Create RLS EQ initialized with external coefficients */ \ /* _h : filter coefficients; set to NULL for {1,0,0...},[size: _n x 1] */ \ /* _n : filter length */ \ EQRLS() EQRLS(_create)(T * _h, \ unsigned int _n); \ \ /* Re-create EQ initialized with external coefficients */ \ /* _q : equalizer object */ \ /* _h : filter coefficients (NULL for {1,0,0...}), [size: _n x 1] */ \ /* _n : filter length */ \ EQRLS() EQRLS(_recreate)(EQRLS() _q, \ T * _h, \ unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ EQRLS() EQRLS(_copy)(EQRLS() _q); \ \ /* Destroy equalizer object, freeing all internal memory */ \ int EQRLS(_destroy)(EQRLS() _q); \ \ /* Reset equalizer object, clearing internal state */ \ int EQRLS(_reset)(EQRLS() _q); \ \ /* Print equalizer internal state */ \ int EQRLS(_print)(EQRLS() _q); \ \ /* Get equalizer learning rate */ \ float EQRLS(_get_bw)(EQRLS() _q); \ \ /* Set equalizer learning rate */ \ /* _q : equalizer object */ \ /* _mu : learning rate, _mu > 0 */ \ int EQRLS(_set_bw)(EQRLS() _q, \ float _mu); \ \ /* Push sample into equalizer internal buffer */ \ /* _q : equalizer object */ \ /* _x : input sample */ \ int EQRLS(_push)(EQRLS() _q, T _x); \ \ /* Execute internal dot product and return result */ \ /* _q : equalizer object */ \ /* _y : output sample */ \ int EQRLS(_execute)(EQRLS() _q, T * _y); \ \ /* Step through one cycle of equalizer training */ \ /* _q : equalizer object */ \ /* _d : desired output */ \ /* _d_hat : actual output */ \ int EQRLS(_step)(EQRLS() _q, T _d, T _d_hat); \ \ /* Get equalizer's internal coefficients */ \ /* _q : equalizer object */ \ /* _w : weights, [size: _p x 1] */ \ int EQRLS(_get_weights)(EQRLS() _q, \ T * _w); \ \ /* Train equalizer object on group of samples */ \ /* _q : equalizer object */ \ /* _w : input/output weights, [size: _p x 1] */ \ /* _x : received sample vector,[size: _n x 1] */ \ /* _d : desired output vector, [size: _n x 1] */ \ /* _n : input, output vector length */ \ int EQRLS(_train)(EQRLS() _q, \ T * _w, \ T * _x, \ T * _d, \ unsigned int _n); \ LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_RRRF, float) LIQUID_EQRLS_DEFINE_API(LIQUID_EQRLS_MANGLE_CCCF, liquid_float_complex) // // MODULE : fec (forward error-correction) // // soft bit values #define LIQUID_SOFTBIT_0 (0) #define LIQUID_SOFTBIT_1 (255) #define LIQUID_SOFTBIT_ERASURE (127) // available CRC schemes #define LIQUID_CRC_NUM_SCHEMES 7 typedef enum { LIQUID_CRC_UNKNOWN=0, // unknown/unavailable CRC scheme LIQUID_CRC_NONE, // no error-detection LIQUID_CRC_CHECKSUM, // 8-bit checksum LIQUID_CRC_8, // 8-bit CRC LIQUID_CRC_16, // 16-bit CRC LIQUID_CRC_24, // 24-bit CRC LIQUID_CRC_32 // 32-bit CRC } crc_scheme; // pretty names for crc schemes extern const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2]; // Print compact list of existing and available CRC schemes int liquid_print_crc_schemes(); // returns crc_scheme based on input string crc_scheme liquid_getopt_str2crc(const char * _str); // get length of CRC (bytes) unsigned int crc_get_length(crc_scheme _scheme); // generate error-detection key // _scheme : error-detection scheme // _msg : input data message, [size: _n x 1] // _n : input data message size unsigned int crc_generate_key(crc_scheme _scheme, unsigned char * _msg, unsigned int _n); // generate error-detection key and append to end of message // _scheme : error-detection scheme (resulting in 'p' bytes) // _msg : input data message, [size: _n+p x 1] // _n : input data message size (excluding key at end) int crc_append_key(crc_scheme _scheme, unsigned char * _msg, unsigned int _n); // validate message using error-detection key // _scheme : error-detection scheme // _msg : input data message, [size: _n x 1] // _n : input data message size // _key : error-detection key int crc_validate_message(crc_scheme _scheme, unsigned char * _msg, unsigned int _n, unsigned int _key); // check message with key appended to end of array // _scheme : error-detection scheme (resulting in 'p' bytes) // _msg : input data message, [size: _n+p x 1] // _n : input data message size (excluding key at end) int crc_check_key(crc_scheme _scheme, unsigned char * _msg, unsigned int _n); // get size of key (bytes) unsigned int crc_sizeof_key(crc_scheme _scheme); // available FEC schemes #define LIQUID_FEC_NUM_SCHEMES 28 typedef enum { LIQUID_FEC_UNKNOWN=0, // unknown/unsupported scheme LIQUID_FEC_NONE, // no error-correction LIQUID_FEC_REP3, // simple repeat code, r1/3 LIQUID_FEC_REP5, // simple repeat code, r1/5 LIQUID_FEC_HAMMING74, // Hamming (7,4) block code, r1/2 (really 4/7) LIQUID_FEC_HAMMING84, // Hamming (7,4) with extra parity bit, r1/2 LIQUID_FEC_HAMMING128, // Hamming (12,8) block code, r2/3 LIQUID_FEC_GOLAY2412, // Golay (24,12) block code, r1/2 LIQUID_FEC_SECDED2216, // SEC-DED (22,16) block code, r8/11 LIQUID_FEC_SECDED3932, // SEC-DED (39,32) block code LIQUID_FEC_SECDED7264, // SEC-DED (72,64) block code, r8/9 // codecs not defined internally (see http://www.ka9q.net/code/fec/) LIQUID_FEC_CONV_V27, // r1/2, K=7, dfree=10 LIQUID_FEC_CONV_V29, // r1/2, K=9, dfree=12 LIQUID_FEC_CONV_V39, // r1/3, K=9, dfree=18 LIQUID_FEC_CONV_V615, // r1/6, K=15, dfree<=57 (Heller 1968) // punctured (perforated) codes LIQUID_FEC_CONV_V27P23, // r2/3, K=7, dfree=6 LIQUID_FEC_CONV_V27P34, // r3/4, K=7, dfree=5 LIQUID_FEC_CONV_V27P45, // r4/5, K=7, dfree=4 LIQUID_FEC_CONV_V27P56, // r5/6, K=7, dfree=4 LIQUID_FEC_CONV_V27P67, // r6/7, K=7, dfree=3 LIQUID_FEC_CONV_V27P78, // r7/8, K=7, dfree=3 LIQUID_FEC_CONV_V29P23, // r2/3, K=9, dfree=7 LIQUID_FEC_CONV_V29P34, // r3/4, K=9, dfree=6 LIQUID_FEC_CONV_V29P45, // r4/5, K=9, dfree=5 LIQUID_FEC_CONV_V29P56, // r5/6, K=9, dfree=5 LIQUID_FEC_CONV_V29P67, // r6/7, K=9, dfree=4 LIQUID_FEC_CONV_V29P78, // r7/8, K=9, dfree=4 // Reed-Solomon codes LIQUID_FEC_RS_M8 // m=8, n=255, k=223 } fec_scheme; // pretty names for fec schemes extern const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2]; // Print compact list of existing and available FEC schemes int liquid_print_fec_schemes(); // returns fec_scheme based on input string fec_scheme liquid_getopt_str2fec(const char * _str); // fec object (pointer to fec structure) typedef struct fec_s * fec; // return the encoded message length using a particular error- // correction scheme (object-independent method) // _scheme : forward error-correction scheme // _msg_len : raw, uncoded message length unsigned int fec_get_enc_msg_length(fec_scheme _scheme, unsigned int _msg_len); // get the theoretical rate of a particular forward error- // correction scheme (object-independent method) float fec_get_rate(fec_scheme _scheme); // create a fec object of a particular scheme // _scheme : error-correction scheme // _opts : (ignored) fec fec_create(fec_scheme _scheme, void *_opts); // recreate fec object // _q : old fec object // _scheme : new error-correction scheme // _opts : (ignored) fec fec_recreate(fec _q, fec_scheme _scheme, void *_opts); // Copy object including all internal objects and state fec fec_copy(fec _q); // destroy fec object int fec_destroy(fec _q); // print fec object internals int fec_print(fec _q); // encode a block of data using a fec scheme // _q : fec object // _dec_msg_len : decoded message length // _msg_dec : decoded message // _msg_enc : encoded message int fec_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); // decode a block of data using a fec scheme // _q : fec object // _dec_msg_len : decoded message length // _msg_enc : encoded message // _msg_dec : decoded message int fec_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // decode a block of data using a fec scheme (soft decision) // _q : fec object // _dec_msg_len : decoded message length // _msg_enc : encoded message (soft bits) // _msg_dec : decoded message int fec_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // // Packetizer // // computes the number of encoded bytes after packetizing // // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code unsigned int packetizer_compute_enc_msg_len(unsigned int _n, int _crc, int _fec0, int _fec1); // computes the number of decoded bytes before packetizing // // _k : number of encoded bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code unsigned int packetizer_compute_dec_msg_len(unsigned int _k, int _crc, int _fec0, int _fec1); typedef struct packetizer_s * packetizer; // create packetizer object // // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code packetizer packetizer_create(unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1); // re-create packetizer object // // _p : initialz packetizer object // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code packetizer packetizer_recreate(packetizer _p, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1); // Copy object including all internal objects and state packetizer packetizer_copy(packetizer _p); // destroy packetizer object int packetizer_destroy(packetizer _p); // print packetizer object internals int packetizer_print(packetizer _p); // access methods unsigned int packetizer_get_dec_msg_len(packetizer _p); unsigned int packetizer_get_enc_msg_len(packetizer _p); crc_scheme packetizer_get_crc (packetizer _p); fec_scheme packetizer_get_fec0 (packetizer _p); fec_scheme packetizer_get_fec1 (packetizer _p); // Execute the packetizer on an input message // // _p : packetizer object // _msg : input message (uncoded bytes) // _pkt : encoded output message int packetizer_encode(packetizer _p, const unsigned char * _msg, unsigned char * _pkt); // Execute the packetizer to decode an input message, return validity // check of resulting data // // _p : packetizer object // _pkt : input message (coded bytes) // _msg : decoded output message int packetizer_decode(packetizer _p, const unsigned char * _pkt, unsigned char * _msg); // Execute the packetizer to decode an input message, return validity // check of resulting data // // _p : packetizer object // _pkt : input message (coded soft bits) // _msg : decoded output message int packetizer_decode_soft(packetizer _p, const unsigned char * _pkt, unsigned char * _msg); // // interleaver // typedef struct interleaver_s * interleaver; // create interleaver // _n : number of bytes interleaver interleaver_create(unsigned int _n); // Copy object including all internal objects and state interleaver linterleaver_copy(interleaver _q); // destroy interleaver object int interleaver_destroy(interleaver _q); // print interleaver object internals int interleaver_print(interleaver _q); // set depth (number of internal iterations) // _q : interleaver object // _depth : depth int interleaver_set_depth(interleaver _q, unsigned int _depth); // execute forward interleaver (encoder) // _q : interleaver object // _msg_dec : decoded (un-interleaved) message // _msg_enc : encoded (interleaved) message int interleaver_encode(interleaver _q, unsigned char * _msg_dec, unsigned char * _msg_enc); // execute forward interleaver (encoder) on soft bits // _q : interleaver object // _msg_dec : decoded (un-interleaved) message // _msg_enc : encoded (interleaved) message int interleaver_encode_soft(interleaver _q, unsigned char * _msg_dec, unsigned char * _msg_enc); // execute reverse interleaver (decoder) // _q : interleaver object // _msg_enc : encoded (interleaved) message // _msg_dec : decoded (un-interleaved) message int interleaver_decode(interleaver _q, unsigned char * _msg_enc, unsigned char * _msg_dec); // execute reverse interleaver (decoder) on soft bits // _q : interleaver object // _msg_enc : encoded (interleaved) message // _msg_dec : decoded (un-interleaved) message int interleaver_decode_soft(interleaver _q, unsigned char * _msg_enc, unsigned char * _msg_dec); // // MODULE : fft (fast Fourier transform) // // type of transform typedef enum { LIQUID_FFT_UNKNOWN = 0, // unknown transform type // regular complex one-dimensional transforms LIQUID_FFT_FORWARD = +1, // complex one-dimensional FFT LIQUID_FFT_BACKWARD = -1, // complex one-dimensional inverse FFT // discrete cosine transforms LIQUID_FFT_REDFT00 = 10, // real one-dimensional DCT-I LIQUID_FFT_REDFT10 = 11, // real one-dimensional DCT-II LIQUID_FFT_REDFT01 = 12, // real one-dimensional DCT-III LIQUID_FFT_REDFT11 = 13, // real one-dimensional DCT-IV // discrete sine transforms LIQUID_FFT_RODFT00 = 20, // real one-dimensional DST-I LIQUID_FFT_RODFT10 = 21, // real one-dimensional DST-II LIQUID_FFT_RODFT01 = 22, // real one-dimensional DST-III LIQUID_FFT_RODFT11 = 23, // real one-dimensional DST-IV // modified discrete cosine transform LIQUID_FFT_MDCT = 30, // MDCT LIQUID_FFT_IMDCT = 31, // IMDCT } liquid_fft_type; #define LIQUID_FFT_MANGLE_FLOAT(name) LIQUID_CONCAT(fft,name) // Macro : FFT // FFT : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_FFT_DEFINE_API(FFT,T,TC) \ \ /* Fast Fourier Transform (FFT) and inverse (plan) object */ \ typedef struct FFT(plan_s) * FFT(plan); \ \ /* Allocate a one-dimensional array similar to the ordinary malloc. The */ \ /* implementation may internally align the allocated memory to support */ \ /* some optimizations. Use the result as the input or output array */ \ /* argument to one of the fft_create* methods. As with the ordinary */ \ /* malloc, the result must be typecast to the proper type. Memory */ \ /* allocated by this function must be deallocated by fft_free and not */ \ /* by the ordinary free. */ \ /* _n : array size */ \ void * FFT(_malloc)(unsigned int _n); \ \ /* Free the one-dimensional array allocated by fft_malloc. */ \ /* _x : pointer to array */ \ void FFT(_free)(void * _x); \ \ /* Create regular complex one-dimensional transform */ \ /* _n : transform size */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _y : pointer to output array, [size: _n x 1] */ \ /* _dir : direction (e.g. LIQUID_FFT_FORWARD) */ \ /* _flags : options, optimization */ \ FFT(plan) FFT(_create_plan)(unsigned int _n, \ TC * _x, \ TC * _y, \ int _dir, \ int _flags); \ \ /* Create real-to-real one-dimensional transform */ \ /* _n : transform size */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _y : pointer to output array, [size: _n x 1] */ \ /* _type : transform type (e.g. LIQUID_FFT_REDFT00) */ \ /* _flags : options, optimization */ \ FFT(plan) FFT(_create_plan_r2r_1d)(unsigned int _n, \ T * _x, \ T * _y, \ int _type, \ int _flags); \ \ /* Destroy transform and free all internally-allocated memory */ \ int FFT(_destroy_plan)(FFT(plan) _p); \ \ /* Print transform plan and internal strategy to stdout. This includes */ \ /* information on the strategy for computing large transforms with many */ \ /* prime factors or with large prime factors. */ \ int FFT(_print_plan)(FFT(plan) _p); \ \ /* Run the transform */ \ int FFT(_execute)(FFT(plan) _p); \ \ /* Perform n-point FFT allocating plan internally */ \ /* _nfft : fft size */ \ /* _x : input array, [size: _nfft x 1] */ \ /* _y : output array, [size: _nfft x 1] */ \ /* _dir : fft direction: LIQUID_FFT_{FORWARD,BACKWARD} */ \ /* _flags : fft flags */ \ int FFT(_run)(unsigned int _n, \ TC * _x, \ TC * _y, \ int _dir, \ int _flags); \ \ /* Perform n-point real one-dimensional FFT allocating plan internally */ \ /* _nfft : fft size */ \ /* _x : input array, [size: _nfft x 1] */ \ /* _y : output array, [size: _nfft x 1] */ \ /* _type : fft type, e.g. LIQUID_FFT_REDFT10 */ \ /* _flags : fft flags */ \ int FFT(_r2r_1d_run)(unsigned int _n, \ T * _x, \ T * _y, \ int _type, \ int _flags); \ \ /* Perform _n-point fft shift */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : input array size */ \ int FFT(_shift)(TC * _x, \ unsigned int _n); \ LIQUID_FFT_DEFINE_API(LIQUID_FFT_MANGLE_FLOAT,float,liquid_float_complex) // If using fftw library (and not overridden with configuration), clean up // planner's persistent data. This must be done outside any methods as fftw // uses *static memory* in its planner which cannot be cleaned up if any // other function or method in the calling process creates or uses an fftw // plan. int liquid_fftwf_cleanup_wrapper(void); // antiquated fft methods // FFT(plan) FFT(_create_plan_mdct)(unsigned int _n, // T * _x, // T * _y, // int _kind, // int _flags); // // spectral periodogram // #define LIQUID_SPGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(spgramcf,name) #define LIQUID_SPGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(spgramf, name) #define LIQUID_SPGRAM_PSD_MIN (1e-12) // Macro : SPGRAM // SPGRAM : name-mangling macro // T : primitive data type // TC : primitive data type (complex) // TI : primitive data type (input) #define LIQUID_SPGRAM_DEFINE_API(SPGRAM,T,TC,TI) \ \ /* Spectral periodogram object for computing power spectral density */ \ /* estimates of various signals */ \ typedef struct SPGRAM(_s) * SPGRAM(); \ \ /* Create spgram object, fully defined */ \ /* _nfft : transform (FFT) size, _nfft >= 2 */ \ /* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ /* _window_len : window length, 1 <= _window_len <= _nfft */ \ /* _delay : delay between transforms, _delay > 0 */ \ SPGRAM() SPGRAM(_create)(unsigned int _nfft, \ int _wtype, \ unsigned int _window_len, \ unsigned int _delay); \ \ /* Create default spgram object of a particular transform size using */ \ /* the Kaiser-Bessel window (LIQUID_WINDOW_KAISER), a window length */ \ /* equal to _nfft/2, and a delay of _nfft/4 */ \ /* _nfft : FFT size, _nfft >= 2 */ \ SPGRAM() SPGRAM(_create_default)(unsigned int _nfft); \ \ /* Copy object including all internal objects and state */ \ SPGRAM() SPGRAM(_copy)(SPGRAM() _q); \ \ /* Destroy spgram object, freeing all internally-allocated memory */ \ int SPGRAM(_destroy)(SPGRAM() _q); \ \ /* Clears the internal state of the object, but not the internal buffer */ \ int SPGRAM(_clear)(SPGRAM() _q); \ \ /* Reset the object to its original state completely. This effectively */ \ /* executes the clear() method and then resets the internal buffer */ \ int SPGRAM(_reset)(SPGRAM() _q); \ \ /* Print internal state of the object to stdout */ \ int SPGRAM(_print)(SPGRAM() _q); \ \ /* Set the filter bandwidth for accumulating independent transform */ \ /* squared magnitude outputs. */ \ /* This is used to compute a running time-average power spectral */ \ /* density output. */ \ /* The value of _alpha determines how the power spectral estimate is */ \ /* accumulated across transforms and can range from 0 to 1 with a */ \ /* special case of -1 to accumulate infinitely. */ \ /* Setting _alpha to 0 minimizes the bandwidth and the PSD estimate */ \ /* will never update. */ \ /* Setting _alpha to 1 forces the object to always use the most recent */ \ /* spectral estimate. */ \ /* Setting _alpha to -1 is a special case to enable infinite spectral */ \ /* accumulation. */ \ /* _q : spectral periodogram object */ \ /* _alpha : forgetting factor, set to -1 for infinite, 0<=_alpha<=1 */ \ int SPGRAM(_set_alpha)(SPGRAM() _q, \ float _alpha); \ \ /* Get the filter bandwidth for accumulating independent transform */ \ /* squared magnitude outputs. */ \ float SPGRAM(_get_alpha)(SPGRAM() _q); \ \ /* Set the center frequency of the received signal. */ \ /* This is for display purposes only when generating the output image. */ \ /* _q : spectral periodogram object */ \ /* _freq : center frequency [Hz] */ \ int SPGRAM(_set_freq)(SPGRAM() _q, \ float _freq); \ \ /* Set the sample rate (frequency) of the received signal. */ \ /* This is for display purposes only when generating the output image. */ \ /* _q : spectral periodogram object */ \ /* _rate : sample rate [Hz] */ \ int SPGRAM(_set_rate)(SPGRAM() _q, \ float _rate); \ \ /* Get transform (FFT) size */ \ unsigned int SPGRAM(_get_nfft)(SPGRAM() _q); \ \ /* Get window length */ \ unsigned int SPGRAM(_get_window_len)(SPGRAM() _q); \ \ /* Get delay between transforms */ \ unsigned int SPGRAM(_get_delay)(SPGRAM() _q); \ \ /* Get window type used for spectral estimation */ \ int SPGRAM(_get_wtype)(SPGRAM() _q); \ \ /* Get number of samples processed since reset */ \ unsigned long long int SPGRAM(_get_num_samples)(SPGRAM() _q); \ \ /* Get number of samples processed since object was created */ \ unsigned long long int SPGRAM(_get_num_samples_total)(SPGRAM() _q); \ \ /* Get number of transforms processed since reset */ \ unsigned long long int SPGRAM(_get_num_transforms)(SPGRAM() _q); \ \ /* Get number of transforms processed since object was created */ \ unsigned long long int SPGRAM(_get_num_transforms_total)(SPGRAM() _q); \ \ /* Push a single sample into the object, executing internal transform */ \ /* as necessary. */ \ /* _q : spgram object */ \ /* _x : input sample */ \ int SPGRAM(_push)(SPGRAM() _q, \ TI _x); \ \ /* Write a block of samples to the object, executing internal */ \ /* transform as necessary. */ \ /* _q : spgram object */ \ /* _x : input buffer, [size: _n x 1] */ \ /* _n : input buffer length */ \ int SPGRAM(_write)(SPGRAM() _q, \ TI * _x, \ unsigned int _n); \ \ /* Compute spectral periodogram output (fft-shifted values, linear) */ \ /* from current buffer contents */ \ /* _q : spgram object */ \ /* _psd : output spectrum (linear), [size: _nfft x 1] */ \ int SPGRAM(_get_psd_mag)(SPGRAM() _q, \ T * _psd); \ \ /* Compute spectral periodogram output (fft-shifted values in dB) from */ \ /* current buffer contents */ \ /* _q : spgram object */ \ /* _psd : output spectrum (dB), [size: _nfft x 1] */ \ int SPGRAM(_get_psd)(SPGRAM() _q, \ T * _psd); \ \ /* Export stand-alone gnuplot file for plotting output spectrum, */ \ /* returning 0 on success, anything other than 0 for failure */ \ /* _q : spgram object */ \ /* _filename : input buffer, [size: _n x 1] */ \ int SPGRAM(_export_gnuplot)(SPGRAM() _q, \ const char * _filename); \ \ /* Estimate spectrum on input signal (create temporary object for */ \ /* convenience */ \ /* _nfft : FFT size */ \ /* _x : input signal, [size: _n x 1] */ \ /* _n : input signal length */ \ /* _psd : output spectrum, [size: _nfft x 1] */ \ int SPGRAM(_estimate_psd)(unsigned int _nfft, \ TI * _x, \ unsigned int _n, \ T * _psd); \ LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_CFLOAT, float, liquid_float_complex, liquid_float_complex) LIQUID_SPGRAM_DEFINE_API(LIQUID_SPGRAM_MANGLE_FLOAT, float, liquid_float_complex, float) // // asgram : ascii spectral periodogram // #define LIQUID_ASGRAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(asgramcf,name) #define LIQUID_ASGRAM_MANGLE_FLOAT(name) LIQUID_CONCAT(asgramf, name) // Macro : ASGRAM // ASGRAM : name-mangling macro // T : primitive data type // TC : primitive data type (complex) // TI : primitive data type (input) #define LIQUID_ASGRAM_DEFINE_API(ASGRAM,T,TC,TI) \ \ /* ASCII spectral periodogram for computing and displaying an estimate */ \ /* of a signal's power spectrum with ASCII characters */ \ typedef struct ASGRAM(_s) * ASGRAM(); \ \ /* Create asgram object with size _nfft */ \ /* _nfft : size of FFT taken for each transform (character width) */ \ ASGRAM() ASGRAM(_create)(unsigned int _nfft); \ \ /* Copy object including all internal objects and state */ \ ASGRAM() ASGRAM(_copy)(ASGRAM() _q); \ \ /* Destroy asgram object, freeing all internally-allocated memory */ \ int ASGRAM(_destroy)(ASGRAM() _q); \ \ /* Reset the internal state of the asgram object */ \ int ASGRAM(_reset)(ASGRAM() _q); \ \ /* Set the scale and offset for spectrogram in terms of dB for display */ \ /* purposes */ \ /* _q : asgram object */ \ /* _ref : signal reference level [dB] */ \ /* _div : signal division [dB] */ \ int ASGRAM(_set_scale)(ASGRAM() _q, \ float _ref, \ float _div); \ \ /* Set the display's 10 characters for output string starting from the */ \ /* weakest and ending with the strongest */ \ /* _q : asgram object */ \ /* _ascii : 10-character display, default: " .,-+*&NM#" */ \ int ASGRAM(_set_display)(ASGRAM() _q, \ const char * _ascii); \ \ /* Push a single sample into the asgram object, executing internal */ \ /* transform as necessary. */ \ /* _q : asgram object */ \ /* _x : input sample */ \ int ASGRAM(_push)(ASGRAM() _q, \ TI _x); \ \ /* Write a block of samples to the asgram object, executing internal */ \ /* transforms as necessary. */ \ /* _q : asgram object */ \ /* _x : input buffer, [size: _n x 1] */ \ /* _n : input buffer length */ \ int ASGRAM(_write)(ASGRAM() _q, \ TI * _x, \ unsigned int _n); \ \ /* Compute spectral periodogram output from current buffer contents */ \ /* and return the ascii character string to display along with the peak */ \ /* value and its frequency location */ \ /* _q : asgram object */ \ /* _ascii : output ASCII string, [size: _nfft x 1] */ \ /* _peakval : peak power spectral density value [dB] */ \ /* _peakfreq : peak power spectral density frequency */ \ int ASGRAM(_execute)(ASGRAM() _q, \ char * _ascii, \ float * _peakval, \ float * _peakfreq); \ \ /* Compute spectral periodogram output from current buffer contents and */ \ /* print standard format to stdout */ \ int ASGRAM(_print)(ASGRAM() _q); \ LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_CFLOAT, float, liquid_float_complex, liquid_float_complex) LIQUID_ASGRAM_DEFINE_API(LIQUID_ASGRAM_MANGLE_FLOAT, float, liquid_float_complex, float) // // spectral periodogram waterfall // #define LIQUID_SPWATERFALL_MANGLE_CFLOAT(name) LIQUID_CONCAT(spwaterfallcf,name) #define LIQUID_SPWATERFALL_MANGLE_FLOAT(name) LIQUID_CONCAT(spwaterfallf, name) // Macro : SPWATERFALL // SPWATERFALL : name-mangling macro // T : primitive data type // TC : primitive data type (complex) // TI : primitive data type (input) #define LIQUID_SPWATERFALL_DEFINE_API(SPWATERFALL,T,TC,TI) \ \ /* Spectral periodogram waterfall object for computing time-varying */ \ /* power spectral density estimates */ \ typedef struct SPWATERFALL(_s) * SPWATERFALL(); \ \ /* Create spwaterfall object, fully defined */ \ /* _nfft : transform (FFT) size, _nfft >= 2 */ \ /* _wtype : window type, e.g. LIQUID_WINDOW_HAMMING */ \ /* _window_len : window length, 1 <= _window_len <= _nfft */ \ /* _delay : delay between transforms, _delay > 0 */ \ /* _time : number of aggregated transforms, _time > 0 */ \ SPWATERFALL() SPWATERFALL(_create)(unsigned int _nfft, \ int _wtype, \ unsigned int _window_len, \ unsigned int _delay, \ unsigned int _time); \ \ /* Create default spwatefall object (Kaiser-Bessel window) */ \ /* _nfft : transform size, _nfft >= 2 */ \ /* _time : delay between transforms, _delay > 0 */ \ SPWATERFALL() SPWATERFALL(_create_default)(unsigned int _nfft, \ unsigned int _time); \ \ /* Copy object including all internal objects and state */ \ SPWATERFALL() SPWATERFALL(_copy)(SPWATERFALL() _q); \ \ /* Destroy spwaterfall object, freeing all internally-allocated memory */ \ int SPWATERFALL(_destroy)(SPWATERFALL() _q); \ \ /* Clears the internal state of the object, but not the internal buffer */ \ int SPWATERFALL(_clear)(SPWATERFALL() _q); \ \ /* Reset the object to its original state completely. This effectively */ \ /* executes the clear() method and then resets the internal buffer */ \ int SPWATERFALL(_reset)(SPWATERFALL() _q); \ \ /* Print internal state of the object to stdout */ \ int SPWATERFALL(_print)(SPWATERFALL() _q); \ \ /* Get number of samples processed since object was created */ \ uint64_t SPWATERFALL(_get_num_samples_total)(SPWATERFALL() _q); \ \ /* Get FFT size (columns in PSD output) */ \ unsigned int SPWATERFALL(_get_num_freq)(SPWATERFALL() _q); \ \ /* Get number of accumulated FFTs (rows in PSD output) */ \ unsigned int SPWATERFALL(_get_num_time)(SPWATERFALL() _q); \ \ /* Get window length used in spectral estimation */ \ unsigned int SPWATERFALL(_get_window_len)(SPWATERFALL() _q); \ \ /* Get delay between transforms used in spectral estimation */ \ unsigned int SPWATERFALL(_get_delay)(SPWATERFALL() _q); \ \ /* Get window type used in spectral estimation */ \ int SPWATERFALL(_get_wtype)(SPWATERFALL() _q); \ \ /* Get power spectral density (PSD), size: nfft x time */ \ const T * SPWATERFALL(_get_psd)(SPWATERFALL() _q); \ \ /* Set the center frequency of the received signal. */ \ /* This is for display purposes only when generating the output image. */ \ /* _q : spectral periodogram waterfall object */ \ /* _freq : center frequency [Hz] */ \ int SPWATERFALL(_set_freq)(SPWATERFALL() _q, \ float _freq); \ \ /* Set the sample rate (frequency) of the received signal. */ \ /* This is for display purposes only when generating the output image. */ \ /* _q : spectral periodogram waterfall object */ \ /* _rate : sample rate [Hz] */ \ int SPWATERFALL(_set_rate)(SPWATERFALL() _q, \ float _rate); \ \ /* Set the canvas size. */ \ /* This is for display purposes only when generating the output image. */ \ /* _q : spectral periodogram waterfall object */ \ /* _width : image width [pixels] */ \ /* _height : image height [pixels] */ \ int SPWATERFALL(_set_dims)(SPWATERFALL() _q, \ unsigned int _width, \ unsigned int _height); \ \ /* Set commands for executing directly before 'plot' statement. */ \ /* _q : spectral periodogram waterfall object */ \ /* _commands : gnuplot commands separated by semicolons */ \ int SPWATERFALL(_set_commands)(SPWATERFALL() _q, \ const char * _commands); \ \ /* Push a single sample into the object, executing internal transform */ \ /* as necessary. */ \ /* _q : spwaterfall object */ \ /* _x : input sample */ \ int SPWATERFALL(_push)(SPWATERFALL() _q, \ TI _x); \ \ /* Write a block of samples to the object, executing internal */ \ /* transform as necessary. */ \ /* _q : spwaterfall object */ \ /* _x : input buffer, [size: _n x 1] */ \ /* _n : input buffer length */ \ int SPWATERFALL(_write)(SPWATERFALL() _q, \ TI * _x, \ unsigned int _n); \ \ /* Export set of files for plotting */ \ /* _q : spwaterfall object */ \ /* _base : base filename (will export .gnu, .bin, and .png files) */ \ int SPWATERFALL(_export)(SPWATERFALL() _q, \ const char * _base); \ LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_CFLOAT, float, liquid_float_complex, liquid_float_complex) LIQUID_SPWATERFALL_DEFINE_API(LIQUID_SPWATERFALL_MANGLE_FLOAT, float, liquid_float_complex, float) // // MODULE : filter // // // firdes: finite impulse response filter design // // prototypes #define LIQUID_FIRFILT_NUM_TYPES (16) typedef enum { LIQUID_FIRFILT_UNKNOWN=0, // unknown filter type // Nyquist filter prototypes LIQUID_FIRFILT_KAISER, // Nyquist Kaiser filter LIQUID_FIRFILT_PM, // Parks-McClellan filter LIQUID_FIRFILT_RCOS, // raised-cosine filter LIQUID_FIRFILT_FEXP, // flipped exponential LIQUID_FIRFILT_FSECH, // flipped hyperbolic secant LIQUID_FIRFILT_FARCSECH, // flipped arc-hyperbolic secant // root-Nyquist filter prototypes LIQUID_FIRFILT_ARKAISER, // root-Nyquist Kaiser (approximate optimum) LIQUID_FIRFILT_RKAISER, // root-Nyquist Kaiser (true optimum) LIQUID_FIRFILT_RRC, // root raised-cosine LIQUID_FIRFILT_hM3, // harris-Moerder-3 filter LIQUID_FIRFILT_GMSKTX, // GMSK transmit filter LIQUID_FIRFILT_GMSKRX, // GMSK receive filter LIQUID_FIRFILT_RFEXP, // flipped exponential LIQUID_FIRFILT_RFSECH, // flipped hyperbolic secant LIQUID_FIRFILT_RFARCSECH, // flipped arc-hyperbolic secant } liquid_firfilt_type; // Design (root-)Nyquist filter from prototype // _type : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples/symbol, _k > 1 // _m : symbol delay, _m > 0 // _beta : excess bandwidth factor, _beta in [0,1) // _dt : fractional sample delay, _dt in [-1,1] // _h : output coefficient buffer (length: 2*_k*_m+1) int liquid_firdes_prototype(liquid_firfilt_type _type, unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // pretty names for filter design types extern const char * liquid_firfilt_type_str[LIQUID_FIRFILT_NUM_TYPES][2]; // returns filter type based on input string int liquid_getopt_str2firfilt(const char * _str); // estimate required filter length given // _df : transition bandwidth (0 < _b < 0.5) // _as : stop-band attenuation [dB], _as > 0 unsigned int estimate_req_filter_len(float _df, float _as); // estimate filter stop-band attenuation given // _df : transition bandwidth (0 < _b < 0.5) // _n : filter length float estimate_req_filter_As(float _df, unsigned int _n); // estimate filter transition bandwidth given // _as : stop-band attenuation [dB], _as > 0 // _n : filter length float estimate_req_filter_df(float _as, unsigned int _n); // returns the Kaiser window beta factor give the filter's target // stop-band attenuation (As) [Vaidyanathan:1993] // _as : target filter's stop-band attenuation [dB], _as > 0 float kaiser_beta_As(float _as); // Design FIR filter using Parks-McClellan algorithm // band type specifier typedef enum { LIQUID_FIRDESPM_BANDPASS=0, // regular band-pass filter LIQUID_FIRDESPM_DIFFERENTIATOR, // differentiating filter LIQUID_FIRDESPM_HILBERT // Hilbert transform } liquid_firdespm_btype; // weighting type specifier typedef enum { LIQUID_FIRDESPM_FLATWEIGHT=0, // flat weighting LIQUID_FIRDESPM_EXPWEIGHT, // exponential weighting LIQUID_FIRDESPM_LINWEIGHT, // linear weighting } liquid_firdespm_wtype; // run filter design (full life cycle of object) // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _des : desired response, [size: _num_bands x 1] // _weights : response weighting, [size: _num_bands x 1] // _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) // _h : output coefficients array, [size: _h_len x 1] int firdespm_run(unsigned int _h_len, unsigned int _num_bands, float * _bands, float * _des, float * _weights, liquid_firdespm_wtype * _wtype, liquid_firdespm_btype _btype, float * _h); // run filter design for basic low-pass filter // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 [ignored] // _h : output coefficient buffer, [size: _n x 1] int firdespm_lowpass(unsigned int _n, float _fc, float _as, float _mu, float * _h); // firdespm response callback function // _frequency : normalized frequency // _userdata : pointer to userdata // _desired : (return) desired response // _weight : (return) weight typedef int (*firdespm_callback)(double _frequency, void * _userdata, double * _desired, double * _weight); // structured object typedef struct firdespm_s * firdespm; // create firdespm object // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _des : desired response, [size: _num_bands x 1] // _weights : response weighting, [size: _num_bands x 1] // _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) firdespm firdespm_create(unsigned int _h_len, unsigned int _num_bands, float * _bands, float * _des, float * _weights, liquid_firdespm_wtype * _wtype, liquid_firdespm_btype _btype); // create firdespm object with user-defined callback // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) // _callback : user-defined callback for specifying desired response & weights // _userdata : user-defined data structure for callback function firdespm firdespm_create_callback(unsigned int _h_len, unsigned int _num_bands, float * _bands, liquid_firdespm_btype _btype, firdespm_callback _callback, void * _userdata); // Copy object including all internal objects and state firdespm firdespm_copy(firdespm _q); // destroy firdespm object int firdespm_destroy(firdespm _q); // print firdespm object internals int firdespm_print(firdespm _q); // execute filter design, storing result in _h int firdespm_execute(firdespm _q, float * _h); // Design halfband filter using Parks-McClellan algorithm given the // filter length and desired transition band // _m : filter semi-length, _m > 0 // _ft : filter transition band (relative), 0 < _ft < 0.5 // _h : output coefficient buffer, [size: 4 _m + 1 x 1] int liquid_firdespm_halfband_ft(unsigned int _m, float _ft, float * _h); // Design halfband filter using Parks-McClellan algorithm given the // filter length and desired stop-band suppression // _m : filter semi-length, _m > 0 // _as : filter stop-band suppression [dB], _as > 0 // _h : output coefficient buffer, [size: 4 _m + 1 x 1] int liquid_firdespm_halfband_as(unsigned int _m, float _as, float * _h); // Design FIR filter using generic window/taper method // _wtype : window type, e.g. LIQUID_WINDOW_HAMMING // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _arg : window-specific argument, if required // _h : output coefficient buffer, [size: _n x 1] int liquid_firdes_windowf(int _wtype, unsigned int _n, float _fc, float _arg, float * _h); // Design FIR using Kaiser window // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 // _h : output coefficient buffer, [size: _n x 1] int liquid_firdes_kaiser(unsigned int _n, float _fc, float _as, float _mu, float *_h); // Design finite impulse response notch filter // _m : filter semi-length, m in [1,1000] // _f0 : filter notch frequency (normalized), -0.5 <= _fc <= 0.5 // _as : stop-band attenuation [dB], _as > 0 // _h : output coefficient buffer, [size: 2*_m+1 x 1] int liquid_firdes_notch(unsigned int _m, float _f0, float _as, float * _h); // Design FIR doppler filter // _n : filter length // _fd : normalized doppler frequency (0 < _fd < 0.5) // _K : Rice fading factor (K >= 0) // _theta : LoS component angle of arrival // _h : output coefficient buffer int liquid_firdes_doppler(unsigned int _n, float _fd, float _K, float _theta, float * _h); // Design Nyquist raised-cosine filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_rcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design root-Nyquist raised-cosine filter int liquid_firdes_rrcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design root-Nyquist Kaiser filter int liquid_firdes_rkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design (approximate) root-Nyquist Kaiser filter int liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design root-Nyquist harris-Moerder filter int liquid_firdes_hM3(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design GMSK transmit and receive filters int liquid_firdes_gmsktx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); int liquid_firdes_gmskrx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design flipped exponential Nyquist/root-Nyquist filters int liquid_firdes_fexp( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); int liquid_firdes_rfexp(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design flipped hyperbolic secand Nyquist/root-Nyquist filters int liquid_firdes_fsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); int liquid_firdes_rfsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Design flipped arc-hyperbolic secand Nyquist/root-Nyquist filters int liquid_firdes_farcsech( unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); int liquid_firdes_rfarcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // Compute group delay for an FIR filter // _h : filter coefficients array // _n : filter length // _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) float fir_group_delay(float * _h, unsigned int _n, float _fc); // Compute group delay for an IIR filter // _b : filter numerator coefficients // _nb : filter numerator length // _a : filter denominator coefficients // _na : filter denominator length // _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) float iir_group_delay(float * _b, unsigned int _nb, float * _a, unsigned int _na, float _fc); // liquid_filter_autocorr() // // Compute auto-correlation of filter at a specific lag. // // _h : filter coefficients, [size: _h_len x 1] // _h_len : filter length // _lag : auto-correlation lag (samples) float liquid_filter_autocorr(float * _h, unsigned int _h_len, int _lag); // liquid_filter_crosscorr() // // Compute cross-correlation of two filters at a specific lag. // // _h : filter coefficients, [size: _h_len] // _h_len : filter length // _g : filter coefficients, [size: _g_len] // _g_len : filter length // _lag : cross-correlation lag (samples) float liquid_filter_crosscorr(float * _h, unsigned int _h_len, float * _g, unsigned int _g_len, int _lag); // liquid_filter_isi() // // Compute inter-symbol interference (ISI)--both RMS and // maximum--for the filter _h. // // _h : filter coefficients, [size: 2*_k*_m+1 x 1] // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _rms : output root mean-squared ISI // _max : maximum ISI void liquid_filter_isi(float * _h, unsigned int _k, unsigned int _m, float * _rms, float * _max); // Compute relative out-of-band energy // // _h : filter coefficients, [size: _h_len x 1] // _h_len : filter length // _fc : analysis cut-off frequency // _nfft : fft size float liquid_filter_energy(float * _h, unsigned int _h_len, float _fc, unsigned int _nfft); // Get static frequency response from filter coefficients at particular // frequency with real-valued coefficients // _h : coefficients, [size: _h_len x 1] // _h_len : length of coefficients array // _fc : center frequency for analysis, -0.5 <= _fc <= 0.5 // _H : pointer to output value int liquid_freqrespf(float * _h, unsigned int _h_len, float _fc, liquid_float_complex * _H); // Get static frequency response from filter coefficients at particular // frequency with complex coefficients // _h : coefficients, [size: _h_len x 1] // _h_len : length of coefficients array // _fc : center frequency for analysis, -0.5 <= _fc <= 0.5 // _H : pointer to output value int liquid_freqrespcf(liquid_float_complex * _h, unsigned int _h_len, float _fc, liquid_float_complex * _H); // // IIR filter design // // IIR filter design filter type typedef enum { LIQUID_IIRDES_BUTTER=0, LIQUID_IIRDES_CHEBY1, LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_ELLIP, LIQUID_IIRDES_BESSEL } liquid_iirdes_filtertype; // IIR filter design band type typedef enum { LIQUID_IIRDES_LOWPASS=0, LIQUID_IIRDES_HIGHPASS, LIQUID_IIRDES_BANDPASS, LIQUID_IIRDES_BANDSTOP } liquid_iirdes_bandtype; // IIR filter design coefficients format typedef enum { LIQUID_IIRDES_SOS=0, LIQUID_IIRDES_TF } liquid_iirdes_format; // IIR filter design template // _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) // _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) // _format : coefficients format (e.g. LIQUID_IIRDES_SOS) // _n : filter order // _fc : low-pass prototype cut-off frequency // _f0 : center frequency (band-pass, band-stop) // _ap : pass-band ripple in dB // _as : stop-band ripple in dB // _b : numerator // _a : denominator int liquid_iirdes(liquid_iirdes_filtertype _ftype, liquid_iirdes_bandtype _btype, liquid_iirdes_format _format, unsigned int _n, float _fc, float _f0, float _ap, float _as, float * _b, float * _a); // compute analog zeros, poles, gain for specific filter types int butter_azpkf(unsigned int _n, liquid_float_complex * _za, liquid_float_complex * _pa, liquid_float_complex * _ka); int cheby1_azpkf(unsigned int _n, float _ep, liquid_float_complex * _z, liquid_float_complex * _p, liquid_float_complex * _k); int cheby2_azpkf(unsigned int _n, float _es, liquid_float_complex * _z, liquid_float_complex * _p, liquid_float_complex * _k); int ellip_azpkf(unsigned int _n, float _ep, float _es, liquid_float_complex * _z, liquid_float_complex * _p, liquid_float_complex * _k); int bessel_azpkf(unsigned int _n, liquid_float_complex * _z, liquid_float_complex * _p, liquid_float_complex * _k); // compute frequency pre-warping factor float iirdes_freqprewarp(liquid_iirdes_bandtype _btype, float _fc, float _f0); // convert analog z/p/k form to discrete z/p/k form (bilinear z-transform) // _za : analog zeros [length: _nza] // _nza : number of analog zeros // _pa : analog poles [length: _npa] // _npa : number of analog poles // _m : frequency pre-warping factor // _zd : output digital zeros [length: _npa] // _pd : output digital poles [length: _npa] // _kd : output digital gain (should actually be real-valued) int bilinear_zpkf(liquid_float_complex * _za, unsigned int _nza, liquid_float_complex * _pa, unsigned int _npa, liquid_float_complex _ka, float _m, liquid_float_complex * _zd, liquid_float_complex * _pd, liquid_float_complex * _kd); // compute bilinear z-transform using polynomial expansion in numerator and // denominator // // b[0] + b[1]*s + ... + b[nb]*s^(nb-1) // H(s) = ------------------------------------ // a[0] + a[1]*s + ... + a[na]*s^(na-1) // // computes H(z) = H( s -> _m*(z-1)/(z+1) ) and expands as // // bd[0] + bd[1]*z^-1 + ... + bd[nb]*z^-n // H(z) = -------------------------------------- // ad[0] + ad[1]*z^-1 + ... + ad[nb]*z^-m // // _b : numerator array, [size: _b_order+1] // _b_order : polynomial order of _b // _a : denominator array, [size: _a_order+1] // _a_order : polynomial order of _a // _m : bilateral warping factor // _bd : output digital filter numerator, [size: _b_order+1] // _ad : output digital filter numerator, [size: _a_order+1] int bilinear_nd(liquid_float_complex * _b, unsigned int _b_order, liquid_float_complex * _a, unsigned int _a_order, float _m, liquid_float_complex * _bd, liquid_float_complex * _ad); // digital z/p/k low-pass to high-pass // _zd : digital zeros (low-pass prototype), [length: _n] // _pd : digital poles (low-pass prototype), [length: _n] // _n : low-pass filter order // _zdt : output digital zeros transformed [length: _n] // _pdt : output digital poles transformed [length: _n] int iirdes_dzpk_lp2hp(liquid_float_complex * _zd, liquid_float_complex * _pd, unsigned int _n, liquid_float_complex * _zdt, liquid_float_complex * _pdt); // digital z/p/k low-pass to band-pass // _zd : digital zeros (low-pass prototype), [length: _n] // _pd : digital poles (low-pass prototype), [length: _n] // _n : low-pass filter order // _f0 : center frequency // _zdt : output digital zeros transformed [length: 2*_n] // _pdt : output digital poles transformed [length: 2*_n] int iirdes_dzpk_lp2bp(liquid_float_complex * _zd, liquid_float_complex * _pd, unsigned int _n, float _f0, liquid_float_complex * _zdt, liquid_float_complex * _pdt); // convert discrete z/p/k form to transfer function // _zd : digital zeros [length: _n] // _pd : digital poles [length: _n] // _n : filter order // _kd : digital gain // _b : output numerator [length: _n+1] // _a : output denominator [length: _n+1] int iirdes_dzpk2tff(liquid_float_complex * _zd, liquid_float_complex * _pd, unsigned int _n, liquid_float_complex _kd, float * _b, float * _a); // convert discrete z/p/k form to second-order sections // _zd : digital zeros [length: _n] // _pd : digital poles [length: _n] // _n : filter order // _kd : digital gain // _b : output numerator, [size: 3 x L+r] // _a : output denominator, [size: 3 x L+r] // where r = _n%2, L = (_n-r)/2 int iirdes_dzpk2sosf(liquid_float_complex * _zd, liquid_float_complex * _pd, unsigned int _n, liquid_float_complex _kd, float * _b, float * _a); // additional IIR filter design templates // design 2nd-order IIR filter (active lag) // 1 + t2 * s // F(s) = ------------ // 1 + t1 * s // // _w : filter bandwidth // _zeta : damping factor (1/sqrt(2) suggested) // _K : loop gain (1000 suggested) // _b : output feed-forward coefficients, [size: 3 x 1] // _a : output feed-back coefficients, [size: 3 x 1] void iirdes_pll_active_lag(float _w, float _zeta, float _K, float * _b, float * _a); // design 2nd-order IIR filter (active PI) // 1 + t2 * s // F(s) = ------------ // t1 * s // // _w : filter bandwidth // _zeta : damping factor (1/sqrt(2) suggested) // _K : loop gain (1000 suggested) // _b : output feed-forward coefficients, [size: 3 x 1] // _a : output feed-back coefficients, [size: 3 x 1] void iirdes_pll_active_PI(float _w, float _zeta, float _K, float * _b, float * _a); // checks stability of iir filter // _b : feed-forward coefficients, [size: _n x 1] // _a : feed-back coefficients, [size: _n x 1] // _n : number of coefficients int iirdes_isstable(float * _b, float * _a, unsigned int _n); // // linear prediction // // compute the linear prediction coefficients for an input signal _x // _x : input signal, [size: _n x 1] // _n : input signal length // _p : prediction filter order // _a : prediction filter, [size: _p+1 x 1] // _e : prediction error variance, [size: _p+1 x 1] void liquid_lpc(float * _x, unsigned int _n, unsigned int _p, float * _a, float * _g); // solve the Yule-Walker equations using Levinson-Durbin recursion // for _symmetric_ autocorrelation // _r : autocorrelation array, [size: _p+1 x 1] // _p : filter order // _a : output coefficients, [size: _p+1 x 1] // _e : error variance, [size: _p+1 x 1] // // NOTES: // By definition _a[0] = 1.0 void liquid_levinson(float * _r, unsigned int _p, float * _a, float * _e); // // auto-correlator (delay cross-correlation) // #define LIQUID_AUTOCORR_MANGLE_CCCF(name) LIQUID_CONCAT(autocorr_cccf,name) #define LIQUID_AUTOCORR_MANGLE_RRRF(name) LIQUID_CONCAT(autocorr_rrrf,name) // Macro: // AUTOCORR : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_AUTOCORR_DEFINE_API(AUTOCORR,TO,TC,TI) \ \ /* Computes auto-correlation with a fixed lag on input signals */ \ typedef struct AUTOCORR(_s) * AUTOCORR(); \ \ /* Create auto-correlator object with a particular window length and */ \ /* delay */ \ /* _window_size : size of the correlator window */ \ /* _delay : correlator delay [samples] */ \ AUTOCORR() AUTOCORR(_create)(unsigned int _window_size, \ unsigned int _delay); \ \ /* Destroy auto-correlator object, freeing internal memory */ \ int AUTOCORR(_destroy)(AUTOCORR() _q); \ \ /* Reset auto-correlator object's internals */ \ int AUTOCORR(_reset)(AUTOCORR() _q); \ \ /* Print auto-correlator parameters to stdout */ \ int AUTOCORR(_print)(AUTOCORR() _q); \ \ /* Push sample into auto-correlator object */ \ /* _q : auto-correlator object */ \ /* _x : single input sample */ \ int AUTOCORR(_push)(AUTOCORR() _q, \ TI _x); \ \ /* Write block of samples to auto-correlator object */ \ /* _q : auto-correlation object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : number of input samples */ \ int AUTOCORR(_write)(AUTOCORR() _q, \ TI * _x, \ unsigned int _n); \ \ /* Compute single auto-correlation output */ \ /* _q : auto-correlator object */ \ /* _rxx : auto-correlated output */ \ int AUTOCORR(_execute)(AUTOCORR() _q, \ TO * _rxx); \ \ /* Compute auto-correlation on block of samples; the input and output */ \ /* arrays may have the same pointer */ \ /* _q : auto-correlation object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _rxx : input array, [size: _n x 1] */ \ int AUTOCORR(_execute_block)(AUTOCORR() _q, \ TI * _x, \ unsigned int _n, \ TO * _rxx); \ \ /* return sum of squares of buffered samples */ \ float AUTOCORR(_get_energy)(AUTOCORR() _q); \ LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) LIQUID_AUTOCORR_DEFINE_API(LIQUID_AUTOCORR_MANGLE_RRRF, float, float, float) // // Finite impulse response filter // #define LIQUID_FIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(firfilt_rrrf,name) #define LIQUID_FIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(firfilt_crcf,name) #define LIQUID_FIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(firfilt_cccf,name) // Macro: // FIRFILT : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FIRFILT_DEFINE_API(FIRFILT,TO,TC,TI) \ \ /* Finite impulse response (FIR) filter */ \ typedef struct FIRFILT(_s) * FIRFILT(); \ \ /* Create a finite impulse response filter (firfilt) object by directly */ \ /* specifying the filter coefficients in an array */ \ /* _h : filter coefficients, [size: _n x 1] */ \ /* _n : number of filter coefficients, _n > 0 */ \ FIRFILT() FIRFILT(_create)(TC * _h, \ unsigned int _n); \ \ /* Create object using Kaiser-Bessel windowed sinc method */ \ /* _n : filter length, _n > 0 */ \ /* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ /* _as : filter stop-band attenuation [dB], _as > 0 */ \ /* _mu : fractional sample offset, -0.5 < _mu < 0.5 */ \ FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, \ float _fc, \ float _as, \ float _mu); \ \ /* Create object from square-root Nyquist prototype. */ \ /* The filter length will be \(2 k m + 1 \) samples long with a delay */ \ /* of \( k m + 1 \) samples. */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : nominal samples per symbol, _k > 1 */ \ /* _m : filter delay [symbols], _m > 0 */ \ /* _beta : rolloff factor, 0 < beta <= 1 */ \ /* _mu : fractional sample offset [samples], -0.5 < _mu < 0.5 */ \ FIRFILT() FIRFILT(_create_rnyquist)(int _type, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ float _mu); \ \ /* Create object from Parks-McClellan algorithm prototype */ \ /* _h_len : filter length, _h_len > 0 */ \ /* _fc : cutoff frequency, 0 < _fc < 0.5 */ \ /* _as : stop-band attenuation [dB], _as > 0 */ \ FIRFILT() FIRFILT(_create_firdespm)(unsigned int _h_len, \ float _fc, \ float _as); \ \ /* Create rectangular filter prototype; that is */ \ /* \( \vec{h} = \{ 1, 1, 1, \ldots 1 \} \) */ \ /* _n : length of filter [samples], 0 < _n <= 1024 */ \ FIRFILT() FIRFILT(_create_rect)(unsigned int _n); \ \ /* Create DC blocking filter from prototype */ \ /* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ /* _as : prototype filter stop-band attenuation [dB], _as > 0 */ \ FIRFILT() FIRFILT(_create_dc_blocker)(unsigned int _m, \ float _as); \ \ /* Create notch filter from prototype */ \ /* _m : prototype filter semi-length such that filter length is 2*m+1 */ \ /* _as : prototype filter stop-band attenuation [dB], _as > 0 */ \ /* _f0 : center frequency for notch, _fc in [-0.5, 0.5] */ \ FIRFILT() FIRFILT(_create_notch)(unsigned int _m, \ float _as, \ float _f0); \ \ /* Re-create filter object of potentially a different length with */ \ /* different coefficients. If the length of the filter does not change, */ \ /* not memory reallocation is invoked. */ \ /* _q : original filter object */ \ /* _h : pointer to filter coefficients, [size: _n x 1] */ \ /* _n : filter length, _n > 0 */ \ FIRFILT() FIRFILT(_recreate)(FIRFILT() _q, \ TC * _h, \ unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ FIRFILT() FIRFILT(_copy)(FIRFILT() _q); \ \ /* Destroy filter object and free all internal memory */ \ int FIRFILT(_destroy)(FIRFILT() _q); \ \ /* Reset filter object's internal buffer */ \ int FIRFILT(_reset)(FIRFILT() _q); \ \ /* Print filter object information to stdout */ \ int FIRFILT(_print)(FIRFILT() _q); \ \ /* Set output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRFILT(_set_scale)(FIRFILT() _q, \ TC _scale); \ \ /* Get output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor applied to each output sample */ \ int FIRFILT(_get_scale)(FIRFILT() _q, \ TC * _scale); \ \ /* Push sample into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : single input sample */ \ int FIRFILT(_push)(FIRFILT() _q, \ TI _x); \ \ /* Write block of samples into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : buffer of input samples, [size: _n x 1] */ \ /* _n : number of input samples */ \ int FIRFILT(_write)(FIRFILT() _q, \ TI * _x, \ unsigned int _n); \ \ /* Execute vector dot product on the filter's internal buffer and */ \ /* coefficients */ \ /* _q : filter object */ \ /* _y : pointer to single output sample */ \ int FIRFILT(_execute)(FIRFILT() _q, \ TO * _y); \ \ /* Execute filter on one sample, equivalent to push() and execute() */ \ /* _q : filter object */ \ /* _x : single input sample */ \ /* _y : pointer to single output sample */ \ int FIRFILT(_execute_one)(FIRFILT() _q, \ TI _x, \ TO * _y); \ \ /* Execute the filter on a block of input samples; in-place operation */ \ /* is permitted (_x and _y may point to the same place in memory) */ \ /* _q : filter object */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _y : pointer to output array, [size: _n x 1] */ \ int FIRFILT(_execute_block)(FIRFILT() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Get length of filter object (number of internal coefficients) */ \ unsigned int FIRFILT(_get_length)(FIRFILT() _q); \ \ /* Get pointer to coefficients array */ \ const TC * FIRFILT(_get_coefficients)(FIRFILT() _q); \ \ /* Copy internal coefficients to external buffer */ \ /* _q : filter object */ \ /* _h : pointer to output coefficients array, [size: _n x 1] */ \ int FIRFILT(_copy_coefficients)(FIRFILT() _q, \ TC * _h); \ \ /* Compute complex frequency response of filter object */ \ /* _q : filter object */ \ /* _fc : normalized frequency for evaluation */ \ /* _H : pointer to output complex frequency response */ \ int FIRFILT(_freqresponse)(FIRFILT() _q, \ float _fc, \ liquid_float_complex * _H); \ \ /* Compute and return group delay of filter object */ \ /* _q : filter object */ \ /* _fc : frequency to evaluate */ \ float FIRFILT(_groupdelay)(FIRFILT() _q, \ float _fc); \ LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_RRRF, float, float, float) LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FIRFILT_DEFINE_API(LIQUID_FIRFILT_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // fdelay : arbitrary delay #define LIQUID_FDELAY_MANGLE_RRRF(name) LIQUID_CONCAT(fdelay_rrrf,name) #define LIQUID_FDELAY_MANGLE_CRCF(name) LIQUID_CONCAT(fdelay_crcf,name) // Macro: // FDELAY : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FDELAY_DEFINE_API(FDELAY,TO,TC,TI) \ \ /* Finite impulse response (FIR) filter */ \ typedef struct FDELAY(_s) * FDELAY(); \ \ /* Create a delay object with a maximum offset and filter specification */ \ /* _nmax : maximum integer sample offset */ \ /* _m : polyphase filter-bank semi-length, _m > 0 */ \ /* _npfb : number of filters in polyphase filter-bank, _npfb > 0 */ \ FDELAY() FDELAY(_create)(unsigned int _nmax, \ unsigned int _m, \ unsigned int _npfb); \ \ /* Create a delay object with a maximum offset and default filter */ \ /* parameters (_m = 8, _npfb = 64) */ \ /* _nmax : maximum integer sample offset */ \ FDELAY() FDELAY(_create_default)(unsigned int _nmax); \ \ /* Destroy delay object and free all internal memory */ \ int FDELAY(_destroy)(FDELAY() _q); \ \ /* Reset delay object internals */ \ int FDELAY(_reset)(FDELAY() _q); \ \ /* Print delay object internals */ \ int FDELAY(_print)(FDELAY() _q); \ \ /* Get current delay (accounting for _m?) */ \ float FDELAY(_get_delay)(FDELAY() _q); \ int FDELAY(_set_delay)(FDELAY() _q, float _delay); \ int FDELAY(_adjust_delay)(FDELAY() _q, float _delta); \ \ unsigned int FDELAY(_get_nmax)(FDELAY() _q); \ unsigned int FDELAY(_get_m) (FDELAY() _q); \ unsigned int FDELAY(_get_npfb)(FDELAY() _q); \ \ /* Push sample into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : single input sample */ \ int FDELAY(_push)(FDELAY() _q, \ TI _x); \ \ /* Write a block of samplex into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : buffer of input samples, [size: _n x 1] */ \ /* _n : number of input samples */ \ int FDELAY(_write)(FDELAY() _q, \ TI * _x, \ unsigned int _n); \ \ /* Execute vector dot product on the filter's internal buffer and */ \ /* coefficients */ \ /* _q : filter object */ \ /* _y : pointer to single output sample */ \ int FDELAY(_execute)(FDELAY() _q, \ TO * _y); \ \ /* Execute the filter on a block of input samples; in-place operation */ \ /* is permitted (_x and _y may point to the same place in memory) */ \ /* _q : filter object */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _y : pointer to output array, [size: _n x 1] */ \ int FDELAY(_execute_block)(FDELAY() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_FDELAY_DEFINE_API(LIQUID_FDELAY_MANGLE_RRRF, float, float, float) LIQUID_FDELAY_DEFINE_API(LIQUID_FDELAY_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) // // FIR Hilbert transform // 2:1 real-to-complex decimator // 1:2 complex-to-real interpolator // #define LIQUID_FIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(firhilbf, name) //#define LIQUID_FIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(firhilb, name) // NOTES: // Although firhilb is a placeholder for both decimation and // interpolation, separate objects should be used for each task. #define LIQUID_FIRHILB_DEFINE_API(FIRHILB,T,TC) \ \ /* Finite impulse response (FIR) Hilbert transform */ \ typedef struct FIRHILB(_s) * FIRHILB(); \ \ /* Create a firhilb object with a particular filter semi-length and */ \ /* desired stop-band attenuation. */ \ /* Internally the object designs a half-band filter based on applying */ \ /* a Kaiser-Bessel window to a sinc function to guarantee zeros at all */ \ /* off-center odd indexed samples. */ \ /* _m : filter semi-length, delay is \( 2 m + 1 \) */ \ /* _as : filter stop-band attenuation [dB] */ \ FIRHILB() FIRHILB(_create)(unsigned int _m, \ float _as); \ \ /* Copy object including all internal objects and state */ \ FIRHILB() FIRHILB(_copy)(FIRHILB() _q); \ \ /* Destroy finite impulse response Hilbert transform, freeing all */ \ /* internally-allocted memory and objects. */ \ int FIRHILB(_destroy)(FIRHILB() _q); \ \ /* Print firhilb object internals to stdout */ \ int FIRHILB(_print)(FIRHILB() _q); \ \ /* Reset firhilb object internal state */ \ int FIRHILB(_reset)(FIRHILB() _q); \ \ /* Execute Hilbert transform (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input sample */ \ /* _y : complex-valued output sample */ \ int FIRHILB(_r2c_execute)(FIRHILB() _q, \ T _x, \ TC * _y); \ \ /* Execute Hilbert transform (complex to real) */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y0 : real-valued output sample, lower side-band retained */ \ /* _y1 : real-valued output sample, upper side-band retained */ \ int FIRHILB(_c2r_execute)(FIRHILB() _q, \ TC _x, \ T * _y0, \ T * _y1); \ \ /* Execute Hilbert transform decimator (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input array, [size: 2 x 1] */ \ /* _y : complex-valued output sample */ \ int FIRHILB(_decim_execute)(FIRHILB() _q, \ T * _x, \ TC * _y); \ \ /* Execute Hilbert transform decimator (real to complex) on a block of */ \ /* samples */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input array, [size: 2*_n x 1] */ \ /* _n : number of output samples */ \ /* _y : complex-valued output array, [size: _n x 1] */ \ int FIRHILB(_decim_execute_block)(FIRHILB() _q, \ T * _x, \ unsigned int _n, \ TC * _y); \ \ /* Execute Hilbert transform interpolator (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y : real-valued output array, [size: 2 x 1] */ \ int FIRHILB(_interp_execute)(FIRHILB() _q, \ TC _x, \ T * _y); \ \ /* Execute Hilbert transform interpolator (complex to real) on a block */ \ /* of samples */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input array, [size: _n x 1] */ \ /* _n : number of *input* samples */ \ /* _y : real-valued output array, [size: 2*_n x 1] */ \ int FIRHILB(_interp_execute_block)(FIRHILB() _q, \ TC * _x, \ unsigned int _n, \ T * _y); \ LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_FLOAT, float, liquid_float_complex) //LIQUID_FIRHILB_DEFINE_API(LIQUID_FIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) // // Infinite impulse response (IIR) Hilbert transform // 2:1 real-to-complex decimator // 1:2 complex-to-real interpolator // #define LIQUID_IIRHILB_MANGLE_FLOAT(name) LIQUID_CONCAT(iirhilbf, name) //#define LIQUID_IIRHILB_MANGLE_DOUBLE(name) LIQUID_CONCAT(iirhilb, name) // NOTES: // Although iirhilb is a placeholder for both decimation and // interpolation, separate objects should be used for each task. #define LIQUID_IIRHILB_DEFINE_API(IIRHILB,T,TC) \ \ /* Infinite impulse response (IIR) Hilbert transform */ \ typedef struct IIRHILB(_s) * IIRHILB(); \ \ /* Create a iirhilb object with a particular filter type, order, and */ \ /* desired pass- and stop-band attenuation. */ \ /* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ /* _n : filter order, _n > 0 */ \ /* _ap : pass-band ripple [dB], _ap > 0 */ \ /* _as : stop-band ripple [dB], _as > 0 */ \ IIRHILB() IIRHILB(_create)(liquid_iirdes_filtertype _ftype, \ unsigned int _n, \ float _ap, \ float _as); \ \ /* Copy object including all internal objects and state */ \ IIRHILB() IIRHILB(_copy)(IIRHILB() _q); \ \ /* Create a default iirhilb object with a particular filter order. */ \ /* _n : filter order, _n > 0 */ \ IIRHILB() IIRHILB(_create_default)(unsigned int _n); \ \ /* Destroy finite impulse response Hilbert transform, freeing all */ \ /* internally-allocted memory and objects. */ \ int IIRHILB(_destroy)(IIRHILB() _q); \ \ /* Print iirhilb object internals to stdout */ \ int IIRHILB(_print)(IIRHILB() _q); \ \ /* Reset iirhilb object internal state */ \ int IIRHILB(_reset)(IIRHILB() _q); \ \ /* Execute Hilbert transform (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input sample */ \ /* _y : complex-valued output sample */ \ int IIRHILB(_r2c_execute)(IIRHILB() _q, \ T _x, \ TC * _y); \ \ /* Execute Hilbert transform (real to complex) on a block of samples */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input sample array, [size: _n x 1] */ \ /* _n : number of input,output samples */ \ /* _y : complex-valued output sample array, [size: _n x 1] */ \ int IIRHILB(_r2c_execute_block)(IIRHILB() _q, \ T * _x, \ unsigned int _n, \ TC * _y); \ \ /* Execute Hilbert transform (complex to real) */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y : real-valued output sample */ \ int IIRHILB(_c2r_execute)(IIRHILB() _q, \ TC _x, \ T * _y); \ \ /* Execute Hilbert transform (complex to real) on a block of samples */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample array, [size: _n x 1] */ \ /* _n : number of input,output samples */ \ /* _y : real-valued output sample array, [size: _n x 1] */ \ int IIRHILB(_c2r_execute_block)(IIRHILB() _q, \ TC * _x, \ unsigned int _n, \ T * _y); \ \ /* Execute Hilbert transform decimator (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input array, [size: 2 x 1] */ \ /* _y : complex-valued output sample */ \ int IIRHILB(_decim_execute)(IIRHILB() _q, \ T * _x, \ TC * _y); \ \ /* Execute Hilbert transform decimator (real to complex) on a block of */ \ /* samples */ \ /* _q : Hilbert transform object */ \ /* _x : real-valued input array, [size: 2*_n x 1] */ \ /* _n : number of output samples */ \ /* _y : complex-valued output array, [size: _n x 1] */ \ int IIRHILB(_decim_execute_block)(IIRHILB() _q, \ T * _x, \ unsigned int _n, \ TC * _y); \ \ /* Execute Hilbert transform interpolator (real to complex) */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input sample */ \ /* _y : real-valued output array, [size: 2 x 1] */ \ int IIRHILB(_interp_execute)(IIRHILB() _q, \ TC _x, \ T * _y); \ \ /* Execute Hilbert transform interpolator (complex to real) on a block */ \ /* of samples */ \ /* _q : Hilbert transform object */ \ /* _x : complex-valued input array, [size: _n x 1] */ \ /* _n : number of *input* samples */ \ /* _y : real-valued output array, [size: 2*_n x 1] */ \ int IIRHILB(_interp_execute_block)(IIRHILB() _q, \ TC * _x, \ unsigned int _n, \ T * _y); \ LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_FLOAT, float, liquid_float_complex) //LIQUID_IIRHILB_DEFINE_API(LIQUID_IIRHILB_MANGLE_DOUBLE, double, liquid_double_complex) // // FFT-based finite impulse response filter // #define LIQUID_FFTFILT_MANGLE_RRRF(name) LIQUID_CONCAT(fftfilt_rrrf,name) #define LIQUID_FFTFILT_MANGLE_CRCF(name) LIQUID_CONCAT(fftfilt_crcf,name) #define LIQUID_FFTFILT_MANGLE_CCCF(name) LIQUID_CONCAT(fftfilt_cccf,name) // Macro: // FFTFILT : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FFTFILT_DEFINE_API(FFTFILT,TO,TC,TI) \ \ /* Fast Fourier transform (FFT) finite impulse response filter */ \ typedef struct FFTFILT(_s) * FFTFILT(); \ \ /* Create FFT-based FIR filter using external coefficients */ \ /* _h : filter coefficients, [size: _h_len x 1] */ \ /* _h_len : filter length, _h_len > 0 */ \ /* _n : block size = nfft/2, _n >= _h_len-1 */ \ FFTFILT() FFTFILT(_create)(TC * _h, \ unsigned int _h_len, \ unsigned int _n); \ \ /* Copy object including all internal objects and state */ \ FFTFILT() FFTFILT(_copy)(FFTFILT() _q); \ \ /* Destroy filter object and free all internal memory */ \ int FFTFILT(_destroy)(FFTFILT() _q); \ \ /* Reset filter object's internal buffer */ \ int FFTFILT(_reset)(FFTFILT() _q); \ \ /* Print filter object information to stdout */ \ int FFTFILT(_print)(FFTFILT() _q); \ \ /* Set output scaling for filter */ \ int FFTFILT(_set_scale)(FFTFILT() _q, \ TC _scale); \ \ /* Get output scaling for filter */ \ int FFTFILT(_get_scale)(FFTFILT() _q, \ TC * _scale); \ \ /* Execute the filter on internal buffer and coefficients given a block */ \ /* of input samples; in-place operation is permitted (_x and _y may */ \ /* point to the same place in memory) */ \ /* _q : filter object */ \ /* _x : pointer to input data array, [size: _n x 1] */ \ /* _y : pointer to output data array, [size: _n x 1] */ \ int FFTFILT(_execute)(FFTFILT() _q, \ TI * _x, \ TO * _y); \ \ /* Get length of filter object's internal coefficients */ \ unsigned int FFTFILT(_get_length)(FFTFILT() _q); \ LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_RRRF, float, float, float) LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FFTFILT_DEFINE_API(LIQUID_FFTFILT_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Infinite impulse response filter // #define LIQUID_IIRFILT_MANGLE_RRRF(name) LIQUID_CONCAT(iirfilt_rrrf,name) #define LIQUID_IIRFILT_MANGLE_CRCF(name) LIQUID_CONCAT(iirfilt_crcf,name) #define LIQUID_IIRFILT_MANGLE_CCCF(name) LIQUID_CONCAT(iirfilt_cccf,name) // Macro: // IIRFILT : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_IIRFILT_DEFINE_API(IIRFILT,TO,TC,TI) \ \ /* Infinite impulse response (IIR) filter */ \ typedef struct IIRFILT(_s) * IIRFILT(); \ \ /* Create infinite impulse response filter from external coefficients. */ \ /* Note that the number of feed-forward and feed-back coefficients do */ \ /* not need to be equal, but they do need to be non-zero. */ \ /* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ /* equal to zero, otherwise the filter will be invalid as this value is */ \ /* factored out from all coefficients. */ \ /* For stability reasons the number of coefficients should reasonably */ \ /* not exceed about 8 for single-precision floating-point. */ \ /* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ /* _nb : number of feed-forward coefficients, _nb > 0 */ \ /* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ /* _na : number of feed-back coefficients, _na > 0 */ \ IIRFILT() IIRFILT(_create)(TC * _b, \ unsigned int _nb, \ TC * _a, \ unsigned int _na); \ \ /* Create IIR filter using 2nd-order sections from external */ \ /* coefficients. */ \ /* _b : feed-forward coefficients, [size: _nsos x 3] */ \ /* _a : feed-back coefficients, [size: _nsos x 3] */ \ /* _nsos : number of second-order sections (sos), _nsos > 0 */ \ IIRFILT() IIRFILT(_create_sos)(TC * _b, \ TC * _a, \ unsigned int _nsos); \ \ /* Create IIR filter from design template */ \ /* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ /* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ /* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ /* _order : filter order, _order > 0 */ \ /* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ /* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ /* _ap : pass-band ripple in dB, _ap > 0 */ \ /* _as : stop-band ripple in dB, _as > 0 */ \ IIRFILT() IIRFILT(_create_prototype)( \ liquid_iirdes_filtertype _ftype, \ liquid_iirdes_bandtype _btype, \ liquid_iirdes_format _format, \ unsigned int _order, \ float _fc, \ float _f0, \ float _ap, \ float _as); \ \ /* Create simplified low-pass Butterworth IIR filter */ \ /* _order : filter order, _order > 0 */ \ /* _fc : low-pass prototype cut-off frequency */ \ IIRFILT() IIRFILT(_create_lowpass)(unsigned int _order, \ float _fc); \ \ /* Create 8th-order integrator filter */ \ IIRFILT() IIRFILT(_create_integrator)(void); \ \ /* Create 8th-order differentiator filter */ \ IIRFILT() IIRFILT(_create_differentiator)(void); \ \ /* Create simple first-order DC-blocking filter with transfer function */ \ /* \( H(z) = \frac{1 - z^{-1}}{1 - (1-\alpha)z^{-1}} \) */ \ /* _alpha : normalized filter bandwidth, _alpha > 0 */ \ IIRFILT() IIRFILT(_create_dc_blocker)(float _alpha); \ \ /* Create filter to operate as second-order integrating phase-locked */ \ /* loop (active lag design) */ \ /* _w : filter bandwidth, 0 < _w < 1 */ \ /* _zeta : damping factor, \( 1/\sqrt{2} \) suggested, 0 < _zeta < 1 */ \ /* _K : loop gain, 1000 suggested, _K > 0 */ \ IIRFILT() IIRFILT(_create_pll)(float _w, \ float _zeta, \ float _K); \ \ /* Copy object including all internal objects and state */ \ IIRFILT() IIRFILT(_copy)(IIRFILT() _q); \ \ /* Destroy iirfilt object, freeing all internal memory */ \ int IIRFILT(_destroy)(IIRFILT() _q); \ \ /* Print iirfilt object properties to stdout */ \ int IIRFILT(_print)(IIRFILT() _q); \ \ /* Reset iirfilt object internals */ \ int IIRFILT(_reset)(IIRFILT() _q); \ \ /* Set output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor to apply to each output sample */ \ int IIRFILT(_set_scale)(IIRFILT() _q, TC _scale); \ \ /* Get output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor applied to each output sample */ \ int IIRFILT(_get_scale)(IIRFILT() _q, TC * _scale); \ \ /* Compute filter output given a single input sample */ \ /* _q : iirfilt object */ \ /* _x : input sample */ \ /* _y : output sample pointer */ \ int IIRFILT(_execute)(IIRFILT() _q, \ TI _x, \ TO * _y); \ \ /* Execute the filter on a block of input samples; */ \ /* in-place operation is permitted (the input and output buffers may be */ \ /* the same) */ \ /* _q : filter object */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _n : number of input, output samples, _n > 0 */ \ /* _y : pointer to output array, [size: _n x 1] */ \ int IIRFILT(_execute_block)(IIRFILT() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Return number of coefficients for iirfilt object (maximum between */ \ /* the feed-forward and feed-back coefficients). Note that the filter */ \ /* length = filter order + 1 */ \ unsigned int IIRFILT(_get_length)(IIRFILT() _q); \ \ /* Compute complex frequency response of filter object */ \ /* _q : filter object */ \ /* _fc : normalized frequency for evaluation */ \ /* _H : pointer to output complex frequency response */ \ int IIRFILT(_freqresponse)(IIRFILT() _q, \ float _fc, \ liquid_float_complex * _H); \ \ /* Compute power spectral density response of filter object in dB */ \ /* _q : filter object */ \ /* _fc : normalized frequency for evaluation */ \ float IIRFILT(_get_psd)(IIRFILT() _q, \ float _fc); \ \ /* Compute and return group delay of filter object */ \ /* _q : filter object */ \ /* _fc : frequency to evaluate */ \ float IIRFILT(_groupdelay)(IIRFILT() _q, float _fc); \ LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_RRRF, float, float, float) LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_IIRFILT_DEFINE_API(LIQUID_IIRFILT_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // iirfiltsos : infinite impulse response filter (second-order sections) // #define LIQUID_IIRFILTSOS_MANGLE_RRRF(name) LIQUID_CONCAT(iirfiltsos_rrrf,name) #define LIQUID_IIRFILTSOS_MANGLE_CRCF(name) LIQUID_CONCAT(iirfiltsos_crcf,name) #define LIQUID_IIRFILTSOS_MANGLE_CCCF(name) LIQUID_CONCAT(iirfiltsos_cccf,name) #define LIQUID_IIRFILTSOS_DEFINE_API(IIRFILTSOS,TO,TC,TI) \ \ /* Infinite impulse response filter primitive using second-order */ \ /* sections */ \ typedef struct IIRFILTSOS(_s) * IIRFILTSOS(); \ \ /* create 2nd-order infinite impulse response filter */ \ /* _b : feed-forward coefficients, [size: _3 x 1] */ \ /* _a : feed-back coefficients, [size: _3 x 1] */ \ IIRFILTSOS() IIRFILTSOS(_create)(TC * _b, \ TC * _a); \ \ /* Copy object including all internal objects and state */ \ IIRFILTSOS() IIRFILTSOS(_copy)(IIRFILTSOS() _q); \ \ /* explicitly set 2nd-order IIR filter coefficients */ \ /* _q : iirfiltsos object */ \ /* _b : feed-forward coefficients, [size: 3 x 1] */ \ /* _a : feed-back coefficients, [size: 3 x 1] */ \ int IIRFILTSOS(_set_coefficients)(IIRFILTSOS() _q, \ TC * _b, \ TC * _a); \ \ /* destroy iirfiltsos object, freeing all internal memory */ \ int IIRFILTSOS(_destroy)(IIRFILTSOS() _q); \ \ /* print iirfiltsos object properties to stdout */ \ int IIRFILTSOS(_print)(IIRFILTSOS() _q); \ \ /* clear/reset iirfiltsos object internals */ \ int IIRFILTSOS(_reset)(IIRFILTSOS() _q); \ \ /* compute filter output */ \ /* _q : iirfiltsos object */ \ /* _x : input sample */ \ /* _y : output sample pointer */ \ int IIRFILTSOS(_execute)(IIRFILTSOS() _q, \ TI _x, \ TO * _y); \ \ /* compute filter output, direct-form I method */ \ /* _q : iirfiltsos object */ \ /* _x : input sample */ \ /* _y : output sample pointer */ \ int IIRFILTSOS(_execute_df1)(IIRFILTSOS() _q, \ TI _x, \ TO * _y); \ \ /* compute filter output, direct-form II method */ \ /* _q : iirfiltsos object */ \ /* _x : input sample */ \ /* _y : output sample pointer */ \ int IIRFILTSOS(_execute_df2)(IIRFILTSOS() _q, \ TI _x, \ TO * _y); \ \ /* compute and return group delay of filter object */ \ /* _q : filter object */ \ /* _fc : frequency to evaluate */ \ float IIRFILTSOS(_groupdelay)(IIRFILTSOS() _q, \ float _fc); \ LIQUID_IIRFILTSOS_DEFINE_API(LIQUID_IIRFILTSOS_MANGLE_RRRF, float, float, float) LIQUID_IIRFILTSOS_DEFINE_API(LIQUID_IIRFILTSOS_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_IIRFILTSOS_DEFINE_API(LIQUID_IIRFILTSOS_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // FIR Polyphase filter bank // #define LIQUID_FIRPFB_MANGLE_RRRF(name) LIQUID_CONCAT(firpfb_rrrf,name) #define LIQUID_FIRPFB_MANGLE_CRCF(name) LIQUID_CONCAT(firpfb_crcf,name) #define LIQUID_FIRPFB_MANGLE_CCCF(name) LIQUID_CONCAT(firpfb_cccf,name) // Macro: // FIRPFB : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FIRPFB_DEFINE_API(FIRPFB,TO,TC,TI) \ \ /* Finite impulse response (FIR) polyphase filter bank (PFB) */ \ typedef struct FIRPFB(_s) * FIRPFB(); \ \ /* Create firpfb object with _num_filters sub-filters each having */ \ /* exactly _h_len/_num_filters coefficients */ \ /* from an external array of coefficients */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _h : coefficients, [size: _h_len x 1] */ \ /* _h_len : complete filter length (where _h_len is a */ \ /* multiple of _num_filters), _h_len >= _num_filters */ \ FIRPFB() FIRPFB(_create)(unsigned int _num_filters, \ TC * _h, \ unsigned int _h_len); \ \ /* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ /* method, using default values for cut-off frequency and stop-band */ \ /* attenuation. This is equivalent to: */ \ /* FIRPFB(_create_kaiser)(_M, _m, 0.5, 60.0) */ \ /* which creates a Nyquist filter at the appropriate cut-off frequency. */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _m : filter semi-length [samples], _m > 0 */ \ FIRPFB() FIRPFB(_create_default)(unsigned int _num_filters, \ unsigned int _m); \ \ /* Create firpfb object using Kaiser-Bessel windowed sinc filter design */ \ /* method */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _m : filter semi-length [samples], _m > 0 */ \ /* _fc : filter normalized cut-off frequency, 0 < _fc < 0.5 */ \ /* _as : filter stop-band suppression [dB], _as > 0 */ \ FIRPFB() FIRPFB(_create_kaiser)(unsigned int _num_filters, \ unsigned int _m, \ float _fc, \ float _as); \ \ /* Create firpfb from square-root Nyquist prototype */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _k : nominal samples/symbol, _k > 1 */ \ /* _m : filter delay [symbols], _m > 0 */ \ /* _beta : rolloff factor, 0 < _beta <= 1 */ \ FIRPFB() FIRPFB(_create_rnyquist)(int _type, \ unsigned int _num_filters, \ unsigned int _k, \ unsigned int _m, \ float _beta); \ \ /* Create from square-root derivative Nyquist prototype */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _k : nominal samples/symbol, _k > 1 */ \ /* _m : filter delay [symbols], _m > 0 */ \ /* _beta : rolloff factor, 0 < _beta <= 1 */ \ FIRPFB() FIRPFB(_create_drnyquist)(int _type, \ unsigned int _num_filters, \ unsigned int _k, \ unsigned int _m, \ float _beta); \ \ /* Re-create firpfb object of potentially a different length with */ \ /* different coefficients. If the length of the filter does not change, */ \ /* not memory reallocation is invoked. */ \ /* _q : original firpfb object */ \ /* _num_filters : number of filters in the bank, _num_filters > 1 */ \ /* _h : coefficients, [size: _h_len x 1] */ \ /* _h_len : complete filter length (where _h_len is a */ \ /* multiple of _num_filters), _h_len >= _num_filters */ \ FIRPFB() FIRPFB(_recreate)(FIRPFB() _q, \ unsigned int _num_filters, \ TC * _h, \ unsigned int _h_len); \ \ /* Copy object including all internal objects and state */ \ FIRPFB() FIRPFB(_copy)(FIRPFB() _q); \ \ /* Destroy firpfb object, freeing all internal memory and destroying */ \ /* all internal objects */ \ int FIRPFB(_destroy)(FIRPFB() _q); \ \ /* Print firpfb object's parameters to stdout */ \ int FIRPFB(_print)(FIRPFB() _q); \ \ /* Set output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRPFB(_set_scale)(FIRPFB() _q, \ TC _scale); \ \ /* Get output scaling for filter */ \ /* _q : filter object */ \ /* _scale : scaling factor applied to each output sample */ \ int FIRPFB(_get_scale)(FIRPFB() _q, \ TC * _scale); \ \ /* Reset firpfb object's internal buffer */ \ int FIRPFB(_reset)(FIRPFB() _q); \ \ /* Push sample into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : single input sample */ \ int FIRPFB(_push)(FIRPFB() _q, \ TI _x); \ \ /* Write a block of samples into object's internal buffer */ \ /* _q : filter object */ \ /* _x : single input sample */ \ int FIRPFB(_write)(FIRPFB() _q, \ TI * _x, \ unsigned int _n); \ \ /* Execute vector dot product on the filter's internal buffer and */ \ /* coefficients using the coefficients from sub-filter at index _i */ \ /* _q : firpfb object */ \ /* _i : index of filter to use */ \ /* _y : pointer to output sample */ \ int FIRPFB(_execute)(FIRPFB() _q, \ unsigned int _i, \ TO * _y); \ \ /* Execute the filter on a block of input samples, all using index _i. */ \ /* In-place operation is permitted (_x and _y may point to the same */ \ /* place in memory) */ \ /* _q : firpfb object */ \ /* _i : index of filter to use */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _y : pointer to output array, [size: _n x 1] */ \ int FIRPFB(_execute_block)(FIRPFB() _q, \ unsigned int _i, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_RRRF, float, float, float) LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FIRPFB_DEFINE_API(LIQUID_FIRPFB_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Interpolators // // firinterp : finite impulse response interpolator #define LIQUID_FIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(firinterp_rrrf,name) #define LIQUID_FIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(firinterp_crcf,name) #define LIQUID_FIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(firinterp_cccf,name) #define LIQUID_FIRINTERP_DEFINE_API(FIRINTERP,TO,TC,TI) \ \ /* Finite impulse response (FIR) interpolator */ \ typedef struct FIRINTERP(_s) * FIRINTERP(); \ \ /* Create interpolator from external coefficients. Internally the */ \ /* interpolator creates a polyphase filter bank to efficiently realize */ \ /* resampling of the input signal. */ \ /* If the input filter length is not a multiple of the interpolation */ \ /* factor \(M\), the object internally pads the coefficients with zeros */ \ /* to compensate. */ \ /* _interp : interpolation factor \(M\), _interp >= 2 */ \ /* _h : filter coefficients, [size: _h_len x 1] */ \ /* _h_len : filter length, _h_len >= _interp */ \ FIRINTERP() FIRINTERP(_create)(unsigned int _interp, \ TC * _h, \ unsigned int _h_len); \ \ /* Create interpolator from filter prototype prototype (Kaiser-Bessel */ \ /* windowed-sinc function) */ \ /* _interp : interpolation factor \(M\), _interp >= 2 */ \ /* _m : filter delay [symbols], _m >= 1 */ \ /* _as : stop-band attenuation [dB], _as >= 0 */ \ FIRINTERP() FIRINTERP(_create_kaiser)(unsigned int _interp, \ unsigned int _m, \ float _as); \ \ /* Create interpolator object from filter prototype */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ /* _interp : interpolation factor \(M\), _interp >= 2 */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ /* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ FIRINTERP() FIRINTERP(_create_prototype)(int _type, \ unsigned int _interp, \ unsigned int _m, \ float _beta, \ float _dt); \ \ /* Create linear interpolator object */ \ /* _interp : interpolation factor \(M\), _interp >= 2 */ \ FIRINTERP() FIRINTERP(_create_linear)(unsigned int _interp); \ \ /* Create window interpolator object */ \ /* _interp : interpolation factor \(M\), _interp >= 2 */ \ /* _m : filter semi-length, _m > 0 */ \ FIRINTERP() FIRINTERP(_create_window)(unsigned int _interp, \ unsigned int _m); \ \ /* Copy object including all internal objects and state */ \ FIRINTERP() FIRINTERP(_copy)(FIRINTERP() _q); \ \ /* Destroy firinterp object, freeing all internal memory */ \ int FIRINTERP(_destroy)(FIRINTERP() _q); \ \ /* Print firinterp object's internal properties to stdout */ \ int FIRINTERP(_print)(FIRINTERP() _q); \ \ /* Reset internal state */ \ int FIRINTERP(_reset)(FIRINTERP() _q); \ \ /* Get interpolation rate */ \ unsigned int FIRINTERP(_get_interp_rate)(FIRINTERP() _q); \ \ /* Get sub-filter length (length of each poly-phase filter) */ \ unsigned int FIRINTERP(_get_sub_len)(FIRINTERP() _q); \ \ /* Set output scaling for interpolator */ \ /* _q : interpolator object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRINTERP(_set_scale)(FIRINTERP() _q, \ TC _scale); \ \ /* Get output scaling for interpolator */ \ /* _q : interpolator object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRINTERP(_get_scale)(FIRINTERP() _q, \ TC * _scale); \ \ /* Execute interpolation on single input sample and write \(M\) output */ \ /* samples (\(M\) is the interpolation factor) */ \ /* _q : firinterp object */ \ /* _x : input sample */ \ /* _y : output sample array, [size: M x 1] */ \ int FIRINTERP(_execute)(FIRINTERP() _q, \ TI _x, \ TO * _y); \ \ /* Execute interpolation on block of input samples, increasing the */ \ /* sample rate of the input by the interpolation factor \(M\). */ \ /* _q : firinterp object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : size of input array */ \ /* _y : output sample array, [size: M*_n x 1] */ \ int FIRINTERP(_execute_block)(FIRINTERP() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Execute interpolation with zero-valued input (e.g. flush internal */ \ /* state) */ \ /* _q : firinterp object */ \ /* _y : output sample array, [size: M x 1] */ \ int FIRINTERP(_flush)(FIRINTERP() _q, \ TO * _y); \ LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_RRRF, float, float, float) LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FIRINTERP_DEFINE_API(LIQUID_FIRINTERP_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // iirinterp : infinite impulse response interpolator #define LIQUID_IIRINTERP_MANGLE_RRRF(name) LIQUID_CONCAT(iirinterp_rrrf,name) #define LIQUID_IIRINTERP_MANGLE_CRCF(name) LIQUID_CONCAT(iirinterp_crcf,name) #define LIQUID_IIRINTERP_MANGLE_CCCF(name) LIQUID_CONCAT(iirinterp_cccf,name) #define LIQUID_IIRINTERP_DEFINE_API(IIRINTERP,TO,TC,TI) \ \ /* Infinite impulse response (IIR) interpolator */ \ typedef struct IIRINTERP(_s) * IIRINTERP(); \ \ /* Create infinite impulse response interpolator from external */ \ /* coefficients. */ \ /* Note that the number of feed-forward and feed-back coefficients do */ \ /* not need to be equal, but they do need to be non-zero. */ \ /* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ /* equal to zero, otherwise the filter will be invalid as this value is */ \ /* factored out from all coefficients. */ \ /* For stability reasons the number of coefficients should reasonably */ \ /* not exceed about 8 for single-precision floating-point. */ \ /* _M : interpolation factor, _M >= 2 */ \ /* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ /* _nb : number of feed-forward coefficients, _nb > 0 */ \ /* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ /* _na : number of feed-back coefficients, _na > 0 */ \ IIRINTERP() IIRINTERP(_create)(unsigned int _M, \ TC * _b, \ unsigned int _nb, \ TC * _a, \ unsigned int _na); \ \ /* Create interpolator object with default Butterworth prototype */ \ /* _M : interpolation factor, _M >= 2 */ \ /* _order : filter order, _order > 0 */ \ IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, \ unsigned int _order); \ \ /* Create IIR interpolator from prototype */ \ /* _M : interpolation factor, _M >= 2 */ \ /* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ /* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ /* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ /* _order : filter order, _order > 0 */ \ /* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ /* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ /* _ap : pass-band ripple in dB, _ap > 0 */ \ /* _as : stop-band ripple in dB, _as > 0 */ \ IIRINTERP() IIRINTERP(_create_prototype)( \ unsigned int _M, \ liquid_iirdes_filtertype _ftype, \ liquid_iirdes_bandtype _btype, \ liquid_iirdes_format _format, \ unsigned int _order, \ float _fc, \ float _f0, \ float _ap, \ float _as); \ \ /* Copy object including all internal objects and state */ \ IIRINTERP() IIRINTERP(_copy)(IIRINTERP() _q); \ \ /* Destroy interpolator object and free internal memory */ \ int IIRINTERP(_destroy)(IIRINTERP() _q); \ \ /* Print interpolator object internals to stdout */ \ int IIRINTERP(_print)(IIRINTERP() _q); \ \ /* Reset interpolator object */ \ int IIRINTERP(_reset)(IIRINTERP() _q); \ \ /* Execute interpolation on single input sample and write \(M\) output */ \ /* samples (\(M\) is the interpolation factor) */ \ /* _q : iirinterp object */ \ /* _x : input sample */ \ /* _y : output sample array, [size: _M x 1] */ \ int IIRINTERP(_execute)(IIRINTERP() _q, \ TI _x, \ TO * _y); \ \ /* Execute interpolation on block of input samples */ \ /* _q : iirinterp object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : size of input array */ \ /* _y : output sample array, [size: _M*_n x 1] */ \ int IIRINTERP(_execute_block)(IIRINTERP() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Compute and return group delay of object */ \ /* _q : filter object */ \ /* _fc : frequency to evaluate */ \ float IIRINTERP(_groupdelay)(IIRINTERP() _q, \ float _fc); \ LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_RRRF, float, float, float) LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_IIRINTERP_DEFINE_API(LIQUID_IIRINTERP_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Decimators // // firdecim : finite impulse response decimator #define LIQUID_FIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(firdecim_rrrf,name) #define LIQUID_FIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(firdecim_crcf,name) #define LIQUID_FIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(firdecim_cccf,name) #define LIQUID_FIRDECIM_DEFINE_API(FIRDECIM,TO,TC,TI) \ \ /* Finite impulse response (FIR) decimator */ \ typedef struct FIRDECIM(_s) * FIRDECIM(); \ \ /* Create decimator from external coefficients */ \ /* _M : decimation factor, _M >= 2 */ \ /* _h : filter coefficients, [size: _h_len x 1] */ \ /* _h_len : filter length, _h_len >= _M */ \ FIRDECIM() FIRDECIM(_create)(unsigned int _M, \ TC * _h, \ unsigned int _h_len); \ \ /* Create decimator from filter prototype prototype (Kaiser-Bessel */ \ /* windowed-sinc function) */ \ /* _M : decimation factor, _M >= 2 */ \ /* _m : filter delay [symbols], _m >= 1 */ \ /* _as : stop-band attenuation [dB], _as >= 0 */ \ FIRDECIM() FIRDECIM(_create_kaiser)(unsigned int _M, \ unsigned int _m, \ float _as); \ \ /* Create decimator object from filter prototype */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ /* _M : interpolation factor, _M > 1 */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ /* _dt : fractional sample delay, -1 <= _dt <= 1 */ \ FIRDECIM() FIRDECIM(_create_prototype)(int _type, \ unsigned int _M, \ unsigned int _m, \ float _beta, \ float _dt); \ \ /* Copy object including all internal objects and state */ \ FIRDECIM() FIRDECIM(_copy)(FIRDECIM() _q); \ \ /* Destroy decimator object, freeing all internal memory */ \ int FIRDECIM(_destroy)(FIRDECIM() _q); \ \ /* Print decimator object properties to stdout */ \ int FIRDECIM(_print)(FIRDECIM() _q); \ \ /* Reset decimator object internal state */ \ int FIRDECIM(_reset)(FIRDECIM() _q); \ \ /* Get decimation rate */ \ unsigned int FIRDECIM(_get_decim_rate)(FIRDECIM() _q); \ \ /* Set output scaling for decimator */ \ /* _q : decimator object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRDECIM(_set_scale)(FIRDECIM() _q, \ TC _scale); \ \ /* Get output scaling for decimator */ \ /* _q : decimator object */ \ /* _scale : scaling factor to apply to each output sample */ \ int FIRDECIM(_get_scale)(FIRDECIM() _q, \ TC * _scale); \ \ /* Compute complex frequency response \(H\) of decimator on prototype */ \ /* filter coefficients at a specific frequency \(f_c\) */ \ /* _q : decimator object */ \ /* _fc : normalized frequency for evaluation */ \ /* _H : pointer to output complex frequency response */ \ int FIRDECIM(_freqresp)(FIRDECIM() _q, \ float _fc, \ liquid_float_complex * _H); \ \ /* Execute decimator on _M input samples */ \ /* _q : decimator object */ \ /* _x : input samples, [size: _M x 1] */ \ /* _y : output sample pointer */ \ int FIRDECIM(_execute)(FIRDECIM() _q, \ TI * _x, \ TO * _y); \ \ /* Execute decimator on block of _n*_M input samples */ \ /* _q : decimator object */ \ /* _x : input array, [size: _n*_M x 1] */ \ /* _n : number of _output_ samples */ \ /* _y : output array, [_size: _n x 1] */ \ int FIRDECIM(_execute_block)(FIRDECIM() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_RRRF, float, float, float) LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FIRDECIM_DEFINE_API(LIQUID_FIRDECIM_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // iirdecim : infinite impulse response decimator #define LIQUID_IIRDECIM_MANGLE_RRRF(name) LIQUID_CONCAT(iirdecim_rrrf,name) #define LIQUID_IIRDECIM_MANGLE_CRCF(name) LIQUID_CONCAT(iirdecim_crcf,name) #define LIQUID_IIRDECIM_MANGLE_CCCF(name) LIQUID_CONCAT(iirdecim_cccf,name) #define LIQUID_IIRDECIM_DEFINE_API(IIRDECIM,TO,TC,TI) \ \ /* Infinite impulse response (IIR) decimator */ \ typedef struct IIRDECIM(_s) * IIRDECIM(); \ \ /* Create infinite impulse response decimator from external */ \ /* coefficients. */ \ /* Note that the number of feed-forward and feed-back coefficients do */ \ /* not need to be equal, but they do need to be non-zero. */ \ /* Furthermore, the first feed-back coefficient \(a_0\) cannot be */ \ /* equal to zero, otherwise the filter will be invalid as this value is */ \ /* factored out from all coefficients. */ \ /* For stability reasons the number of coefficients should reasonably */ \ /* not exceed about 8 for single-precision floating-point. */ \ /* _M : decimation factor, _M >= 2 */ \ /* _b : feed-forward coefficients (numerator), [size: _nb x 1] */ \ /* _nb : number of feed-forward coefficients, _nb > 0 */ \ /* _a : feed-back coefficients (denominator), [size: _na x 1] */ \ /* _na : number of feed-back coefficients, _na > 0 */ \ IIRDECIM() IIRDECIM(_create)(unsigned int _M, \ TC * _b, \ unsigned int _nb, \ TC * _a, \ unsigned int _na); \ \ /* Create decimator object with default Butterworth prototype */ \ /* _M : decimation factor, _M >= 2 */ \ /* _order : filter order, _order > 0 */ \ IIRDECIM() IIRDECIM(_create_default)(unsigned int _M, \ unsigned int _order); \ \ /* Create IIR decimator from prototype */ \ /* _M : decimation factor, _M >= 2 */ \ /* _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) */ \ /* _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) */ \ /* _format : coefficients format (e.g. LIQUID_IIRDES_SOS) */ \ /* _order : filter order, _order > 0 */ \ /* _fc : low-pass prototype cut-off frequency, 0 <= _fc <= 0.5 */ \ /* _f0 : center frequency (band-pass, band-stop), 0 <= _f0 <= 0.5 */ \ /* _ap : pass-band ripple in dB, _ap > 0 */ \ /* _as : stop-band ripple in dB, _as > 0 */ \ IIRDECIM() IIRDECIM(_create_prototype)( \ unsigned int _M, \ liquid_iirdes_filtertype _ftype, \ liquid_iirdes_bandtype _btype, \ liquid_iirdes_format _format, \ unsigned int _order, \ float _fc, \ float _f0, \ float _ap, \ float _as); \ \ /* Copy object including all internal objects and state */ \ IIRDECIM() IIRDECIM(_copy)(IIRDECIM() _q); \ \ /* Destroy decimator object and free internal memory */ \ int IIRDECIM(_destroy)(IIRDECIM() _q); \ \ /* Print decimator object internals */ \ int IIRDECIM(_print)(IIRDECIM() _q); \ \ /* Reset decimator object */ \ int IIRDECIM(_reset)(IIRDECIM() _q); \ \ /* Execute decimator on _M input samples */ \ /* _q : decimator object */ \ /* _x : input samples, [size: _M x 1] */ \ /* _y : output sample pointer */ \ int IIRDECIM(_execute)(IIRDECIM() _q, \ TI * _x, \ TO * _y); \ \ /* Execute decimator on block of _n*_M input samples */ \ /* _q : decimator object */ \ /* _x : input array, [size: _n*_M x 1] */ \ /* _n : number of _output_ samples */ \ /* _y : output array, [_sze: _n x 1] */ \ int IIRDECIM(_execute_block)(IIRDECIM() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Compute and return group delay of object */ \ /* _q : filter object */ \ /* _fc : frequency to evaluate */ \ float IIRDECIM(_groupdelay)(IIRDECIM() _q, \ float _fc); \ LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_RRRF, float, float, float) LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_IIRDECIM_DEFINE_API(LIQUID_IIRDECIM_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Half-band resampler // #define LIQUID_RESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(resamp2_rrrf,name) #define LIQUID_RESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(resamp2_crcf,name) #define LIQUID_RESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(resamp2_cccf,name) #define LIQUID_RESAMP2_DEFINE_API(RESAMP2,TO,TC,TI) \ \ /* Half-band resampler, implemented as a dyadic (half-band) polyphase */ \ /* filter bank for interpolation, decimation, synthesis, and analysis. */ \ typedef struct RESAMP2(_s) * RESAMP2(); \ \ /* Create half-band resampler from design prototype. */ \ /* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ /* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ /* _as : stop-band attenuation [dB], _as > 0 */ \ RESAMP2() RESAMP2(_create)(unsigned int _m, \ float _f0, \ float _as); \ \ /* Re-create half-band resampler with new properties */ \ /* _q : original half-band resampler object */ \ /* _m : filter semi-length (h_len = 4*m+1), _m >= 2 */ \ /* _f0 : filter center frequency, -0.5 <= _f0 <= 0.5 */ \ /* _as : stop-band attenuation [dB], _as > 0 */ \ RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, \ unsigned int _m, \ float _f0, \ float _as); \ \ /* Copy object including all internal objects and state */ \ RESAMP2() RESAMP2(_copy)(RESAMP2() _q); \ \ /* Destroy resampler, freeing all internally-allocated memory */ \ int RESAMP2(_destroy)(RESAMP2() _q); \ \ /* print resampler object's internals to stdout */ \ int RESAMP2(_print)(RESAMP2() _q); \ \ /* Reset internal buffer */ \ int RESAMP2(_reset)(RESAMP2() _q); \ \ /* Get resampler filter delay (semi-length m) */ \ unsigned int RESAMP2(_get_delay)(RESAMP2() _q); \ \ /* Get output scaling for resampler */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ int RESAMP2(_set_scale)(RESAMP2() _q, \ TC _scale); \ \ /* Get output scaling for resampler */ \ /* _q : resampler object */ \ /* _scale : scaling factor applied to each output sample */ \ int RESAMP2(_get_scale)(RESAMP2() _q, \ TC * _scale); \ \ /* Execute resampler as half-band filter for a single input sample */ \ /* \(x\) where \(y_0\) is the output of the effective low-pass filter, */ \ /* and \(y_1\) is the output of the effective high-pass filter. */ \ /* _q : resampler object */ \ /* _x : input sample */ \ /* _y0 : output sample pointer (low frequency) */ \ /* _y1 : output sample pointer (high frequency) */ \ int RESAMP2(_filter_execute)(RESAMP2() _q, \ TI _x, \ TO * _y0, \ TO * _y1); \ \ /* Execute resampler as half-band analysis filterbank on a pair of */ \ /* sequential time-domain input samples. */ \ /* The decimated outputs of the low- and high-pass equivalent filters */ \ /* are stored in \(y_0\) and \(y_1\), respectively. */ \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output array, [size: 2 x 1] */ \ int RESAMP2(_analyzer_execute)(RESAMP2() _q, \ TI * _x, \ TO * _y); \ \ /* Execute resampler as half-band synthesis filterbank on a pair of */ \ /* input samples. The low- and high-pass input samples are provided by */ \ /* \(x_0\) and \(x_1\), respectively. The sequential time-domain output */ \ /* samples are stored in \(y_0\) and \(y_1\). */ \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output array, [size: 2 x 1] */ \ int RESAMP2(_synthesizer_execute)(RESAMP2() _q, \ TI * _x, \ TO * _y); \ \ /* Execute resampler as half-band decimator on a pair of sequential */ \ /* time-domain input samples. */ \ /* _q : resampler object */ \ /* _x : input array, [size: 2 x 1] */ \ /* _y : output sample pointer */ \ int RESAMP2(_decim_execute)(RESAMP2() _q, \ TI * _x, \ TO * _y); \ \ /* Execute resampler as half-band interpolator on a single input sample */ \ /* _q : resampler object */ \ /* _x : input sample */ \ /* _y : output array, [size: 2 x 1] */ \ int RESAMP2(_interp_execute)(RESAMP2() _q, \ TI _x, \ TO * _y); \ LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_RRRF, float, float, float) LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_RESAMP2_DEFINE_API(LIQUID_RESAMP2_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Rational resampler // #define LIQUID_RRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(rresamp_rrrf,name) #define LIQUID_RRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(rresamp_crcf,name) #define LIQUID_RRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(rresamp_cccf,name) #define LIQUID_RRESAMP_DEFINE_API(RRESAMP,TO,TC,TI) \ \ /* Rational rate resampler, implemented as a polyphase filterbank */ \ typedef struct RRESAMP(_s) * RRESAMP(); \ \ /* Create rational-rate resampler object from external coefficients to */ \ /* resample at an exact rate \(P/Q\) = interp/decim. */ \ /* Note that to preserve the input filter coefficients, the greatest */ \ /* common divisor (gcd) is not removed internally from interp and decim */ \ /* when this method is called. */ \ /* _interp : interpolation factor, _interp > 0 */ \ /* _decim : decimation factor, _decim > 0 */ \ /* _m : filter semi-length (delay), 0 < _m */ \ /* _h : filter coefficients, [size: 2*_interp*_m x 1] */ \ RRESAMP() RRESAMP(_create)(unsigned int _interp, \ unsigned int _decim, \ unsigned int _m, \ TC * _h); \ \ /* Create rational-rate resampler object from filter prototype to */ \ /* resample at an exact rate \(P/Q\) = interp/decim. */ \ /* Note that because the filter coefficients are computed internally */ \ /* here, the greatest common divisor (gcd) from _interp and _decim is */ \ /* internally removed to improve speed. */ \ /* _interp : interpolation factor, _interp > 0 */ \ /* _decim : decimation factor, _decim > 0 */ \ /* _m : filter semi-length (delay), 0 < _m */ \ /* _bw : filter bandwidth relative to sample rate. When the */ \ /* the resampler is configured as an interpolator a value of */ \ /* 0.5 (critically filtered) or less is recommended. */ \ /* When the resampler is configured as a decimator, the */ \ /* critical bandwidth is 0.5*_interp/_decim. */ \ /* When _bw < 0, the object will use the appropriate */ \ /* critical bandwidth (interpolation or decimation), */ \ /* 0 < _bw <= 0.5 */ \ /* _as : filter stop-band attenuation [dB], 0 < _as */ \ RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, \ unsigned int _decim, \ unsigned int _m, \ float _bw, \ float _as); \ \ /* Create rational-rate resampler object from filter prototype to */ \ /* resample at an exact rate \(P/Q\) = interp/decim. */ \ /* Note that because the filter coefficients are computed internally */ \ /* here, the greatest common divisor (gcd) from _interp and _decim is */ \ /* internally removed to improve speed. */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RCOS) */ \ /* _interp : interpolation factor, _interp > 0 */ \ /* _decim : decimation factor, _decim > 0 */ \ /* _m : filter semi-length (delay), 0 < _m */ \ /* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ RRESAMP() RRESAMP(_create_prototype)(int _type, \ unsigned int _interp, \ unsigned int _decim, \ unsigned int _m, \ float _beta); \ \ /* Create rational resampler object with a specified resampling rate of */ \ /* exactly interp/decim with default parameters. This is a simplified */ \ /* method to provide a basic resampler with a baseline set of */ \ /* parameters abstracting away some of the complexities with the */ \ /* filterbank design. */ \ /* The default parameters are */ \ /* m = 12 (filter semi-length), */ \ /* bw = 0.5 (filter bandwidth), and */ \ /* as = 60 dB (filter stop-band attenuation) */ \ /* _interp : interpolation factor, _interp > 0 */ \ /* _decim : decimation factor, _decim > 0 */ \ RRESAMP() RRESAMP(_create_default)(unsigned int _interp, \ unsigned int _decim); \ \ /* Copy object including all internal objects and state */ \ RRESAMP() RRESAMP(_copy)(RRESAMP() _q); \ \ /* Destroy resampler object, freeing all internal memory */ \ int RRESAMP(_destroy)(RRESAMP() _q); \ \ /* Print resampler object internals to stdout */ \ int RRESAMP(_print)(RRESAMP() _q); \ \ /* Reset resampler object internals */ \ int RRESAMP(_reset)(RRESAMP() _q); \ \ /* Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ int RRESAMP(_set_scale)(RRESAMP() _q, \ TC _scale); \ \ /* Get output scaling for filter */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ int RRESAMP(_get_scale)(RRESAMP() _q, \ TC * _scale); \ \ /* Get resampler delay (filter semi-length \(m\)) */ \ unsigned int RRESAMP(_get_delay)(RRESAMP() _q); \ \ /* Get original interpolation factor when object was created, before */ \ /* removing greatest common divisor */ \ unsigned int RRESAMP(_get_P)(RRESAMP() _q); \ \ /* Get internal interpolation factor of resampler, \(P\), after */ \ /* removing greatest common divisor */ \ unsigned int RRESAMP(_get_interp)(RRESAMP() _q); \ \ /* Get original decimation factor \(Q\) when object was created */ \ /* before removing greatest common divisor */ \ unsigned int RRESAMP(_get_Q)(RRESAMP() _q); \ \ /* Get internal decimation factor of resampler, \(Q\), after removing */ \ /* greatest common divisor */ \ unsigned int RRESAMP(_get_decim)(RRESAMP() _q); \ \ /* Get block length (e.g. greatest common divisor) between original */ \ /* interpolation rate \(P\) and decimation rate \(Q\) values */ \ unsigned int RRESAMP(_get_block_len)(RRESAMP() _q); \ \ /* Get rate of resampler, \(r = P/Q\) = interp/decim */ \ float RRESAMP(_get_rate)(RRESAMP() _q); \ \ /* Write \(Q\) input samples (after removing greatest common divisor) */ \ /* into buffer, but do not compute output. This effectively updates the */ \ /* internal state of the resampler. */ \ /* _q : resamp object */ \ /* _buf : input sample array, [size: decim x 1] */ \ int RRESAMP(_write)(RRESAMP() _q, \ TI * _buf); \ \ /* Execute rational-rate resampler on a block of input samples and */ \ /* store the resulting samples in the output array. */ \ /* Note that the size of the input and output buffers correspond to the */ \ /* values of the interpolation and decimation rates (\(P\) and \(Q\), */ \ /* respectively) passed when the object was created, even if they */ \ /* share a common divisor. */ \ /* Internally the rational resampler reduces \(P\) and \(Q\) */ \ /* by their greatest common denominator to reduce processing; */ \ /* however sometimes it is convenient to create the object based on */ \ /* expected output/input block sizes. This expectation is preserved. */ \ /* So if an object is created with an interpolation rate \(P=80\) */ \ /* and a decimation rate \(Q=72\), the object will internally set */ \ /* \(P=10\) and \(Q=9\) (with a g.c.d of 8); however when */ \ /* "execute" is called the resampler will still expect an input buffer */ \ /* of 72 and an output buffer of 80. */ \ /* _q : resamp object */ \ /* _x : input sample array, [size: decim x 1] */ \ /* _y : output sample array, [size: interp x 1] */ \ int RRESAMP(_execute)(RRESAMP() _q, \ TI * _x, \ TO * _y); \ \ /* Execute on a block of samples */ \ /* _q : resamp object */ \ /* _x : input sample array, [size: decim*n x 1] */ \ /* _n : block size */ \ /* _y : output sample array, [size: interp*n x 1] */ \ int RRESAMP(_execute_block)(RRESAMP() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_RRRF, float, float, float) LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_RRESAMP_DEFINE_API(LIQUID_RRESAMP_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Arbitrary resampler // #define LIQUID_RESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(resamp_rrrf,name) #define LIQUID_RESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(resamp_crcf,name) #define LIQUID_RESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(resamp_cccf,name) #define LIQUID_RESAMP_DEFINE_API(RESAMP,TO,TC,TI) \ \ /* Arbitrary rate resampler, implemented as a polyphase filterbank */ \ typedef struct RESAMP(_s) * RESAMP(); \ \ /* Create arbitrary resampler object from filter prototype */ \ /* _rate : arbitrary resampling rate, 0 < _rate */ \ /* _m : filter semi-length (delay), 0 < _m */ \ /* _fc : filter cutoff frequency, 0 < _fc < 0.5 */ \ /* _as : filter stop-band attenuation [dB], 0 < _as */ \ /* _npfb : number of filters in the bank, 0 < _npfb */ \ RESAMP() RESAMP(_create)(float _rate, \ unsigned int _m, \ float _fc, \ float _as, \ unsigned int _npfb); \ \ /* Create arbitrary resampler object with a specified input resampling */ \ /* rate and default parameters. This is a simplified method to provide */ \ /* a basic resampler with a baseline set of parameters, abstracting */ \ /* away some of the complexities with the filterbank design. */ \ /* The default parameters are */ \ /* m = 7 (filter semi-length), */ \ /* fc = min(0.49,_rate/2) (filter cutoff frequency), */ \ /* as = 60 dB (filter stop-band attenuation), and */ \ /* npfb = 64 (number of filters in the bank). */ \ /* _rate : arbitrary resampling rate, 0 < _rate */ \ RESAMP() RESAMP(_create_default)(float _rate); \ \ /* Copy object including all internal objects and state */ \ RESAMP() RESAMP(_copy)(RESAMP() _q); \ \ /* Destroy arbitrary resampler object, freeing all internal memory */ \ int RESAMP(_destroy)(RESAMP() _q); \ \ /* Print resamp object internals to stdout */ \ int RESAMP(_print)(RESAMP() _q); \ \ /* Reset resamp object internals */ \ int RESAMP(_reset)(RESAMP() _q); \ \ /* Get resampler delay (filter semi-length \(m\)) */ \ unsigned int RESAMP(_get_delay)(RESAMP() _q); \ \ /* Set output scaling for resampler */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ int RESAMP(_set_scale)(RESAMP() _q, \ TC _scale); \ \ /* Get output scaling for resampler */ \ /* _q : resampler object */ \ /* _scale : scaling factor to apply to each output sample */ \ int RESAMP(_get_scale)(RESAMP() _q, \ TC * _scale); \ \ /* Set rate of arbitrary resampler */ \ /* _q : resampling object */ \ /* _rate : new sampling rate, _rate > 0 */ \ int RESAMP(_set_rate)(RESAMP() _q, \ float _rate); \ \ /* Get rate of arbitrary resampler */ \ float RESAMP(_get_rate)(RESAMP() _q); \ \ /* adjust rate of arbitrary resampler */ \ /* _q : resampling object */ \ /* _gamma : rate adjustment factor: rate <- rate * gamma, _gamma > 0 */ \ int RESAMP(_adjust_rate)(RESAMP() _q, \ float _gamma); \ \ /* Set resampling timing phase */ \ /* _q : resampling object */ \ /* _tau : sample timing phase, -1 <= _tau <= 1 */ \ int RESAMP(_set_timing_phase)(RESAMP() _q, \ float _tau); \ \ /* Adjust resampling timing phase */ \ /* _q : resampling object */ \ /* _delta : sample timing adjustment, -1 <= _delta <= 1 */ \ int RESAMP(_adjust_timing_phase)(RESAMP() _q, \ float _delta); \ \ /* Get the number of output samples given current state and input */ \ /* buffer size. */ \ /* _q : resampling object */ \ /* _num_input : number of input samples */ \ unsigned int RESAMP(_get_num_output)(RESAMP() _q, \ unsigned int _num_input); \ \ /* Execute arbitrary resampler on a single input sample and store the */ \ /* resulting samples in the output array. The number of output samples */ \ /* depends upon the resampling rate but will be at most */ \ /* \( \lceil{ r \rceil} \) samples. */ \ /* _q : resamp object */ \ /* _x : single input sample */ \ /* _y : output sample array (pointer) */ \ /* _num_written : number of samples written to _y */ \ int RESAMP(_execute)(RESAMP() _q, \ TI _x, \ TO * _y, \ unsigned int * _num_written); \ \ /* Execute arbitrary resampler on a block of input samples and store */ \ /* the resulting samples in the output array. The number of output */ \ /* samples depends upon the resampling rate and the number of input */ \ /* samples but will be at most \( \lceil{ r n_x \rceil} \) samples. */ \ /* _q : resamp object */ \ /* _x : input buffer, [size: _nx x 1] */ \ /* _nx : input buffer */ \ /* _y : output sample array (pointer) */ \ /* _ny : number of samples written to _y */ \ int RESAMP(_execute_block)(RESAMP() _q, \ TI * _x, \ unsigned int _nx, \ TO * _y, \ unsigned int * _ny); \ LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_RRRF, float, float, float) LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_RESAMP_DEFINE_API(LIQUID_RESAMP_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Multi-stage half-band resampler // // resampling type (interpolator/decimator) typedef enum { LIQUID_RESAMP_INTERP=0, // interpolator LIQUID_RESAMP_DECIM, // decimator } liquid_resamp_type; #define LIQUID_MSRESAMP2_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp2_rrrf,name) #define LIQUID_MSRESAMP2_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp2_crcf,name) #define LIQUID_MSRESAMP2_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp2_cccf,name) #define LIQUID_MSRESAMP2_DEFINE_API(MSRESAMP2,TO,TC,TI) \ \ /* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ /* (half-band) polyphase filter banks for interpolation and decimation. */ \ typedef struct MSRESAMP2(_s) * MSRESAMP2(); \ \ /* Create multi-stage half-band resampler as either decimator or */ \ /* interpolator. */ \ /* _type : resampler type (e.g. LIQUID_RESAMP_DECIM) */ \ /* _num_stages : number of resampling stages, _num_stages <= 16 */ \ /* _fc : filter cut-off frequency, 0 < _fc < 0.5 */ \ /* _f0 : filter center frequency (set to zero) */ \ /* _as : stop-band attenuation [dB], _as > 0 */ \ MSRESAMP2() MSRESAMP2(_create)(int _type, \ unsigned int _num_stages, \ float _fc, \ float _f0, \ float _as); \ \ /* Copy object including all internal objects and state */ \ MSRESAMP2() MSRESAMP2(_copy)(MSRESAMP2() _q); \ \ /* Destroy multi-stage half-band resampler, freeing all internal memory */ \ int MSRESAMP2(_destroy)(MSRESAMP2() _q); \ \ /* Print msresamp object internals to stdout */ \ int MSRESAMP2(_print)(MSRESAMP2() _q); \ \ /* Reset msresamp object internal state */ \ int MSRESAMP2(_reset)(MSRESAMP2() _q); \ \ /* Get multi-stage half-band resampling rate */ \ float MSRESAMP2(_get_rate)(MSRESAMP2() _q); \ \ /* Get number of half-band resampling stages in object */ \ unsigned int MSRESAMP2(_get_num_stages)(MSRESAMP2() _q); \ \ /* Get resampling type (LIQUID_RESAMP_DECIM, LIQUID_RESAMP_INTERP) */ \ int MSRESAMP2(_get_type)(MSRESAMP2() _q); \ \ /* Get group delay (number of output samples) */ \ float MSRESAMP2(_get_delay)(MSRESAMP2() _q); \ \ /* Execute multi-stage resampler, M = 2^num_stages */ \ /* LIQUID_RESAMP_INTERP: input: 1, output: M */ \ /* LIQUID_RESAMP_DECIM: input: M, output: 1 */ \ /* _q : msresamp object */ \ /* _x : input sample array */ \ /* _y : output sample array */ \ int MSRESAMP2(_execute)(MSRESAMP2() _q, \ TI * _x, \ TO * _y); \ LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_RRRF, float, float, float) LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_MSRESAMP2_DEFINE_API(LIQUID_MSRESAMP2_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Multi-stage arbitrary resampler // #define LIQUID_MSRESAMP_MANGLE_RRRF(name) LIQUID_CONCAT(msresamp_rrrf,name) #define LIQUID_MSRESAMP_MANGLE_CRCF(name) LIQUID_CONCAT(msresamp_crcf,name) #define LIQUID_MSRESAMP_MANGLE_CCCF(name) LIQUID_CONCAT(msresamp_cccf,name) #define LIQUID_MSRESAMP_DEFINE_API(MSRESAMP,TO,TC,TI) \ \ /* Multi-stage half-band resampler, implemented as cascaded dyadic */ \ /* (half-band) polyphase filter banks followed by an arbitrary rate */ \ /* resampler for interpolation and decimation. */ \ typedef struct MSRESAMP(_s) * MSRESAMP(); \ \ /* Create multi-stage arbitrary resampler */ \ /* _r : resampling rate (output/input), _r > 0 */ \ /* _as : stop-band attenuation [dB], _as > 0 */ \ MSRESAMP() MSRESAMP(_create)(float _r, \ float _as); \ \ /* Copy object including all internal objects and state */ \ MSRESAMP() MSRESAMP(_copy)(MSRESAMP() _q); \ \ /* Destroy multi-stage arbitrary resampler */ \ int MSRESAMP(_destroy)(MSRESAMP() _q); \ \ /* Print msresamp object internals to stdout */ \ int MSRESAMP(_print)(MSRESAMP() _q); \ \ /* Reset msresamp object internal state */ \ int MSRESAMP(_reset)(MSRESAMP() _q); \ \ /* Get filter delay (output samples) */ \ float MSRESAMP(_get_delay)(MSRESAMP() _q); \ \ /* get overall resampling rate */ \ float MSRESAMP(_get_rate)(MSRESAMP() _q); \ \ /* Get the number of output samples given current state and input */ \ /* buffer size. */ \ /* _q : resampling object */ \ /* _num_input : number of input samples */ \ unsigned int MSRESAMP(_get_num_output)(MSRESAMP() _q, \ unsigned int _num_input); \ \ /* Execute multi-stage resampler on one or more input samples. */ \ /* The number of output samples depends upon the resampling rate and */ \ /* the number of input samples. In general it is good practice to */ \ /* allocate at least \( \lceil{ 1 + 2 r n_x \rceil} \) samples in the */ \ /* output array to avoid overflows. */ \ /* _q : msresamp object */ \ /* _x : input sample array, [size: _nx x 1] */ \ /* _nx : input sample array size */ \ /* _y : pointer to output array for storing result */ \ /* _ny : number of samples written to _y */ \ int MSRESAMP(_execute)(MSRESAMP() _q, \ TI * _x, \ unsigned int _nx, \ TO * _y, \ unsigned int * _ny); \ LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_RRRF, float, float, float) LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_MSRESAMP_DEFINE_API(LIQUID_MSRESAMP_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Direct digital [up/down] synthesizer // #define LIQUID_DDS_MANGLE_CCCF(name) LIQUID_CONCAT(dds_cccf,name) #define LIQUID_DDS_DEFINE_API(DDS,TO,TC,TI) \ \ /* Direct digital (up/down) synthesizer object */ \ typedef struct DDS(_s) * DDS(); \ \ /* Create digital synthesizer object */ \ /* _num_stages : number of half-band stages, _num_stages > 0 */ \ /* _fc : signal relative center frequency, _fc in [-0.5,0.5] */ \ /* _bw : signal relative bandwidth, _bw in (0,1) */ \ /* _as : filter stop-band attenuation (dB), _as > 0 */ \ DDS() DDS(_create)(unsigned int _num_stages, \ float _fc, \ float _bw, \ float _as); \ \ /* Copy object including all internal objects and state */ \ DDS() DDS(_copy)(DDS() _q); \ \ /* Destroy digital synthesizer object */ \ int DDS(_destroy)(DDS() _q); \ \ /* Print synthesizer object internals */ \ int DDS(_print)(DDS() _q); \ \ /* Reset synthesizer object internals */ \ int DDS(_reset)(DDS() _q); \ \ /* Set output scaling for synthesizer */ \ /* _q : synthesizer object */ \ /* _scale : scaling factor to apply to each output sample */ \ int DDS(_set_scale)(DDS() _q, \ TC _scale); \ \ /* Get output scaling for synthesizer */ \ /* _q : synthesizer object */ \ /* _scale : scaling factor to apply to each output sample */ \ int DDS(_get_scale)(DDS() _q, \ TC * _scale); \ \ /* Get number of half-band states in DDS object */ \ unsigned int DDS(_get_num_stages)(DDS() _q); \ \ /* Get delay (samples) when running as interpolator */ \ unsigned int DDS(_get_delay_interp)(DDS() _q); \ \ /* Get delay (samples) when running as decimator */ \ float DDS(_get_delay_decim)(DDS() _q); \ \ /* Run DDS object as decimator */ \ /* _q : synthesizer object */ \ /* _x : input data array, [size: (1<<_num_stages) x 1] */ \ /* _y : output sample */ \ int DDS(_decim_execute)(DDS() _q, \ TI * _x, \ TO * _y); \ \ /* Run DDS object as interpolator */ \ /* _q : synthesizer object */ \ /* _x : input sample */ \ /* _y : output data array, [size: (1<<_num_stages) x 1] */ \ int DDS(_interp_execute)(DDS() _q, \ TI _x, \ TO * _y); \ LIQUID_DDS_DEFINE_API(LIQUID_DDS_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Symbol timing recovery (symbol synchronizer) // #define LIQUID_SYMSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(symsync_rrrf,name) #define LIQUID_SYMSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(symsync_crcf,name) #define LIQUID_SYMSYNC_DEFINE_API(SYMSYNC,TO,TC,TI) \ \ /* Multi-rate symbol synchronizer for symbol timing recovery. */ \ typedef struct SYMSYNC(_s) * SYMSYNC(); \ \ /* Create synchronizer object from external coefficients */ \ /* _k : samples per symbol, _k >= 2 */ \ /* _M : number of filters in the bank, _M > 0 */ \ /* _h : matched filter coefficients, [size: _h_len x 1] */ \ /* _h_len : length of matched filter; \( h_{len} = 2 k m + 1 \) */ \ SYMSYNC() SYMSYNC(_create)(unsigned int _k, \ unsigned int _M, \ TC * _h, \ unsigned int _h_len); \ \ /* Create square-root Nyquist symbol synchronizer from prototype */ \ /* _type : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : samples/symbol, _k >= 2 */ \ /* _m : symbol delay, _m > 0 */ \ /* _beta : rolloff factor, 0 <= _beta <= 1 */ \ /* _M : number of filters in the bank, _M > 0 */ \ SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ unsigned int _M); \ \ /* Create symsync using Kaiser filter interpolator. This is useful when */ \ /* the input signal has its matched filter applied already. */ \ /* _k : input samples/symbol, _k >= 2 */ \ /* _m : symbol delay, _m > 0 */ \ /* _beta : rolloff factor, 0<= _beta <= 1 */ \ /* _M : number of filters in the bank, _M > 0 */ \ SYMSYNC() SYMSYNC(_create_kaiser)(unsigned int _k, \ unsigned int _m, \ float _beta, \ unsigned int _M); \ \ /* Copy object including all internal objects and state */ \ SYMSYNC() SYMSYNC(_copy)(SYMSYNC() _q); \ \ /* Destroy symsync object, freeing all internal memory */ \ int SYMSYNC(_destroy)(SYMSYNC() _q); \ \ /* Print symsync object's parameters to stdout */ \ int SYMSYNC(_print)(SYMSYNC() _q); \ \ /* Reset symsync internal state */ \ int SYMSYNC(_reset)(SYMSYNC() _q); \ \ /* Lock the symbol synchronizer's loop control */ \ int SYMSYNC(_lock)(SYMSYNC() _q); \ \ /* Unlock the symbol synchronizer's loop control */ \ int SYMSYNC(_unlock)(SYMSYNC() _q); \ \ /* Check the lock state of the symbol synchronizer's loop control, */ \ /* returning 1 if the object is locked, 0 if unlocked. */ \ int SYMSYNC(_is_locked)(SYMSYNC() _q); \ \ /* Set synchronizer output rate (samples/symbol) */ \ /* _q : synchronizer object */ \ /* _k_out : output samples/symbol, _k_out > 0 */ \ int SYMSYNC(_set_output_rate)(SYMSYNC() _q, \ unsigned int _k_out); \ \ /* Set loop-filter bandwidth */ \ /* _q : synchronizer object */ \ /* _bt : loop bandwidth, 0 <= _bt <= 1 */ \ int SYMSYNC(_set_lf_bw)(SYMSYNC() _q, \ float _bt); \ \ /* Return instantaneous fractional timing offset estimate */ \ float SYMSYNC(_get_tau)(SYMSYNC() _q); \ \ /* Execute synchronizer on input data array */ \ /* _q : synchronizer object */ \ /* _x : input data array, [size: _nx x 1] */ \ /* _nx : number of input samples */ \ /* _y : output data array */ \ /* _ny : number of samples written to output buffer */ \ int SYMSYNC(_execute)(SYMSYNC() _q, \ TI * _x, \ unsigned int _nx, \ TO * _y, \ unsigned int * _ny); \ LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_RRRF, float, float, float) LIQUID_SYMSYNC_DEFINE_API(LIQUID_SYMSYNC_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) // // Finite impulse response Farrow filter // #define LIQUID_FIRFARROW_MANGLE_RRRF(name) LIQUID_CONCAT(firfarrow_rrrf,name) #define LIQUID_FIRFARROW_MANGLE_CRCF(name) LIQUID_CONCAT(firfarrow_crcf,name) //#define LIQUID_FIRFARROW_MANGLE_CCCF(name) LIQUID_CONCAT(firfarrow_cccf,name) // Macro: // FIRFARROW : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FIRFARROW_DEFINE_API(FIRFARROW,TO,TC,TI) \ \ /* Finite impulse response (FIR) Farrow filter for timing delay */ \ typedef struct FIRFARROW(_s) * FIRFARROW(); \ \ /* Create firfarrow object */ \ /* _h_len : filter length, _h_len >= 2 */ \ /* _p : polynomial order, _p >= 1 */ \ /* _fc : filter cutoff frequency, 0 <= _fc <= 0.5 */ \ /* _as : stopband attenuation [dB], _as > 0 */ \ FIRFARROW() FIRFARROW(_create)(unsigned int _h_len, \ unsigned int _p, \ float _fc, \ float _as); \ \ /* Destroy firfarrow object, freeing all internal memory */ \ int FIRFARROW(_destroy)(FIRFARROW() _q); \ \ /* Print firfarrow object's internal properties */ \ int FIRFARROW(_print)(FIRFARROW() _q); \ \ /* Reset firfarrow object's internal state */ \ int FIRFARROW(_reset)(FIRFARROW() _q); \ \ /* Push sample into firfarrow object */ \ /* _q : firfarrow object */ \ /* _x : input sample */ \ int FIRFARROW(_push)(FIRFARROW() _q, \ TI _x); \ \ /* Set fractional delay of firfarrow object */ \ /* _q : firfarrow object */ \ /* _mu : fractional sample delay, -1 <= _mu <= 1 */ \ int FIRFARROW(_set_delay)(FIRFARROW() _q, \ float _mu); \ \ /* Execute firfarrow internal dot product */ \ /* _q : firfarrow object */ \ /* _y : output sample pointer */ \ int FIRFARROW(_execute)(FIRFARROW() _q, \ TO * _y); \ \ /* Execute firfarrow filter on block of samples. */ \ /* In-place operation is permitted (the input and output arrays may */ \ /* share the same pointer) */ \ /* _q : firfarrow object */ \ /* _x : input array, [size: _n x 1] */ \ /* _n : input, output array size */ \ /* _y : output array, [size: _n x 1] */ \ int FIRFARROW(_execute_block)(FIRFARROW() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ \ /* Get length of firfarrow object (number of filter taps) */ \ unsigned int FIRFARROW(_get_length)(FIRFARROW() _q); \ \ /* Get coefficients of firfarrow object */ \ /* _q : firfarrow object */ \ /* _h : output coefficients pointer, [size: _h_len x 1] */ \ int FIRFARROW(_get_coefficients)(FIRFARROW() _q, \ float * _h); \ \ /* Compute complex frequency response */ \ /* _q : filter object */ \ /* _fc : frequency */ \ /* _H : output frequency response */ \ int FIRFARROW(_freqresponse)(FIRFARROW() _q, \ float _fc, \ liquid_float_complex * _H); \ \ /* Compute group delay [samples] */ \ /* _q : filter object */ \ /* _fc : frequency */ \ float FIRFARROW(_groupdelay)(FIRFARROW() _q, \ float _fc); \ LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_RRRF, float, float, float) LIQUID_FIRFARROW_DEFINE_API(LIQUID_FIRFARROW_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) // // Order-statistic filter // #define LIQUID_ORDFILT_MANGLE_RRRF(name) LIQUID_CONCAT(ordfilt_rrrf,name) // Macro: // ORDFILT : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_ORDFILT_DEFINE_API(ORDFILT,TO,TC,TI) \ \ /* Finite impulse response (FIR) filter */ \ typedef struct ORDFILT(_s) * ORDFILT(); \ \ /* Create a order-statistic filter (ordfilt) object by specifying */ \ /* the buffer size and appropriate sample index of order statistic. */ \ /* _n : buffer size, _n > 0 */ \ /* _k : sample index for order statistic, 0 <= _k < _n */ \ ORDFILT() ORDFILT(_create)(unsigned int _n, \ unsigned int _k); \ \ /* Create a median filter by specifying buffer semi-length. */ \ /* _m : buffer semi-length */ \ ORDFILT() ORDFILT(_create_medfilt)(unsigned int _m); \ \ /* Copy object including all internal objects and state */ \ ORDFILT() ORDFILT(_copy)(ORDFILT() _q); \ \ /* Destroy filter object and free all internal memory */ \ int ORDFILT(_destroy)(ORDFILT() _q); \ \ /* Reset filter object's internal buffer */ \ int ORDFILT(_reset)(ORDFILT() _q); \ \ /* Print filter object information to stdout */ \ int ORDFILT(_print)(ORDFILT() _q); \ \ /* Push sample into filter object's internal buffer */ \ /* _q : filter object */ \ /* _x : single input sample */ \ int ORDFILT(_push)(ORDFILT() _q, \ TI _x); \ \ /* Write block of samples into object's internal buffer */ \ /* _q : filter object */ \ /* _x : array of input samples, [size: _n x 1] */ \ /* _n : number of input elements */ \ int ORDFILT(_write)(ORDFILT() _q, \ TI * _x, \ unsigned int _n); \ \ /* Execute on the filter's internal buffer */ \ /* _q : filter object */ \ /* _y : pointer to single output sample */ \ int ORDFILT(_execute)(ORDFILT() _q, \ TO * _y); \ \ /* Execute filter on one sample, equivalent to push() and execute() */ \ /* _q : filter object */ \ /* _x : single input sample */ \ /* _y : pointer to single output sample */ \ int ORDFILT(_execute_one)(ORDFILT() _q, \ TI _x, \ TO * _y); \ \ /* Execute the filter on a block of input samples; in-place operation */ \ /* is permitted (_x and _y may point to the same place in memory) */ \ /* _q : filter object */ \ /* _x : pointer to input array, [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _y : pointer to output array, [size: _n x 1] */ \ int ORDFILT(_execute_block)(ORDFILT() _q, \ TI * _x, \ unsigned int _n, \ TO * _y); \ LIQUID_ORDFILT_DEFINE_API(LIQUID_ORDFILT_MANGLE_RRRF, float, float, float) // // MODULE : framing // // framesyncstats : generic frame synchronizer statistic structure typedef struct { // signal quality float evm; // error vector magnitude [dB] float rssi; // received signal strength indicator [dB] float cfo; // carrier frequency offset (f/Fs) // demodulated frame symbols liquid_float_complex * framesyms; // pointer to array, [size: framesyms x 1] unsigned int num_framesyms; // length of framesyms // modulation/coding scheme etc. unsigned int mod_scheme; // modulation scheme unsigned int mod_bps; // modulation depth (bits/symbol) unsigned int check; // data validity check (crc, checksum) unsigned int fec0; // forward error-correction (inner) unsigned int fec1; // forward error-correction (outer) } framesyncstats_s; // external framesyncstats default object extern framesyncstats_s framesyncstats_default; // initialize framesyncstats object on default int framesyncstats_init_default(framesyncstats_s * _stats); // print framesyncstats object int framesyncstats_print(framesyncstats_s * _stats); // framedatastats : gather frame data typedef struct { unsigned int num_frames_detected; unsigned int num_headers_valid; unsigned int num_payloads_valid; unsigned long int num_bytes_received; } framedatastats_s; // reset framedatastats object int framedatastats_reset(framedatastats_s * _stats); // print framedatastats object int framedatastats_print(framedatastats_s * _stats); // Generic frame synchronizer callback function type // _header : header data, [size: 8 bytes] // _header_valid : is header valid? (0:no, 1:yes) // _payload : payload data, [size: _payload_len] // _payload_len : length of payload (bytes) // _payload_valid : is payload valid? (0:no, 1:yes) // _stats : frame statistics object // _userdata : pointer to userdata typedef int (*framesync_callback)(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata); // framesync csma callback functions invoked when signal levels is high or low // _userdata : user-defined data pointer typedef void (*framesync_csma_callback)(void * _userdata); #define LIQUID_QPACKETMODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(qpacketmodem,name) // Macro: // QPACKETMODEM : name-mangling macro // T : primitive data type #define LIQUID_QPACKETMODEM_DEFINE_API(QPACKETMODEM,T,TC) \ \ /* Packet encoder/decoder */ \ typedef struct QPACKETMODEM(_s) * QPACKETMODEM(); \ \ /* Create packet encoder */ \ QPACKETMODEM() QPACKETMODEM(_create)(); \ \ /* Copy object including all internal objects and state */ \ QPACKETMODEM() QPACKETMODEM(_copy) (QPACKETMODEM() _q); \ \ /* Destroy object, freeing all allocated memory */ \ int QPACKETMODEM(_destroy)(QPACKETMODEM() _q); \ \ /* Print modem status to stdout */ \ int QPACKETMODEM(_print)(QPACKETMODEM() _q); \ \ /* Reset internal state of modem object */ \ int QPACKETMODEM(_reset)(QPACKETMODEM() _q); \ \ /* Configure object with particular parameters */ \ /* _q : qpacketmodem object */ \ /* _payload_len : length of payload message [bytes] */ \ /* _check : data integrity check, e.g LIQUID_CRC_32 */ \ /* _fec0 : forward error-correction scheme (inner), e.g. */ \ /* LIQUID_FEC_GOLAY2412 */ \ /* _fec1 : forward error-correction scheme (outer) */ \ /* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ int QPACKETMODEM(_configure)(QPACKETMODEM() _q, \ unsigned int _payload_len, \ crc_scheme _check, \ fec_scheme _fec0, \ fec_scheme _fec1, \ int _ms); \ \ /* Get length of encoded frame in symbols */ \ unsigned int QPACKETMODEM(_get_frame_len)(QPACKETMODEM() _q); \ \ /* Get unencoded/decoded payload length (bytes) */ \ unsigned int QPACKETMODEM(_get_payload_len)(QPACKETMODEM() _q); \ \ /* Get data integrity check, e.g. LIQUID_CRC_32 */ \ unsigned int QPACKETMODEM(_get_crc)(QPACKETMODEM() _q); \ \ /* Get inner forward error-correction scheme, e.g. LIQUID_GOLAY_2412 */ \ unsigned int QPACKETMODEM(_get_fec0)(QPACKETMODEM() _q); \ \ /* Get outer forward error-correction scheme, e.g. LIQUID_GOLAY_2412 */ \ unsigned int QPACKETMODEM(_get_fec1)(QPACKETMODEM() _q); \ \ /* Get modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ unsigned int QPACKETMODEM(_get_modscheme)(QPACKETMODEM() _q); \ \ /* Get demodulator phase error (instantaneous) [radians] */ \ float QPACKETMODEM(_get_demodulator_phase_error)(QPACKETMODEM() _q); \ \ /* Get demodulator error-vector magnitude after frame was received */ \ float QPACKETMODEM(_get_demodulator_evm)(QPACKETMODEM() _q); \ \ /* encode packet into un-modulated frame symbol indices */ \ /* _q : qpacketmodem object */ \ /* _payload : unencoded payload bytes */ \ /* _syms : encoded but un-modulated payload symbol indices */ \ int QPACKETMODEM(_encode_syms)(QPACKETMODEM() _q, \ const unsigned char * _payload, \ unsigned char * _syms); \ \ /* decode packet from demodulated frame symbol indices (hard-decision */ \ /* decoding) */ \ /* _q : qpacketmodem object */ \ /* _syms : received hard-decision symbol indices, */ \ /* [size: frame_len x 1] */ \ /* _payload : recovered decoded payload bytes */ \ /* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode_syms)(QPACKETMODEM() _q, \ unsigned char * _syms, \ unsigned char * _payload); \ \ /* decode packet from demodulated frame bits (soft-decision decoding) */ \ /* _q : qpacketmodem object */ \ /* _bits : received soft-decision bits, [size: bps*frame_len x 1] */ \ /* _payload : recovered decoded payload bytes */ \ int QPACKETMODEM(_decode_bits)(QPACKETMODEM() _q, \ unsigned char * _bits, \ unsigned char * _payload); \ \ /* encode and modulate packet into modulated frame samples */ \ /* _q : qpacketmodem object */ \ /* _payload : unencoded payload bytes */ \ /* _frame : encoded/modulated payload symbols */ \ int QPACKETMODEM(_encode)(QPACKETMODEM() _q, \ const unsigned char * _payload, \ TC * _frame); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using hard-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ /* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode)(QPACKETMODEM() _q, \ TC * _frame, \ unsigned char * _payload); \ \ /* decode packet from modulated frame samples, returning flag if CRC */ \ /* passed using soft-decision decoding */ \ /* _q : qpacketmodem object */ \ /* _frame : encoded/modulated payload symbols */ \ /* _payload : recovered decoded payload bytes */ \ /* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode_soft)(QPACKETMODEM() _q, \ TC * _frame, \ unsigned char * _payload); \ \ /* decode symbol from modulated frame samples, returning flag if all */ \ /* symbols received */ \ /* _q : qpacketmodem object */ \ /* _symbol : input received symbol before demodulation */ \ /* _return : flag indicating if all symbols were received */ \ int QPACKETMODEM(_decode_soft_sym)(QPACKETMODEM() _q, \ TC _symbol); \ \ /* Decode entire packet, assuming that entire frame has been received. */ \ /* _q : qpacketmodem object */ \ /* _payload : output payload [bytes] */ \ /* _return : flag indicating if data integrity check passed */ \ int QPACKETMODEM(_decode_soft_payload)(QPACKETMODEM() _q, \ unsigned char * _payload); \ LIQUID_QPACKETMODEM_DEFINE_API(LIQUID_QPACKETMODEM_MANGLE_FLOAT,float,liquid_float_complex) // // pilot generator/synchronizer for packet burst recovery // // get number of pilots in frame unsigned int qpilot_num_pilots(unsigned int _payload_len, unsigned int _pilot_spacing); // get length of frame with a particular payload length and pilot spacing unsigned int qpilot_frame_len(unsigned int _payload_len, unsigned int _pilot_spacing); // // pilot generator for packet burst recovery // typedef struct qpilotgen_s * qpilotgen; // create packet encoder qpilotgen qpilotgen_create(unsigned int _payload_len, unsigned int _pilot_spacing); qpilotgen qpilotgen_recreate(qpilotgen _q, unsigned int _payload_len, unsigned int _pilot_spacing); // Copy object including all internal objects and state qpilotgen qpilotgen_copy(qpilotgen _q); int qpilotgen_destroy(qpilotgen _q); int qpilotgen_reset( qpilotgen _q); int qpilotgen_print( qpilotgen _q); unsigned int qpilotgen_get_frame_len(qpilotgen _q); // insert pilot symbols int qpilotgen_execute(qpilotgen _q, liquid_float_complex * _payload, liquid_float_complex * _frame); // // pilot synchronizer for packet burst recovery // typedef struct qpilotsync_s * qpilotsync; // create packet encoder qpilotsync qpilotsync_create(unsigned int _payload_len, unsigned int _pilot_spacing); qpilotsync qpilotsync_recreate(qpilotsync _q, unsigned int _payload_len, unsigned int _pilot_spacing); // Copy object including all internal objects and state qpilotsync qpilotsync_copy(qpilotsync _q); int qpilotsync_destroy(qpilotsync _q); int qpilotsync_reset( qpilotsync _q); int qpilotsync_print( qpilotsync _q); unsigned int qpilotsync_get_frame_len(qpilotsync _q); // recover frame symbols from received frame int qpilotsync_execute(qpilotsync _q, liquid_float_complex * _frame, liquid_float_complex * _payload); // get estimates float qpilotsync_get_dphi(qpilotsync _q); float qpilotsync_get_phi (qpilotsync _q); float qpilotsync_get_gain(qpilotsync _q); float qpilotsync_get_evm (qpilotsync _q); // // Basic frame generator (64 bytes data payload) // // frame length in samples #define LIQUID_FRAME64_LEN (1440) typedef struct framegen64_s * framegen64; // create frame generator framegen64 framegen64_create(); // copy object framegen64 framegen64_copy(framegen64 _q); // destroy frame generator int framegen64_destroy(framegen64 _q); // print frame generator internal properties int framegen64_print(framegen64 _q); // generate frame // _q : frame generator object // _header : 8-byte header data, NULL for random // _payload : 64-byte payload data, NULL for random // _frame : output frame samples, [size: LIQUID_FRAME64_LEN x 1] int framegen64_execute(framegen64 _q, unsigned char * _header, unsigned char * _payload, liquid_float_complex * _frame); typedef struct framesync64_s * framesync64; // create framesync64 object // _callback : callback function // _userdata : user data pointer passed to callback function framesync64 framesync64_create(framesync_callback _callback, void * _userdata); // copy object framesync64 framesync64_copy(framesync64 _q); // destroy frame synchronizer int framesync64_destroy(framesync64 _q); // print frame synchronizer internal properties int framesync64_print(framesync64 _q); // reset frame synchronizer internal state int framesync64_reset(framesync64 _q); // set the callback and userdata fields int framesync64_set_callback(framesync64 _q, framesync_callback _callback); int framesync64_set_userdata(framesync64 _q, void * _userdata); // push samples through frame synchronizer // _q : frame synchronizer object // _x : input samples, [size: _n x 1] // _n : number of input samples int framesync64_execute(framesync64 _q, liquid_float_complex * _x, unsigned int _n); DEPRECATED("debugging enabled by default; return non-zero value to export file", int framesync64_debug_enable(framesync64 _q); ) DEPRECATED("debugging enabled by default; return non-zero value to export file", int framesync64_debug_disable(framesync64 _q); ) DEPRECATED("binary debugging file exported on non-zero return value", int framesync64_debug_print(framesync64 _q, const char * _filename); ) // set prefix for exporting debugging files, default: "framesync64" // _q : frame sync object // _prefix : string with valid file path int framesync64_set_prefix(framesync64 _q, const char * _prefix); // get prefix for exporting debugging files const char * framesync64_get_prefix(framesync64 _q); // get number of files exported unsigned int framesync64_get_num_files_exported(framesync64 _q); // get name of last file written const char * framesync64_get_filename(framesync64 _q); // get/set detection threshold float framesync64_get_threshold(framesync64 _q); int framesync64_set_threshold(framesync64 _q, float _threshold); // frame data statistics int framesync64_reset_framedatastats(framesync64 _q); framedatastats_s framesync64_get_framedatastats (framesync64 _q); #if 0 // advanced modes int framesync64_set_csma_callbacks(framesync64 _q, framesync_csma_callback _csma_lock, framesync_csma_callback _csma_unlock, void * _csma_userdata); #endif // // Flexible frame : adjustable payload, mod scheme, etc., but bring // your own error correction, redundancy check // // frame generator typedef struct { unsigned int check; // data validity check unsigned int fec0; // forward error-correction scheme (inner) unsigned int fec1; // forward error-correction scheme (outer) unsigned int mod_scheme; // modulation scheme } flexframegenprops_s; int flexframegenprops_init_default(flexframegenprops_s * _fgprops); typedef struct flexframegen_s * flexframegen; // create flexframegen object // _props : frame properties (modulation scheme, etc.) flexframegen flexframegen_create(flexframegenprops_s * _props); // destroy flexframegen object int flexframegen_destroy(flexframegen _q); // print flexframegen object internals int flexframegen_print(flexframegen _q); // reset flexframegen object internals int flexframegen_reset(flexframegen _q); // is frame assembled? int flexframegen_is_assembled(flexframegen _q); // get frame properties int flexframegen_getprops(flexframegen _q, flexframegenprops_s * _props); // set frame properties int flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props); // set length of user-defined portion of header int flexframegen_set_header_len(flexframegen _q, unsigned int _len); // set properties for header section int flexframegen_set_header_props(flexframegen _q, flexframegenprops_s * _props); // get length of assembled frame (samples) unsigned int flexframegen_getframelen(flexframegen _q); // assemble a frame from an array of data // _q : frame generator object // _header : frame header // _payload : payload data, [size: _payload_len x 1] // _payload_len : payload data length int flexframegen_assemble(flexframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len); // write samples of assembled frame, two samples at a time, returning // '1' when frame is complete, '0' otherwise. Zeros will be written // to the buffer if the frame is not assembled // _q : frame generator object // _buffer : output buffer, [size: _buffer_len x 1] // _buffer_len : output buffer length int flexframegen_write_samples(flexframegen _q, liquid_float_complex * _buffer, unsigned int _buffer_len); // frame synchronizer typedef struct flexframesync_s * flexframesync; // create flexframesync object // _callback : callback function // _userdata : user data pointer passed to callback function flexframesync flexframesync_create(framesync_callback _callback, void * _userdata); // destroy frame synchronizer int flexframesync_destroy(flexframesync _q); // print frame synchronizer internal properties int flexframesync_print(flexframesync _q); // reset frame synchronizer internal state int flexframesync_reset(flexframesync _q); // has frame been detected? int flexframesync_is_frame_open(flexframesync _q); // change length of user-defined region in header int flexframesync_set_header_len(flexframesync _q, unsigned int _len); // enable or disable soft decoding of header int flexframesync_decode_header_soft(flexframesync _q, int _soft); // enable or disable soft decoding of payload int flexframesync_decode_payload_soft(flexframesync _q, int _soft); // set properties for header section int flexframesync_set_header_props(flexframesync _q, flexframegenprops_s * _props); // push samples through frame synchronizer // _q : frame synchronizer object // _x : input samples, [size: _n x 1] // _n : number of input samples int flexframesync_execute(flexframesync _q, liquid_float_complex * _x, unsigned int _n); // frame data statistics int flexframesync_reset_framedatastats(flexframesync _q); framedatastats_s flexframesync_get_framedatastats (flexframesync _q); // enable/disable debugging int flexframesync_debug_enable(flexframesync _q); int flexframesync_debug_disable(flexframesync _q); int flexframesync_debug_print(flexframesync _q, const char * _filename); // // bpacket : binary packet suitable for data streaming // // // bpacket generator/encoder // typedef struct bpacketgen_s * bpacketgen; // create bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_create(unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1); // re-create bpacketgen object from old object // _q : old bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_recreate(bpacketgen _q, unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1); // destroy bpacketgen object, freeing all internally-allocated memory void bpacketgen_destroy(bpacketgen _q); // print bpacketgen internals void bpacketgen_print(bpacketgen _q); // return length of full packet unsigned int bpacketgen_get_packet_len(bpacketgen _q); // encode packet void bpacketgen_encode(bpacketgen _q, unsigned char * _msg_dec, unsigned char * _packet); // // bpacket synchronizer/decoder // typedef struct bpacketsync_s * bpacketsync; typedef int (*bpacketsync_callback)(unsigned char * _payload, int _payload_valid, unsigned int _payload_len, framesyncstats_s _stats, void * _userdata); bpacketsync bpacketsync_create(unsigned int _m, bpacketsync_callback _callback, void * _userdata); int bpacketsync_destroy(bpacketsync _q); int bpacketsync_print(bpacketsync _q); int bpacketsync_reset(bpacketsync _q); // run synchronizer on array of input bytes // _q : bpacketsync object // _bytes : input data array, [size: _n x 1] // _n : input array size int bpacketsync_execute(bpacketsync _q, unsigned char * _bytes, unsigned int _n); // run synchronizer on input byte // _q : bpacketsync object // _byte : input byte int bpacketsync_execute_byte(bpacketsync _q, unsigned char _byte); // run synchronizer on input symbol // _q : bpacketsync object // _sym : input symbol with _bps significant bits // _bps : number of bits in input symbol int bpacketsync_execute_sym(bpacketsync _q, unsigned char _sym, unsigned int _bps); // execute one bit at a time int bpacketsync_execute_bit(bpacketsync _q, unsigned char _bit); // // M-FSK frame generator // typedef struct fskframegen_s * fskframegen; // create M-FSK frame generator fskframegen fskframegen_create(); int fskframegen_destroy (fskframegen _fg); int fskframegen_print (fskframegen _fg); int fskframegen_reset (fskframegen _fg); int fskframegen_assemble(fskframegen _fg, unsigned char * _header, unsigned char * _payload, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, fec_scheme _fec1); unsigned int fskframegen_getframelen(fskframegen _q); int fskframegen_write_samples(fskframegen _fg, liquid_float_complex * _buf, unsigned int _buf_len); // // M-FSK frame synchronizer // typedef struct fskframesync_s * fskframesync; // create M-FSK frame synchronizer // _callback : callback function // _userdata : user data pointer passed to callback function fskframesync fskframesync_create(framesync_callback _callback, void * _userdata); int fskframesync_destroy(fskframesync _q); int fskframesync_print (fskframesync _q); int fskframesync_reset (fskframesync _q); int fskframesync_execute(fskframesync _q, liquid_float_complex _x); int fskframesync_execute_block(fskframesync _q, liquid_float_complex * _x, unsigned int _n); // debugging int fskframesync_debug_enable (fskframesync _q); int fskframesync_debug_disable(fskframesync _q); int fskframesync_debug_export (fskframesync _q, const char * _filename); // // GMSK frame generator // typedef struct gmskframegen_s * gmskframegen; // create GMSK frame generator with specific parameters // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskframegen gmskframegen_create_set(unsigned int _k, unsigned int _m, float _BT); // create default GMSK frame generator (k=2, m=3, BT=0.5) gmskframegen gmskframegen_create(); int gmskframegen_destroy (gmskframegen _q); int gmskframegen_is_assembled (gmskframegen _q); int gmskframegen_print (gmskframegen _q); int gmskframegen_set_header_len(gmskframegen _q, unsigned int _len); int gmskframegen_reset (gmskframegen _q); int gmskframegen_assemble (gmskframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, fec_scheme _fec1); // assemble default frame with a particular size payload int gmskframegen_assemble_default(gmskframegen _q, unsigned int _payload_len); unsigned int gmskframegen_getframelen(gmskframegen _q); // write samples of assembled frame // _q : frame generator object // _buf : output buffer, [size: _buf_len x 1] // _buf_len : output buffer length int gmskframegen_write(gmskframegen _q, liquid_float_complex * _buf, unsigned int _buf_len); // write samples of assembled frame // _q : frame generator object // _buf : output buffer, [size: k x 1] DEPRECATED("use gmskframegen_write(...) instead", int gmskframegen_write_samples(gmskframegen _q, liquid_float_complex * _buf); ) // // GMSK frame synchronizer // typedef struct gmskframesync_s * gmskframesync; // create GMSK frame synchronizer // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create_set(unsigned int _k, unsigned int _m, float _BT, framesync_callback _callback, void * _userdata); // create GMSK frame synchronizer with default parameters (k=2, m=3, BT=0.5) // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create(framesync_callback _callback, void * _userdata); int gmskframesync_destroy(gmskframesync _q); int gmskframesync_print(gmskframesync _q); int gmskframesync_set_header_len(gmskframesync _q, unsigned int _len); int gmskframesync_reset(gmskframesync _q); int gmskframesync_is_frame_open(gmskframesync _q); int gmskframesync_execute(gmskframesync _q, liquid_float_complex * _x, unsigned int _n); // frame data statistics int gmskframesync_reset_framedatastats(gmskframesync _q); framedatastats_s gmskframesync_get_framedatastats (gmskframesync _q); // debug methods DEPRECATED("debug methods add complexity and provide little value", int gmskframesync_debug_enable(gmskframesync _q); ) DEPRECATED("debug methods add complexity and provide little value", int gmskframesync_debug_disable(gmskframesync _q); ) DEPRECATED("debug methods add complexity and provide little value", int gmskframesync_debug_print(gmskframesync _q, const char * _filename); ) // // DSSS frame generator // typedef struct { unsigned int check; unsigned int fec0; unsigned int fec1; } dsssframegenprops_s; typedef struct dsssframegen_s * dsssframegen; dsssframegen dsssframegen_create(dsssframegenprops_s * _props); int dsssframegen_destroy(dsssframegen _q); int dsssframegen_reset(dsssframegen _q); int dsssframegen_is_assembled(dsssframegen _q); int dsssframegen_getprops(dsssframegen _q, dsssframegenprops_s * _props); int dsssframegen_setprops(dsssframegen _q, dsssframegenprops_s * _props); int dsssframegen_set_header_len(dsssframegen _q, unsigned int _len); int dsssframegen_set_header_props(dsssframegen _q, dsssframegenprops_s * _props); unsigned int dsssframegen_getframelen(dsssframegen _q); // assemble a frame from an array of data // _q : frame generator object // _header : frame header // _payload : payload data, [size: _payload_len x 1] // _payload_len : payload data length int dsssframegen_assemble(dsssframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len); int dsssframegen_write_samples(dsssframegen _q, liquid_float_complex * _buffer, unsigned int _buffer_len); // // DSSS frame synchronizer // typedef struct dsssframesync_s * dsssframesync; dsssframesync dsssframesync_create(framesync_callback _callback, void * _userdata); int dsssframesync_destroy (dsssframesync _q); int dsssframesync_print (dsssframesync _q); int dsssframesync_reset (dsssframesync _q); int dsssframesync_is_frame_open (dsssframesync _q); int dsssframesync_set_header_len (dsssframesync _q, unsigned int _len); int dsssframesync_decode_header_soft (dsssframesync _q, int _soft); int dsssframesync_decode_payload_soft (dsssframesync _q, int _soft); int dsssframesync_set_header_props (dsssframesync _q, dsssframegenprops_s * _props); int dsssframesync_execute (dsssframesync _q, liquid_float_complex * _x, unsigned int _n); int dsssframesync_reset_framedatastats(dsssframesync _q); int dsssframesync_debug_enable (dsssframesync _q); int dsssframesync_debug_disable (dsssframesync _q); int dsssframesync_debug_print (dsssframesync _q, const char * _filename); framedatastats_s dsssframesync_get_framedatastats (dsssframesync _q); // // Direct sequence/spread spectrum framing with fixed 64-byte payload // // frame generator object type typedef struct dsssframe64gen_s * dsssframe64gen; // create dsssframe64gen object dsssframe64gen dsssframe64gen_create(); // copy object dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig); // destroy dsssframe64gen object int dsssframe64gen_destroy(dsssframe64gen _q); // print dsssframe64gen object internals int dsssframe64gen_print(dsssframe64gen _q); // get length of assembled frame (samples) unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); // generate a frame // _q : frame generator object // _header : 8-byte header data, NULL for random // _payload : 64-byte payload data, NULL for random // _frame : output frame samples, [size: dsssframegen64gen_get_frame_len() x 1] int dsssframe64gen_execute(dsssframe64gen _q, const unsigned char * _header, const unsigned char * _payload, liquid_float_complex * _buf); // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q); // frame synchronizer object type typedef struct dsssframe64sync_s * dsssframe64sync; dsssframe64sync dsssframe64sync_create(framesync_callback _callback, void * _userdata); // copy object dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig); int dsssframe64sync_destroy (dsssframe64sync _q); int dsssframe64sync_print (dsssframe64sync _q); int dsssframe64sync_reset (dsssframe64sync _q); int dsssframe64sync_is_frame_open (dsssframe64sync _q); int dsssframe64sync_set_callback(dsssframe64sync _q, framesync_callback _callback); int dsssframe64sync_set_context(dsssframe64sync _q, void * _context); // execute frame synchronizer // _q : frame synchronizer object // _buf : input sample array, shape: (_buf_len,) // _buf_len : number of input samples int dsssframe64sync_execute(dsssframe64sync _q, liquid_float_complex * _buf, unsigned int _buf_len); // get detection threshold float dsssframe64sync_get_threshold(dsssframe64sync _q); // set detection threshold int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold); // get carrier offset search range [radians/sample] float dsssframe64sync_get_range(dsssframe64sync _q); // set carrier offset search range int dsssframe64sync_set_range(dsssframe64sync _q, float _dphi_max); // reset frame data statistics int dsssframe64sync_reset_framedatastats(dsssframe64sync _q); // retrieve frame data statistics framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q); // // OFDM flexframe generator // // ofdm frame generator properties typedef struct { unsigned int check; // data validity check unsigned int fec0; // forward error-correction scheme (inner) unsigned int fec1; // forward error-correction scheme (outer) unsigned int mod_scheme; // modulation scheme //unsigned int block_size; // framing block size } ofdmflexframegenprops_s; int ofdmflexframegenprops_init_default(ofdmflexframegenprops_s * _props); typedef struct ofdmflexframegen_s * ofdmflexframegen; // create OFDM flexible framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _fgprops : frame properties (modulation scheme, etc.) ofdmflexframegen ofdmflexframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmflexframegenprops_s * _fgprops); // destroy ofdmflexframegen object int ofdmflexframegen_destroy(ofdmflexframegen _q); // print parameters, properties, etc. int ofdmflexframegen_print(ofdmflexframegen _q); // reset ofdmflexframegen object internals int ofdmflexframegen_reset(ofdmflexframegen _q); // is frame assembled? int ofdmflexframegen_is_assembled(ofdmflexframegen _q); // get properties int ofdmflexframegen_getprops(ofdmflexframegen _q, ofdmflexframegenprops_s * _props); // set properties int ofdmflexframegen_setprops(ofdmflexframegen _q, ofdmflexframegenprops_s * _props); // set user-defined header length int ofdmflexframegen_set_header_len(ofdmflexframegen _q, unsigned int _len); int ofdmflexframegen_set_header_props(ofdmflexframegen _q, ofdmflexframegenprops_s * _props); // get length of frame (symbols) // _q : OFDM frame generator object unsigned int ofdmflexframegen_getframelen(ofdmflexframegen _q); // assemble a frame from an array of data (NULL pointers will use random data) // _q : OFDM frame generator object // _header : frame header [8 bytes] // _payload : payload data, [size: _payload_len x 1] // _payload_len : payload data length int ofdmflexframegen_assemble(ofdmflexframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len); // write samples of assembled frame // _q : OFDM frame generator object // _buf : output buffer, [size: _buf_len x 1] // _buf_len : output buffer length int ofdmflexframegen_write(ofdmflexframegen _q, liquid_float_complex * _buf, unsigned int _buf_len); // // OFDM flex frame synchronizer // typedef struct ofdmflexframesync_s * ofdmflexframesync; // create OFDM flexible framing synchronizer object // _M : number of subcarriers // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmflexframesync ofdmflexframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, framesync_callback _callback, void * _userdata); int ofdmflexframesync_destroy(ofdmflexframesync _q); int ofdmflexframesync_print(ofdmflexframesync _q); // set user-defined header length int ofdmflexframesync_set_header_len(ofdmflexframesync _q, unsigned int _len); int ofdmflexframesync_decode_header_soft(ofdmflexframesync _q, int _soft); int ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q, int _soft); int ofdmflexframesync_set_header_props(ofdmflexframesync _q, ofdmflexframegenprops_s * _props); int ofdmflexframesync_reset(ofdmflexframesync _q); // set the callback and userdata fields int ofdmflexframesync_set_callback(ofdmflexframesync _q, framesync_callback _callback); int ofdmflexframesync_set_userdata(ofdmflexframesync _q, void * _userdata); int ofdmflexframesync_is_frame_open(ofdmflexframesync _q); int ofdmflexframesync_execute(ofdmflexframesync _q, liquid_float_complex * _x, unsigned int _n); // query the received signal strength indication float ofdmflexframesync_get_rssi(ofdmflexframesync _q); // query the received carrier offset estimate float ofdmflexframesync_get_cfo(ofdmflexframesync _q); // frame data statistics int ofdmflexframesync_reset_framedatastats(ofdmflexframesync _q); framedatastats_s ofdmflexframesync_get_framedatastats (ofdmflexframesync _q); // set the received carrier offset estimate int ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo); // enable/disable debugging int ofdmflexframesync_debug_enable(ofdmflexframesync _q); int ofdmflexframesync_debug_disable(ofdmflexframesync _q); int ofdmflexframesync_debug_print(ofdmflexframesync _q, const char * _filename); // // Binary P/N synchronizer // #define LIQUID_BSYNC_MANGLE_RRRF(name) LIQUID_CONCAT(bsync_rrrf,name) #define LIQUID_BSYNC_MANGLE_CRCF(name) LIQUID_CONCAT(bsync_crcf,name) #define LIQUID_BSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bsync_cccf,name) // Macro: // BSYNC : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_BSYNC_DEFINE_API(BSYNC,TO,TC,TI) \ \ /* Binary P/N synchronizer */ \ typedef struct BSYNC(_s) * BSYNC(); \ \ /* Create bsync object */ \ /* _n : sequence length */ \ /* _v : correlation sequence, [size: _n x 1] */ \ BSYNC() BSYNC(_create)(unsigned int _n, \ TC * _v); \ \ /* Create binary synchronizer from m-sequence */ \ /* _g : m-sequence generator polynomial */ \ /* _k : samples/symbol (over-sampling factor) */ \ BSYNC() BSYNC(_create_msequence)(unsigned int _g, \ unsigned int _k); \ \ /* Destroy binary synchronizer object, freeing all internal memory */ \ /* _q : bsync object */ \ int BSYNC(_destroy)(BSYNC() _q); \ \ /* Print object internals to stdout */ \ /* _q : bsync object */ \ int BSYNC(_print)(BSYNC() _q); \ \ /* Correlate input signal against internal sequence */ \ /* _q : bsync object */ \ /* _x : input sample */ \ /* _y : pointer to output sample */ \ int BSYNC(_correlate)(BSYNC() _q, \ TI _x, \ TO * _y); \ LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_RRRF, float, float, float) LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_BSYNC_DEFINE_API(LIQUID_BSYNC_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Pre-demodulation synchronizers (binary and otherwise) // #define LIQUID_PRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT( presync_cccf,name) #define LIQUID_BPRESYNC_MANGLE_CCCF(name) LIQUID_CONCAT(bpresync_cccf,name) // Macro: // PRESYNC : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_PRESYNC_DEFINE_API(PRESYNC,TO,TC,TI) \ \ /* Pre-demodulation signal synchronizer */ \ typedef struct PRESYNC(_s) * PRESYNC(); \ \ /* Create pre-demod synchronizer from external sequence */ \ /* _v : baseband sequence, [size: _n x 1] */ \ /* _n : baseband sequence length, _n > 0 */ \ /* _dphi_max : maximum absolute frequency deviation for detection */ \ /* _m : number of correlators, _m > 0 */ \ PRESYNC() PRESYNC(_create)(TC * _v, \ unsigned int _n, \ float _dphi_max, \ unsigned int _m); \ \ /* Destroy pre-demod synchronizer, freeing all internal memory */ \ int PRESYNC(_destroy)(PRESYNC() _q); \ \ /* Print pre-demod synchronizer internal state */ \ int PRESYNC(_print)(PRESYNC() _q); \ \ /* Reset pre-demod synchronizer internal state */ \ int PRESYNC(_reset)(PRESYNC() _q); \ \ /* Push input sample into pre-demod synchronizer */ \ /* _q : pre-demod synchronizer object */ \ /* _x : input sample */ \ int PRESYNC(_push)(PRESYNC() _q, \ TI _x); \ \ /* Correlate original sequence with internal input buffer */ \ /* _q : pre-demod synchronizer object */ \ /* _rxy : output cross correlation */ \ /* _dphi_hat : output frequency offset estimate */ \ int PRESYNC(_execute)(PRESYNC() _q, \ TO * _rxy, \ float * _dphi_hat); \ // non-binary pre-demodulation synchronizer LIQUID_PRESYNC_DEFINE_API(LIQUID_PRESYNC_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // binary pre-demodulation synchronizer LIQUID_PRESYNC_DEFINE_API(LIQUID_BPRESYNC_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Frame detector // #define LIQUID_QDETECTOR_MANGLE_CCCF(name) LIQUID_CONCAT(qdetector_cccf,name) #define LIQUID_QDETECTOR_DEFINE_API(QDETECTOR,TO,TC,TI) \ \ /* Frame detector and synchronizer; uses a novel correlation method to */ \ /* detect a synchronization pattern, estimate carrier frequency and */ \ /* phase offsets as well as timing phase, then correct for these */ \ /* impairments in a simple interface suitable for custom frame recovery.*/ \ typedef struct QDETECTOR(_s) * QDETECTOR(); \ \ /* Create detector with generic sequence */ \ /* _s : sample sequence */ \ /* _s_len : length of sample sequence */ \ QDETECTOR() QDETECTOR(_create)(TI * _s, \ unsigned int _s_len); \ \ /* Create detector from sequence of symbols using internal linear */ \ /* interpolator */ \ /* _sequence : symbol sequence */ \ /* _sequence_len : length of symbol sequence */ \ /* _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : samples/symbol */ \ /* _m : filter delay */ \ /* _beta : excess bandwidth factor */ \ QDETECTOR() QDETECTOR(_create_linear)(TI * _sequence, \ unsigned int _sequence_len, \ int _ftype, \ unsigned int _k, \ unsigned int _m, \ float _beta); \ \ /* create detector from sequence of GMSK symbols */ \ /* _sequence : bit sequence */ \ /* _sequence_len : length of bit sequence */ \ /* _k : samples/symbol */ \ /* _m : filter delay */ \ /* _beta : excess bandwidth factor */ \ QDETECTOR() QDETECTOR(_create_gmsk)(unsigned char * _sequence, \ unsigned int _sequence_len, \ unsigned int _k, \ unsigned int _m, \ float _beta); \ \ /* create detector from sequence of CP-FSK symbols (assuming one */ \ /* bit/symbol) */ \ /* _sequence : bit sequence */ \ /* _sequence_len : length of bit sequence */ \ /* _bps : bits per symbol, 0 < _bps <= 8 */ \ /* _h : modulation index, _h > 0 */ \ /* _k : samples/symbol */ \ /* _m : filter delay */ \ /* _beta : filter bandwidth parameter, _beta > 0 */ \ /* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ QDETECTOR() QDETECTOR(_create_cpfsk)(unsigned char * _sequence, \ unsigned int _sequence_len, \ unsigned int _bps, \ float _h, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ int _type); \ \ /* Copy object including all internal objects and state */ \ QDETECTOR() QDETECTOR(_copy)(QDETECTOR() _q); \ \ /* Destroy synchronizer object and free all internal memory */ \ int QDETECTOR(_destroy)(QDETECTOR() _q); \ \ /* Reset synchronizer object's internal buffer */ \ int QDETECTOR(_reset)(QDETECTOR() _q); \ \ /* Print synchronizer object information to stdout */ \ int QDETECTOR(_print)(QDETECTOR() _q); \ \ /* run detector, looking for sequence; return pointer to aligned, */ \ /* buffered samples */ \ void * QDETECTOR(_execute)(QDETECTOR() _q, TI _x); \ \ /* get detection threshold */ \ float QDETECTOR(_get_threshold)(QDETECTOR() _q); \ \ /* Set detection threshold (should be between 0 and 1, good starting */ \ /* point is 0.5) */ \ int QDETECTOR(_set_threshold)(QDETECTOR() _q, \ float _threshold); \ \ /* Get carrier offset search range */ \ float QDETECTOR(_get_range)(QDETECTOR() _q); \ \ /* Set carrier offset search range */ \ int QDETECTOR(_set_range)(QDETECTOR() _q, \ float _dphi_max); \ \ /* Get sequence length */ \ unsigned int QDETECTOR(_get_seq_len)(QDETECTOR() _q); \ \ /* Get pointer to original sequence */ \ const void * QDETECTOR(_get_sequence)(QDETECTOR() _q); \ \ /* Get buffer length */ \ unsigned int QDETECTOR(_get_buf_len)(QDETECTOR() _q); \ \ /* Get correlator output of detected frame */ \ float QDETECTOR(_get_rxy)(QDETECTOR() _q); \ \ /* Get fractional timing offset estimate of detected frame */ \ float QDETECTOR(_get_tau)(QDETECTOR() _q); \ \ /* Get channel gain of detected frame */ \ float QDETECTOR(_get_gamma)(QDETECTOR() _q); \ \ /* Get carrier frequency offset estimateof detected frame */ \ float QDETECTOR(_get_dphi)(QDETECTOR() _q); \ \ /* Get carrier phase offset estimate of detected frame */ \ float QDETECTOR(_get_phi)(QDETECTOR() _q); \ LIQUID_QDETECTOR_DEFINE_API(LIQUID_QDETECTOR_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // metadata struct: // - sample count since object was created // - sample count since beginning of frame // // qdsync // #define LIQUID_QDSYNC_MANGLE_CCCF(name) LIQUID_CONCAT(qdsync_cccf,name) #define LIQUID_QDSYNC_DEFINE_API(QDSYNC,TO,TC,TI) \ \ /* Frame detector and synchronizer; uses a novel correlation method to */ \ /* detect a synchronization pattern, estimate carrier frequency and */ \ /* phase offsets as well as timing phase, then correct for these */ \ /* impairments in a simple interface suitable for custom frame recovery.*/ \ typedef struct QDSYNC(_s) * QDSYNC(); \ \ /* synchronization callback, return 0:continue, 1:reset */ \ typedef int (*QDSYNC(_callback))(TO * _buf, \ unsigned int _buf_len, \ void * _context); \ \ /* create detector with generic sequence */ \ /* _s : sample sequence */ \ /* _s_len : length of sample sequence */ \ /* _ftype : filter type */ \ /* _k : samples per symbol */ \ /* _m : filter semi-length */ \ /* _beta : filter excess bandwidth factor */ \ /* _callback : user-defined callback */ \ /* _context : user-defined context */ \ QDSYNC() QDSYNC(_create_linear)(TI * _s, \ unsigned int _s_len, \ int _ftype, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ QDSYNC(_callback) _callback, \ void * _context); \ \ /* Copy object recursively including all internal objects and state */ \ QDSYNC() QDSYNC(_copy)(QDSYNC() _q); \ \ /* Destroy synchronizer object and free all internal memory */ \ int QDSYNC(_destroy)(QDSYNC() _q); \ \ /* Reset synchronizer object's internal buffer */ \ int QDSYNC(_reset)(QDSYNC() _q); \ \ /* Print synchronizer object information to stdout */ \ int QDSYNC(_print)(QDSYNC() _q); \ \ /* Get detection state */ \ int QDSYNC(_is_detected)(QDSYNC() _q); \ \ /* Get detection threshold */ \ float QDSYNC(_get_threshold)(QDSYNC() _q); \ \ /* Set detection threshold */ \ int QDSYNC(_set_threshold)(QDSYNC() _q, \ float _threshold); \ \ /* Get carrier offset search range */ \ float QDSYNC(_get_range)(QDSYNC() _q); \ \ /* Set carrier offset search range */ \ int QDSYNC(_set_range)(QDSYNC() _q, \ float _dphi_max); \ \ /* Set callback method */ \ int QDSYNC(_set_callback)(QDSYNC() _q, \ QDSYNC(_callback) _callback); \ \ /* Set context value */ \ int QDSYNC(_set_context)(QDSYNC() _q, void * _context); \ \ /* Set callback buffer size (the number of symbol provided to the */ \ /* callback whenever it is invoked). */ \ int QDSYNC(_set_buf_len)(QDSYNC() _q, unsigned int _buf_len); \ \ /* execute block of samples */ \ int QDSYNC(_execute)(QDSYNC() _q, \ TI * _buf, \ unsigned int _buf_len); \ \ /* Return flag indicating if synchronizer actively running. */ \ int QDSYNC(_is_open)(QDSYNC() _q); \ \ /* Get synchronizer correlator output after frame was detected */ \ float QDSYNC(_get_rxy) (QDSYNC() _q); \ \ /* Get synchronizer fractional timing offset after frame was detected */ \ float QDSYNC(_get_tau) (QDSYNC() _q); \ \ /* Get synchronizer channel gain after frame was detected */ \ float QDSYNC(_get_gamma)(QDSYNC() _q); \ \ /* Get synchronizer frequency offset estimate after frame was detected */ \ float QDSYNC(_get_dphi) (QDSYNC() _q); \ \ /* Get synchronizer phase offset estimate after frame was detected */ \ float QDSYNC(_get_phi) (QDSYNC() _q); \ LIQUID_QDSYNC_DEFINE_API(LIQUID_QDSYNC_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Pre-demodulation detector // typedef struct detector_cccf_s * detector_cccf; // create pre-demod detector // _s : sequence // _n : sequence length // _threshold : detection threshold (default: 0.7) // _dphi_max : maximum carrier offset detector_cccf detector_cccf_create(liquid_float_complex * _s, unsigned int _n, float _threshold, float _dphi_max); // destroy pre-demo detector object void detector_cccf_destroy(detector_cccf _q); // print pre-demod detector internal state void detector_cccf_print(detector_cccf _q); // reset pre-demod detector internal state void detector_cccf_reset(detector_cccf _q); // Run sample through pre-demod detector's correlator. // Returns '1' if signal was detected, '0' otherwise // _q : pre-demod detector // _x : input sample // _tau_hat : fractional sample offset estimate (set when detected) // _dphi_hat : carrier frequency offset estimate (set when detected) // _gamma_hat : channel gain estimate (set when detected) int detector_cccf_correlate(detector_cccf _q, liquid_float_complex _x, float * _tau_hat, float * _dphi_hat, float * _gamma_hat); // // symbol streaming for testing (no meaningful data, just symbols) // #define LIQUID_SYMSTREAM_MANGLE_CFLOAT(name) LIQUID_CONCAT(symstreamcf,name) #define LIQUID_SYMSTREAM_DEFINE_API(SYMSTREAM,TO) \ \ /* Symbol streaming generator object */ \ typedef struct SYMSTREAM(_s) * SYMSTREAM(); \ \ /* Create symstream object with default parameters. */ \ /* This is equivalent to invoking the create_linear() method */ \ /* with _ftype=LIQUID_FIRFILT_ARKAISER, _k=2, _m=7, _beta=0.3, and */ \ /* with _ms=LIQUID_MODEM_QPSK */ \ SYMSTREAM() SYMSTREAM(_create)(void); \ \ /* Create symstream object with linear modulation */ \ /* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : samples per symbol, _k >= 2 */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ /* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ SYMSTREAM() SYMSTREAM(_create_linear)(int _ftype, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ int _ms); \ \ /* Copy object recursively including all internal objects and state */ \ SYMSTREAM() SYMSTREAM(_copy)(SYMSTREAM() _q); \ \ /* Destroy symstream object, freeing all internal memory */ \ int SYMSTREAM(_destroy)(SYMSTREAM() _q); \ \ /* Print symstream object's parameters */ \ int SYMSTREAM(_print)(SYMSTREAM() _q); \ \ /* Reset symstream internal state */ \ int SYMSTREAM(_reset)(SYMSTREAM() _q); \ \ /* Set internal linear modulation scheme, leaving the filter parameters */ \ /* (interpolator) unmodified */ \ int SYMSTREAM(_set_scheme)(SYMSTREAM() _q, \ int _ms); \ \ /* Get internal filter type */ \ int SYMSTREAM(_get_ftype)(SYMSTREAM() _q); \ \ /* Get internal samples per symbol */ \ float SYMSTREAM(_get_k)(SYMSTREAM() _q); \ \ /* Get internal filter semi-length */ \ unsigned int SYMSTREAM(_get_m)(SYMSTREAM() _q); \ \ /* Get internal filter excess bandwidth factor */ \ float SYMSTREAM(_get_beta)(SYMSTREAM() _q); \ \ /* Get internal linear modulation scheme */ \ int SYMSTREAM(_get_scheme)(SYMSTREAM() _q); \ \ /* Set internal linear gain (before interpolation) */ \ int SYMSTREAM(_set_gain)(SYMSTREAM() _q, \ float _gain); \ \ /* Get internal linear gain (before interpolation) */ \ float SYMSTREAM(_get_gain)(SYMSTREAM() _q); \ \ /* Get delay in samples */ \ unsigned int SYMSTREAM(_get_delay)(SYMSTREAM() _q); \ \ /* Write block of samples to output buffer */ \ /* _q : synchronizer object */ \ /* _buf : output buffer, [size: _buf_len x 1] */ \ /* _buf_len: output buffer size */ \ int SYMSTREAM(_write_samples)(SYMSTREAM() _q, \ TO * _buf, \ unsigned int _buf_len); \ LIQUID_SYMSTREAM_DEFINE_API(LIQUID_SYMSTREAM_MANGLE_CFLOAT, liquid_float_complex) // // symbol streaming, as with symstream but arbitrary output rate // #define LIQUID_SYMSTREAMR_MANGLE_CFLOAT(name) LIQUID_CONCAT(symstreamrcf,name) #define LIQUID_SYMSTREAMR_DEFINE_API(SYMSTREAMR,TO) \ \ /* Symbol streaming generator object */ \ typedef struct SYMSTREAMR(_s) * SYMSTREAMR(); \ \ /* Create symstream object with default parameters. */ \ /* This is equivalent to invoking the create_linear() method */ \ /* with _ftype=LIQUID_FIRFILT_ARKAISER, _k=2, _m=7, _beta=0.3, and */ \ /* with _ms=LIQUID_MODEM_QPSK */ \ SYMSTREAMR() SYMSTREAMR(_create)(void); \ \ /* Create symstream object with linear modulation */ \ /* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _bw : relative signal bandwidth, 0.001 <= _bw <= 1.0 */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ /* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ SYMSTREAMR() SYMSTREAMR(_create_linear)(int _ftype, \ float _bw, \ unsigned int _m, \ float _beta, \ int _ms); \ \ /* Copy object recursively including all internal objects and state */ \ SYMSTREAMR() SYMSTREAMR(_copy)(SYMSTREAMR() _q); \ \ /* Destroy symstream object, freeing all internal memory */ \ int SYMSTREAMR(_destroy)(SYMSTREAMR() _q); \ \ /* Print symstream object's parameters */ \ int SYMSTREAMR(_print)(SYMSTREAMR() _q); \ \ /* Reset symstream internal state */ \ int SYMSTREAMR(_reset)(SYMSTREAMR() _q); \ \ /* Get internal filter type */ \ int SYMSTREAMR(_get_ftype)(SYMSTREAMR() _q); \ \ /* Get internal signal bandwidth (symbol rate) */ \ float SYMSTREAMR(_get_bw)(SYMSTREAMR() _q); \ \ /* Get internal filter semi-length */ \ unsigned int SYMSTREAMR(_get_m)(SYMSTREAMR() _q); \ \ /* Get internal filter excess bandwidth factor */ \ float SYMSTREAMR(_get_beta)(SYMSTREAMR() _q); \ \ /* Set internal linear modulation scheme, leaving the filter parameters */ \ /* (interpolator) unmodified */ \ int SYMSTREAMR(_set_scheme)(SYMSTREAMR() _q, \ int _ms); \ \ /* Get internal linear modulation scheme */ \ int SYMSTREAMR(_get_scheme)(SYMSTREAMR() _q); \ \ /* Set internal linear gain (before interpolation) */ \ int SYMSTREAMR(_set_gain)(SYMSTREAMR() _q, \ float _gain); \ \ /* Get internal linear gain (before interpolation) */ \ float SYMSTREAMR(_get_gain)(SYMSTREAMR() _q); \ \ /* Get delay in samples */ \ float SYMSTREAMR(_get_delay)(SYMSTREAMR() _q); \ \ /* Write block of samples to output buffer */ \ /* _q : synchronizer object */ \ /* _buf : output buffer, [size: _buf_len x 1] */ \ /* _buf_len: output buffer size */ \ int SYMSTREAMR(_write_samples)(SYMSTREAMR() _q, \ TO * _buf, \ unsigned int _buf_len); \ LIQUID_SYMSTREAMR_DEFINE_API(LIQUID_SYMSTREAMR_MANGLE_CFLOAT, liquid_float_complex) // // multi-signal source for testing (no meaningful data, just signals) // #define LIQUID_MSOURCE_MANGLE_CFLOAT(name) LIQUID_CONCAT(msourcecf,name) #define LIQUID_MSOURCE_DEFINE_API(MSOURCE,TO) \ \ /* Multi-signal source generator object */ \ typedef struct MSOURCE(_s) * MSOURCE(); \ \ /* Create msource object by specifying channelizer parameters */ \ /* _M : number of channels in analysis channelizer object */ \ /* _m : prototype channelizer filter semi-length */ \ /* _as : prototype channelizer filter stop-band suppression (dB) */ \ MSOURCE() MSOURCE(_create)(unsigned int _M, \ unsigned int _m, \ float _as); \ \ /* Copy object recursively, including all internal objects and state */ \ MSOURCE() MSOURCE(_copy)(MSOURCE() _q); \ \ /* Create default msource object with default parameters: */ \ /* M = 1200, m = 4, as = 60 */ \ MSOURCE() MSOURCE(_create_default)(void); \ \ /* Destroy msource object */ \ int MSOURCE(_destroy)(MSOURCE() _q); \ \ /* Print msource object */ \ int MSOURCE(_print)(MSOURCE() _q); \ \ /* Reset msource object */ \ int MSOURCE(_reset)(MSOURCE() _q); \ \ /* user-defined callback for generating samples */ \ typedef int (*MSOURCE(_callback))(void * _userdata, \ TO * _v, \ unsigned int _n); \ \ /* Add user-defined signal generator */ \ int MSOURCE(_add_user)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain, \ void * _userdata, \ MSOURCE(_callback) _callback); \ \ /* Add tone to signal generator, returning id of signal */ \ int MSOURCE(_add_tone)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain); \ \ /* Add chirp to signal generator, returning id of signal */ \ /* _q : multi-signal source object */ \ /* _duration : duration of chirp [samples] */ \ /* _negate : negate frequency direction */ \ /* _single : run single chirp? or repeatedly */ \ int MSOURCE(_add_chirp)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain, \ float _duration, \ int _negate, \ int _repeat); \ \ /* Add noise source to signal generator, returning id of signal */ \ /* _q : multi-signal source object */ \ /* _fc : ... */ \ /* _bw : ... */ \ /* _nstd : ... */ \ int MSOURCE(_add_noise)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain); \ \ /* Add modem signal source, returning id of signal */ \ /* _q : multi-signal source object */ \ /* _ms : modulation scheme, e.g. LIQUID_MODEM_QPSK */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : filter excess bandwidth, 0 < _beta <= 1 */ \ int MSOURCE(_add_modem)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain, \ int _ms, \ unsigned int _m, \ float _beta); \ \ /* Add frequency-shift keying modem signal source, returning id of */ \ /* signal */ \ /* _q : multi-signal source object */ \ /* _m : bits per symbol, _bps > 0 */ \ /* _k : samples/symbol, _k >= 2^_m */ \ int MSOURCE(_add_fsk)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain, \ unsigned int _m, \ unsigned int _k); \ \ /* Add GMSK modem signal source, returning id of signal */ \ /* _q : multi-signal source object */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _bt : filter bandwidth-time factor, 0 < _bt <= 1 */ \ int MSOURCE(_add_gmsk)(MSOURCE() _q, \ float _fc, \ float _bw, \ float _gain, \ unsigned int _m, \ float _bt); \ \ /* Remove signal with a particular id, returning 0 upon success */ \ /* _q : multi-signal source object */ \ /* _id : signal source id */ \ int MSOURCE(_remove)(MSOURCE() _q, \ int _id); \ \ /* Enable signal source with a particular id */ \ int MSOURCE(_enable)(MSOURCE() _q, \ int _id); \ \ /* Disable signal source with a particular id */ \ int MSOURCE(_disable)(MSOURCE() _q, \ int _id); \ \ /* Get number of samples generated by the object so far */ \ /* _q : msource object */ \ /* _return : number of time-domain samples generated */ \ unsigned long long int MSOURCE(_get_num_samples)(MSOURCE() _q); \ \ /* Get number of samples generated by specific source so far */ \ /* _q : msource object */ \ /* _id : source id */ \ /* _num_samples : pointer to number of samples generated */ \ int MSOURCE(_get_num_samples_source)(MSOURCE() _q, \ int _id, \ unsigned long int * _num_samples); \ \ /* Set gain in decibels on signal */ \ /* _q : msource object */ \ /* _id : source id */ \ /* _gain : signal gain [dB] */ \ int MSOURCE(_set_gain)(MSOURCE() _q, \ int _id, \ float _gain); \ \ /* Get gain in decibels on signal */ \ /* _q : msource object */ \ /* _id : source id */ \ /* _gain : signal gain output [dB] */ \ int MSOURCE(_get_gain)(MSOURCE() _q, \ int _id, \ float * _gain); \ \ /* Set carrier offset to signal */ \ /* _q : msource object */ \ /* _id : source id */ \ /* _fc : normalized carrier frequency offset, -0.5 <= _fc <= 0.5 */ \ int MSOURCE(_set_frequency)(MSOURCE() _q, \ int _id, \ float _dphi); \ \ /* Get carrier offset to signal */ \ /* _q : msource object */ \ /* _id : source id */ \ /* _fc : normalized carrier frequency offset */ \ int MSOURCE(_get_frequency)(MSOURCE() _q, \ int _id, \ float * _dphi); \ \ /* Write block of samples to output buffer */ \ /* _q : synchronizer object */ \ /* _buf : output buffer, [size: _buf_len x 1] */ \ /* _buf_len: output buffer size */ \ int MSOURCE(_write_samples)(MSOURCE() _q, \ TO * _buf, \ unsigned int _buf_len); \ LIQUID_MSOURCE_DEFINE_API(LIQUID_MSOURCE_MANGLE_CFLOAT, liquid_float_complex) // // Symbol tracking: AGC > symsync > EQ > carrier recovery // #define LIQUID_SYMTRACK_MANGLE_RRRF(name) LIQUID_CONCAT(symtrack_rrrf,name) #define LIQUID_SYMTRACK_MANGLE_CCCF(name) LIQUID_CONCAT(symtrack_cccf,name) // large macro // SYMTRACK : name-mangling macro // T : data type, primitive // TO : data type, output // TC : data type, coefficients // TI : data type, input #define LIQUID_SYMTRACK_DEFINE_API(SYMTRACK,T,TO,TC,TI) \ \ /* Symbol synchronizer and tracking object */ \ typedef struct SYMTRACK(_s) * SYMTRACK(); \ \ /* Create symtrack object, specifying parameters for operation */ \ /* _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) */ \ /* _k : samples per symbol, _k >= 2 */ \ /* _m : filter delay [symbols], _m > 0 */ \ /* _beta : excess bandwidth factor, 0 <= _beta <= 1 */ \ /* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ SYMTRACK() SYMTRACK(_create)(int _ftype, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ int _ms); \ \ /* Create symtrack object using default parameters. */ \ /* The default parameters are */ \ /* ftype = LIQUID_FIRFILT_ARKAISER (filter type), */ \ /* k = 2 (samples per symbol), */ \ /* m = 7 (filter delay), */ \ /* beta = 0.3 (excess bandwidth factor), and */ \ /* ms = LIQUID_MODEM_QPSK (modulation scheme) */ \ SYMTRACK() SYMTRACK(_create_default)(); \ \ /* Destroy symtrack object, freeing all internal memory */ \ int SYMTRACK(_destroy)(SYMTRACK() _q); \ \ /* Print symtrack object's parameters */ \ int SYMTRACK(_print)(SYMTRACK() _q); \ \ /* Reset symtrack internal state */ \ int SYMTRACK(_reset)(SYMTRACK() _q); \ \ /* Get symtrack filter type */ \ int SYMTRACK(_get_ftype)(SYMTRACK() _q); \ \ /* Get symtrack samples per symbol */ \ unsigned int SYMTRACK(_get_k)(SYMTRACK() _q); \ \ /* Get symtrack filter semi-length [symbols] */ \ unsigned int SYMTRACK(_get_m)(SYMTRACK() _q); \ \ /* Get symtrack filter excess bandwidth factor */ \ float SYMTRACK(_get_beta)(SYMTRACK() _q); \ \ /* Get symtrack modulation scheme */ \ int SYMTRACK(_get_modscheme)(SYMTRACK() _q); \ \ /* Set symtrack modulation scheme */ \ /* _q : symtrack object */ \ /* _ms : modulation scheme, _ms(LIQUID_MODEM_BPSK) */ \ int SYMTRACK(_set_modscheme)(SYMTRACK() _q, \ int _ms); \ \ /* Get symtrack internal bandwidth */ \ float SYMTRACK(_get_bandwidth)(SYMTRACK() _q); \ \ /* Set symtrack internal bandwidth */ \ /* _q : symtrack object */ \ /* _bw : tracking bandwidth, _bw > 0 */ \ int SYMTRACK(_set_bandwidth)(SYMTRACK() _q, \ float _bw); \ \ /* Adjust internal NCO by requested frequency */ \ /* _q : symtrack object */ \ /* _dphi : NCO frequency adjustment [radians/sample] */ \ int SYMTRACK(_adjust_frequency)(SYMTRACK() _q, \ T _dphi); \ \ /* Adjust internal NCO by requested phase */ \ /* _q : symtrack object */ \ /* _phi : NCO phase adjustment [radians] */ \ int SYMTRACK(_adjust_phase)(SYMTRACK() _q, \ T _phi); \ \ /* Set symtrack equalization strategy to constant modulus (default) */ \ int SYMTRACK(_set_eq_cm)(SYMTRACK() _q); \ \ /* Set symtrack equalization strategy to decision directed */ \ int SYMTRACK(_set_eq_dd)(SYMTRACK() _q); \ \ /* Disable symtrack equalization */ \ int SYMTRACK(_set_eq_off)(SYMTRACK() _q); \ \ /* Execute synchronizer on single input sample */ \ /* _q : synchronizer object */ \ /* _x : input data sample */ \ /* _y : output data array, [size: 2 x 1] */ \ /* _ny : number of samples written to output buffer (0, 1, or 2) */ \ int SYMTRACK(_execute)(SYMTRACK() _q, \ TI _x, \ TO * _y, \ unsigned int * _ny); \ \ /* execute synchronizer on input data array */ \ /* _q : synchronizer object */ \ /* _x : input data array */ \ /* _nx : number of input samples */ \ /* _y : output data array, [size: 2 _nx x 1] */ \ /* _ny : number of samples written to output buffer */ \ int SYMTRACK(_execute_block)(SYMTRACK() _q, \ TI * _x, \ unsigned int _nx, \ TO * _y, \ unsigned int * _ny); \ LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_RRRF, float, float, float, float) LIQUID_SYMTRACK_DEFINE_API(LIQUID_SYMTRACK_MANGLE_CCCF, float, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // MODULE : math // // ln( Gamma(z) ) float liquid_lngammaf(float _z); // Gamma(z) float liquid_gammaf(float _z); // ln( gamma(z,alpha) ) : lower incomplete gamma function float liquid_lnlowergammaf(float _z, float _alpha); // ln( Gamma(z,alpha) ) : upper incomplete gamma function float liquid_lnuppergammaf(float _z, float _alpha); // gamma(z,alpha) : lower incomplete gamma function float liquid_lowergammaf(float _z, float _alpha); // Gamma(z,alpha) : upper incomplete gamma function float liquid_uppergammaf(float _z, float _alpha); // n! float liquid_factorialf(unsigned int _n); // ln(I_v(z)) : log Modified Bessel function of the first kind float liquid_lnbesselif(float _nu, float _z); // I_v(z) : Modified Bessel function of the first kind float liquid_besselif(float _nu, float _z); // I_0(z) : Modified Bessel function of the first kind (order zero) float liquid_besseli0f(float _z); // J_v(z) : Bessel function of the first kind float liquid_besseljf(float _nu, float _z); // J_0(z) : Bessel function of the first kind (order zero) float liquid_besselj0f(float _z); // Q function float liquid_Qf(float _z); // Marcum Q-function float liquid_MarcumQf(int _M, float _alpha, float _beta); // Marcum Q-function (M=1) float liquid_MarcumQ1f(float _alpha, float _beta); // sin(pi x) / (pi x) float sincf(float _x); // next power of 2 : y = ceil(log2(_x)) unsigned int liquid_nextpow2(unsigned int _x); // (n choose k) = n! / ( k! (n-k)! ) float liquid_nchoosek(unsigned int _n, unsigned int _k); // // Windowing functions // // number of window functions available, including "unknown" type #define LIQUID_WINDOW_NUM_FUNCTIONS (10) // prototypes typedef enum { LIQUID_WINDOW_UNKNOWN=0, // unknown/unsupported scheme LIQUID_WINDOW_HAMMING, // Hamming LIQUID_WINDOW_HANN, // Hann LIQUID_WINDOW_BLACKMANHARRIS, // Blackman-harris (4-term) LIQUID_WINDOW_BLACKMANHARRIS7, // Blackman-harris (7-term) LIQUID_WINDOW_KAISER, // Kaiser (beta factor unspecified) LIQUID_WINDOW_FLATTOP, // flat top (includes negative values) LIQUID_WINDOW_TRIANGULAR, // triangular LIQUID_WINDOW_RCOSTAPER, // raised-cosine taper (taper size unspecified) LIQUID_WINDOW_KBD, // Kaiser-Bessel derived window (beta factor unspecified) } liquid_window_type; // pretty names for window extern const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2]; // Print compact list of existing and available windowing functions int liquid_print_windows(); // returns window type based on input string liquid_window_type liquid_getopt_str2window(const char * _str); // generic window function given type // _type : window type, e.g. LIQUID_WINDOW_KAISER // _i : window index, _i in [0,_wlen-1] // _wlen : length of window // _arg : window-specific argument, if required float liquid_windowf(liquid_window_type _type, unsigned int _i, unsigned int _wlen, float _arg); // Kaiser window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length // _beta : Kaiser-Bessel window shape parameter float liquid_kaiser(unsigned int _i, unsigned int _wlen, float _beta); // Hamming window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length float liquid_hamming(unsigned int _i, unsigned int _wlen); // Hann window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length float liquid_hann(unsigned int _i, unsigned int _wlen); // Blackman-harris window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length float liquid_blackmanharris(unsigned int _i, unsigned int _wlen); // 7th order Blackman-harris window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length float liquid_blackmanharris7(unsigned int _i, unsigned int _wlen); // Flat-top window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length float liquid_flattop(unsigned int _i, unsigned int _wlen); // Triangular window // _i : window index, _i in [0,_wlen-1] // _wlen : full window length // _n : triangle length, _n in {_wlen-1, _wlen, _wlen+1} float liquid_triangular(unsigned int _i, unsigned int _wlen, unsigned int _n); // raised-cosine tapering window // _i : window index // _wlen : full window length // _t : taper length, _t in [0,_wlen/2] float liquid_rcostaper_window(unsigned int _i, unsigned int _wlen, unsigned int _t); // Kaiser-Bessel derived window (single sample) // _i : window index, _i in [0,_wlen-1] // _wlen : length of filter (must be even) // _beta : Kaiser window parameter (_beta > 0) float liquid_kbd(unsigned int _i, unsigned int _wlen, float _beta); // Kaiser-Bessel derived window (full window) // _wlen : full window length (must be even) // _beta : Kaiser window parameter (_beta > 0) // _w : window output buffer, [size: _wlen x 1] int liquid_kbd_window(unsigned int _wlen, float _beta, float * _w); // shim to support legacy APIs (backwards compatible with 1.3.2) float kaiser(unsigned int _i,unsigned int _wlen, float _beta, float _dt); float hamming(unsigned int _i,unsigned int _wlen); float hann(unsigned int _i,unsigned int _wlen); float blackmanharris(unsigned int _i,unsigned int _wlen); float blackmanharris7(unsigned int _i,unsigned int _wlen); float flattop(unsigned int _i,unsigned int _wlen); float triangular(unsigned int _i,unsigned int _wlen,unsigned int _n); float liquid_rcostaper_windowf(unsigned int _i,unsigned int _wlen,unsigned int _t); float kbd(unsigned int _i,unsigned int _wlen,float _beta); int kbd_window(unsigned int _wlen,float _beta,float * _w); // polynomials #define LIQUID_POLY_MANGLE_DOUBLE(name) LIQUID_CONCAT(poly, name) #define LIQUID_POLY_MANGLE_FLOAT(name) LIQUID_CONCAT(polyf, name) #define LIQUID_POLY_MANGLE_CDOUBLE(name) LIQUID_CONCAT(polyc, name) #define LIQUID_POLY_MANGLE_CFLOAT(name) LIQUID_CONCAT(polycf, name) // large macro // POLY : name-mangling macro // T : data type // TC : data type (complex) #define LIQUID_POLY_DEFINE_API(POLY,T,TC) \ \ /* Evaluate polynomial _p at value _x */ \ /* _p : polynomial coefficients, [size: _k x 1] */ \ /* _k : polynomial coefficients length, order is _k - 1 */ \ /* _x : input to evaluate polynomial */ \ T POLY(_val)(T * _p, \ unsigned int _k, \ T _x); \ \ /* Perform least-squares polynomial fit on data set */ \ /* _x : x-value sample set, [size: _n x 1] */ \ /* _y : y-value sample set, [size: _n x 1] */ \ /* _n : number of samples in _x and _y */ \ /* _p : polynomial coefficients output, [size: _k x 1] */ \ /* _k : polynomial coefficients length, order is _k - 1 */ \ int POLY(_fit)(T * _x, \ T * _y, \ unsigned int _n, \ T * _p, \ unsigned int _k); \ \ /* Perform Lagrange polynomial exact fit on data set */ \ /* _x : x-value sample set, size [_n x 1] */ \ /* _y : y-value sample set, size [_n x 1] */ \ /* _n : number of samples in _x and _y */ \ /* _p : polynomial coefficients output, [size: _n x 1] */ \ int POLY(_fit_lagrange)(T * _x, \ T * _y, \ unsigned int _n, \ T * _p); \ \ /* Perform Lagrange polynomial interpolation on data set without */ \ /* computing coefficients as an intermediate step. */ \ /* _x : x-value sample set, [size: _n x 1] */ \ /* _y : y-value sample set, [size: _n x 1] */ \ /* _n : number of samples in _x and _y */ \ /* _x0 : x-value to evaluate and compute interpolant */ \ T POLY(_interp_lagrange)(T * _x, \ T * _y, \ unsigned int _n, \ T _x0); \ \ /* Compute Lagrange polynomial fit in the barycentric form. */ \ /* _x : x-value sample set, size [_n x 1] */ \ /* _n : number of samples in _x */ \ /* _w : barycentric weights normalized so _w[0]=1, size [_n x 1] */ \ int POLY(_fit_lagrange_barycentric)(T * _x, \ unsigned int _n, \ T * _w); \ \ /* Perform Lagrange polynomial interpolation using the barycentric form */ \ /* of the weights. */ \ /* _x : x-value sample set, [size: _n x 1] */ \ /* _y : y-value sample set, [size: _n x 1] */ \ /* _w : barycentric weights, [size: _n x 1] */ \ /* _x0 : x-value to evaluate and compute interpolant */ \ /* _n : number of samples in _x, _y, and _w */ \ T POLY(_val_lagrange_barycentric)(T * _x, \ T * _y, \ T * _w, \ T _x0, \ unsigned int _n); \ \ /* Perform binomial expansion on the polynomial */ \ /* \( P_n(x) = (1+x)^n \) */ \ /* as */ \ /* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ /* NOTE: _p has order n (coefficients has length n+1) */ \ /* _n : polynomial order */ \ /* _p : polynomial coefficients, [size: _n+1 x 1] */ \ int POLY(_expandbinomial)(unsigned int _n, \ T * _p); \ \ /* Perform positive/negative binomial expansion on the polynomial */ \ /* \( P_n(x) = (1+x)^m (1-x)^k \) */ \ /* as */ \ /* \( P_n(x) = p[0] + p[1]x + p[2]x^2 + ... + p[n]x^n \) */ \ /* NOTE: _p has order n=m+k (array is length n+1) */ \ /* _m : number of '1+x' terms */ \ /* _k : number of '1-x' terms */ \ /* _p : polynomial coefficients, [size: _m+_k+1 x 1] */ \ int POLY(_expandbinomial_pm)(unsigned int _m, \ unsigned int _k, \ T * _p); \ \ /* Perform root expansion on the polynomial */ \ /* \( P_n(x) = (x-r[0]) (x-r[1]) ... (x-r[n-1]) \) */ \ /* as */ \ /* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ /* where \( r[0],r[1],...,r[n-1]\) are the roots of \( P_n(x) \). */ \ /* NOTE: _p has order _n (array is length _n+1) */ \ /* _r : roots of polynomial, [size: _n x 1] */ \ /* _n : number of roots in polynomial */ \ /* _p : polynomial coefficients, [size: _n+1 x 1] */ \ int POLY(_expandroots)(T * _r, \ unsigned int _n, \ T * _p); \ \ /* Perform root expansion on the polynomial */ \ /* \( P_n(x) = (xb[0]-a[0]) (xb[1]-a[1])...(xb[n-1]-a[n-1]) \) */ \ /* as */ \ /* \( P_n(x) = p[0] + p[1]x + ... + p[n]x^n \) */ \ /* NOTE: _p has order _n (array is length _n+1) */ \ /* _a : subtractant of polynomial rotos, [size: _n x 1] */ \ /* _b : multiplicant of polynomial roots, [size: _n x 1] */ \ /* _n : number of roots in polynomial */ \ /* _p : polynomial coefficients, [size: _n+1 x 1] */ \ int POLY(_expandroots2)(T * _a, \ T * _b, \ unsigned int _n, \ T * _p); \ \ /* Find the complex roots of a polynomial. */ \ /* _p : polynomial coefficients, [size: _n x 1] */ \ /* _k : polynomial length */ \ /* _roots : resulting complex roots, [size: _k-1 x 1] */ \ int POLY(_findroots)(T * _poly, \ unsigned int _n, \ TC * _roots); \ \ /* Find the complex roots of the polynomial using the Durand-Kerner */ \ /* method */ \ /* _p : polynomial coefficients, [size: _n x 1] */ \ /* _k : polynomial length */ \ /* _roots : resulting complex roots, [size: _k-1 x 1] */ \ int POLY(_findroots_durandkerner)(T * _p, \ unsigned int _k, \ TC * _roots); \ \ /* Find the complex roots of the polynomial using Bairstow's method. */ \ /* _p : polynomial coefficients, [size: _n x 1] */ \ /* _k : polynomial length */ \ /* _roots : resulting complex roots, [size: _k-1 x 1] */ \ int POLY(_findroots_bairstow)(T * _p, \ unsigned int _k, \ TC * _roots); \ \ /* Expand the multiplication of two polynomials */ \ /* \( ( a[0] + a[1]x + a[2]x^2 + ...) (b[0] + b[1]x + b[]x^2 + ...) \) */ \ /* as */ \ /* \( c[0] + c[1]x + c[2]x^2 + ... + c[n]x^n \) */ \ /* where order(c) = order(a) + order(b) + 1 */ \ /* and therefore length(c) = length(a) + length(b) - 1 */ \ /* _a : 1st polynomial coefficients (length is _order_a+1) */ \ /* _order_a : 1st polynomial order */ \ /* _b : 2nd polynomial coefficients (length is _order_b+1) */ \ /* _order_b : 2nd polynomial order */ \ /* _c : output polynomial, [size: _order_a+_order_b+1 x 1] */ \ int POLY(_mul)(T * _a, \ unsigned int _order_a, \ T * _b, \ unsigned int _order_b, \ T * _c); \ LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_DOUBLE, double, liquid_double_complex) LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_FLOAT, float, liquid_float_complex) LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CDOUBLE, liquid_double_complex, liquid_double_complex) LIQUID_POLY_DEFINE_API(LIQUID_POLY_MANGLE_CFLOAT, liquid_float_complex, liquid_float_complex) #if 0 // expands the polynomial: (1+x)^n void poly_binomial_expand(unsigned int _n, int * _c); // expands the polynomial: (1+x)^k * (1-x)^(n-k) void poly_binomial_expand_pm(unsigned int _n, unsigned int _k, int * _c); #endif // // modular arithmetic, etc. // // maximum number of factors #define LIQUID_MAX_FACTORS (40) // is number prime? int liquid_is_prime(unsigned int _n); // compute number's prime factors // _n : number to factor // _factors : pre-allocated array of factors, [size: LIQUID_MAX_FACTORS x 1] // _num_factors: number of factors found, sorted ascending int liquid_factor(unsigned int _n, unsigned int * _factors, unsigned int * _num_factors); // compute number's unique prime factors // _n : number to factor // _factors : pre-allocated array of factors, [size: LIQUID_MAX_FACTORS x 1] // _num_factors: number of unique factors found, sorted ascending int liquid_unique_factor(unsigned int _n, unsigned int * _factors, unsigned int * _num_factors); // compute greatest common divisor between to integers \(p\) and \(q\) unsigned int liquid_gcd(unsigned int _p, unsigned int _q); // compute c = base^exp (mod n) unsigned int liquid_modpow(unsigned int _base, unsigned int _exp, unsigned int _n); // find smallest primitive root of _n unsigned int liquid_primitive_root(unsigned int _n); // find smallest primitive root of _n, assuming _n is prime unsigned int liquid_primitive_root_prime(unsigned int _n); // Euler's totient function unsigned int liquid_totient(unsigned int _n); // // MODULE : matrix // #define LIQUID_MATRIX_MANGLE_DOUBLE(name) LIQUID_CONCAT(matrix, name) #define LIQUID_MATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(matrixf, name) #define LIQUID_MATRIX_MANGLE_CDOUBLE(name) LIQUID_CONCAT(matrixc, name) #define LIQUID_MATRIX_MANGLE_CFLOAT(name) LIQUID_CONCAT(matrixcf, name) // large macro // MATRIX : name-mangling macro // T : data type #define LIQUID_MATRIX_DEFINE_API(MATRIX,T) \ \ /* Print array as matrix to stdout */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _r : rows in matrix */ \ /* _c : columns in matrix */ \ int MATRIX(_print)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Perform point-wise addition between two matrices \(\vec{X}\) */ \ /* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\). */ \ /* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}+\vec{Y}_{i,j} \), */ \ /* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _y : input matrix, [size: _r x _c] */ \ /* _z : output matrix, [size: _r x _c] */ \ /* _r : number of rows in each matrix */ \ /* _c : number of columns in each matrix */ \ int MATRIX(_add)(T * _x, \ T * _y, \ T * _z, \ unsigned int _r, \ unsigned int _c); \ \ /* Perform point-wise subtraction between two matrices \(\vec{X}\) */ \ /* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ /* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}-\vec{Y}_{i,j} \), */ \ /* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _y : input matrix, [size: _r x _c] */ \ /* _z : output matrix, [size: _r x _c] */ \ /* _r : number of rows in each matrix */ \ /* _c : number of columns in each matrix */ \ int MATRIX(_sub)(T * _x, \ T * _y, \ T * _z, \ unsigned int _r, \ unsigned int _c); \ \ /* Perform point-wise multiplication between two matrices \(\vec{X}\) */ \ /* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ /* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j} \vec{Y}_{i,j} \), */ \ /* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _y : input matrix, [size: _r x _c] */ \ /* _z : output matrix, [size: _r x _c] */ \ /* _r : number of rows in each matrix */ \ /* _c : number of columns in each matrix */ \ int MATRIX(_pmul)(T * _x, \ T * _y, \ T * _z, \ unsigned int _r, \ unsigned int _c); \ \ /* Perform point-wise division between two matrices \(\vec{X}\) */ \ /* and \(\vec{Y}\), saving the result in the output matrix \(\vec{Z}\) */ \ /* That is, \(\vec{Z}_{i,j}=\vec{X}_{i,j}/\vec{Y}_{i,j} \), */ \ /* \( \forall_{i \in r} \) and \( \forall_{j \in c} \) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _y : input matrix, [size: _r x _c] */ \ /* _z : output matrix, [size: _r x _c] */ \ /* _r : number of rows in each matrix */ \ /* _c : number of columns in each matrix */ \ int MATRIX(_pdiv)(T * _x, \ T * _y, \ T * _z, \ unsigned int _r, \ unsigned int _c); \ \ /* Multiply two matrices \(\vec{X}\) and \(\vec{Y}\), storing the */ \ /* result in \(\vec{Z}\). */ \ /* NOTE: _rz = _rx, _cz = _cy, and _cx = _ry */ \ /* _x : input matrix, [size: _rx x _cx] */ \ /* _rx : number of rows in _x */ \ /* _cx : number of columns in _x */ \ /* _y : input matrix, [size: _ry x _cy] */ \ /* _ry : number of rows in _y */ \ /* _cy : number of columns in _y */ \ /* _z : output matrix, [size: _rz x _cz] */ \ /* _rz : number of rows in _z */ \ /* _cz : number of columns in _z */ \ int MATRIX(_mul)(T * _x, unsigned int _rx, unsigned int _cx, \ T * _y, unsigned int _ry, unsigned int _cy, \ T * _z, unsigned int _rz, unsigned int _cz); \ \ /* Solve \(\vec{X} = \vec{Y} \vec{Z}\) for \(\vec{Z}\) for square */ \ /* matrices of size \(n\) */ \ /* _x : input matrix, [size: _n x _n] */ \ /* _y : input matrix, [size: _n x _n] */ \ /* _z : output matrix, [size: _n x _n] */ \ /* _n : number of rows and columns in each matrix */ \ int MATRIX(_div)(T * _x, \ T * _y, \ T * _z, \ unsigned int _n); \ \ /* Compute the determinant of a square matrix \(\vec{X}\) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ T MATRIX(_det)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Compute the in-place transpose of the matrix \(\vec{X}\) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_trans)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Compute the in-place Hermitian transpose of the matrix \(\vec{X}\) */ \ /* _x : input matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_hermitian)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Compute \(\vec{X}\vec{X}^T\) on a \(m \times n\) matrix. */ \ /* The result is a \(m \times m\) matrix. */ \ /* _x : input matrix, [size: _m x _n] */ \ /* _m : input rows */ \ /* _n : input columns */ \ /* _xxT : output matrix, [size: _m x _m] */ \ int MATRIX(_mul_transpose)(T * _x, \ unsigned int _m, \ unsigned int _n, \ T * _xxT); \ \ /* Compute \(\vec{X}^T\vec{X}\) on a \(m \times n\) matrix. */ \ /* The result is a \(n \times n\) matrix. */ \ /* _x : input matrix, [size: _m x _n] */ \ /* _m : input rows */ \ /* _n : input columns */ \ /* _xTx : output matrix, [size: _n x _n] */ \ int MATRIX(_transpose_mul)(T * _x, \ unsigned int _m, \ unsigned int _n, \ T * _xTx); \ \ /* Compute \(\vec{X}\vec{X}^H\) on a \(m \times n\) matrix. */ \ /* The result is a \(m \times m\) matrix. */ \ /* _x : input matrix, [size: _m x _n] */ \ /* _m : input rows */ \ /* _n : input columns */ \ /* _xxH : output matrix, [size: _m x _m] */ \ int MATRIX(_mul_hermitian)(T * _x, \ unsigned int _m, \ unsigned int _n, \ T * _xxH); \ \ /* Compute \(\vec{X}^H\vec{X}\) on a \(m \times n\) matrix. */ \ /* The result is a \(n \times n\) matrix. */ \ /* _x : input matrix, [size: _m x _n] */ \ /* _m : input rows */ \ /* _n : input columns */ \ /* _xHx : output matrix, [size: _n x _n] */ \ int MATRIX(_hermitian_mul)(T * _x, \ unsigned int _m, \ unsigned int _n, \ T * _xHx); \ \ \ /* Augment two matrices \(\vec{X}\) and \(\vec{Y}\), storing the result */ \ /* in \(\vec{Z}\) */ \ /* NOTE: _rz = _rx = _ry, _rx = _ry, and _cz = _cx + _cy */ \ /* _x : input matrix, [size: _rx x _cx] */ \ /* _rx : number of rows in _x */ \ /* _cx : number of columns in _x */ \ /* _y : input matrix, [size: _ry x _cy] */ \ /* _ry : number of rows in _y */ \ /* _cy : number of columns in _y */ \ /* _z : output matrix, [size: _rz x _cz] */ \ /* _rz : number of rows in _z */ \ /* _cz : number of columns in _z */ \ int MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx, \ T * _y, unsigned int _ry, unsigned int _cy, \ T * _z, unsigned int _rz, unsigned int _cz); \ \ /* Compute the inverse of a square matrix \(\vec{X}\) */ \ /* _x : input/output matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_inv)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Generate the identity square matrix of size \(n\) */ \ /* _x : output matrix, [size: _n x _n] */ \ /* _n : dimensions of _x */ \ int MATRIX(_eye)(T * _x, \ unsigned int _n); \ \ /* Generate the all-ones matrix of size \(n\) */ \ /* _x : output matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_ones)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Generate the all-zeros matrix of size \(n\) */ \ /* _x : output matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_zeros)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Perform Gauss-Jordan elimination on matrix \(\vec{X}\) */ \ /* _x : input/output matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ int MATRIX(_gjelim)(T * _x, \ unsigned int _r, \ unsigned int _c); \ \ /* Pivot on element \(\vec{X}_{i,j}\) */ \ /* _x : output matrix, [size: _r x _c] */ \ /* _r : rows of _x */ \ /* _c : columns of _x */ \ /* _i : pivot row */ \ /* _j : pivot column */ \ int MATRIX(_pivot)(T * _x, \ unsigned int _r, \ unsigned int _c, \ unsigned int _i, \ unsigned int _j); \ \ /* Swap rows _r1 and _r2 of matrix \(\vec{X}\) */ \ /* _x : input/output matrix, [size: _r x _c] */ \ /* _r : rows of _x */ \ /* _c : columns of _x */ \ /* _r1 : first row to swap */ \ /* _r2 : second row to swap */ \ int MATRIX(_swaprows)(T * _x, \ unsigned int _r, \ unsigned int _c, \ unsigned int _r1, \ unsigned int _r2); \ \ /* Solve linear system of \(n\) equations: \(\vec{A}\vec{x} = \vec{b}\) */ \ /* _A : system matrix, [size: _n x _n] */ \ /* _n : system size */ \ /* _b : equality vector, [size: _n x 1] */ \ /* _x : solution vector, [size: _n x 1] */ \ /* _opts : options (ignored for now) */ \ int MATRIX(_linsolve)(T * _A, \ unsigned int _n, \ T * _b, \ T * _x, \ void * _opts); \ \ /* Solve linear system of equations using conjugate gradient method. */ \ /* _A : symmetric positive definite square matrix */ \ /* _n : system dimension */ \ /* _b : equality, [size: _n x 1] */ \ /* _x : solution estimate, [size: _n x 1] */ \ /* _opts : options (ignored for now) */ \ int MATRIX(_cgsolve)(T * _A, \ unsigned int _n, \ T * _b, \ T * _x, \ void * _opts); \ \ /* Perform L/U/P decomposition using Crout's method */ \ /* _x : input/output matrix, [size: _rx x _cx] */ \ /* _rx : rows of _x */ \ /* _cx : columns of _x */ \ /* _l : first row to swap */ \ /* _u : first row to swap */ \ /* _p : first row to swap */ \ int MATRIX(_ludecomp_crout)(T * _x, \ unsigned int _rx, \ unsigned int _cx, \ T * _l, \ T * _u, \ T * _p); \ \ /* Perform L/U/P decomposition, Doolittle's method */ \ /* _x : input/output matrix, [size: _rx x _cx] */ \ /* _rx : rows of _x */ \ /* _cx : columns of _x */ \ /* _l : first row to swap */ \ /* _u : first row to swap */ \ /* _p : first row to swap */ \ int MATRIX(_ludecomp_doolittle)(T * _x, \ unsigned int _rx, \ unsigned int _cx, \ T * _l, \ T * _u, \ T * _p); \ \ /* Perform orthnormalization using the Gram-Schmidt algorithm */ \ /* _A : input matrix, [size: _r x _c] */ \ /* _r : rows */ \ /* _c : columns */ \ /* _v : output matrix */ \ int MATRIX(_gramschmidt)(T * _A, \ unsigned int _r, \ unsigned int _c, \ T * _v); \ \ /* Perform Q/R decomposition using the Gram-Schmidt algorithm such that */ \ /* \( \vec{A} = \vec{Q} \vec{R} \) */ \ /* and \( \vec{Q}^T \vec{Q} = \vec{I}_n \) */ \ /* and \(\vec{R\}\) is a diagonal \(m \times m\) matrix */ \ /* NOTE: all matrices are square */ \ /* _a : input matrix, [size: _m x _m] */ \ /* _m : rows */ \ /* _n : columns (same as cols) */ \ /* _q : output matrix, [size: _m x _m] */ \ /* _r : output matrix, [size: _m x _m] */ \ int MATRIX(_qrdecomp_gramschmidt)(T * _a, \ unsigned int _m, \ unsigned int _n, \ T * _q, \ T * _r); \ \ /* Compute Cholesky decomposition of a symmetric/Hermitian */ \ /* positive-definite matrix as \( \vec{A} = \vec{L}\vec{L}^T \) */ \ /* _a : input square matrix, [size: _n x _n] */ \ /* _n : input matrix dimension */ \ /* _l : output lower-triangular matrix */ \ int MATRIX(_chol)(T * _a, \ unsigned int _n, \ T * _l); \ #define matrix_access(X,R,C,r,c) ((X)[(r)*(C)+(c)]) #define matrixc_access(X,R,C,r,c) matrix_access(X,R,C,r,c) #define matrixf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) #define matrixcf_access(X,R,C,r,c) matrix_access(X,R,C,r,c) LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_FLOAT, float) LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_DOUBLE, double) LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CFLOAT, liquid_float_complex) LIQUID_MATRIX_DEFINE_API(LIQUID_MATRIX_MANGLE_CDOUBLE, liquid_double_complex) #define LIQUID_SMATRIX_MANGLE_BOOL(name) LIQUID_CONCAT(smatrixb, name) #define LIQUID_SMATRIX_MANGLE_FLOAT(name) LIQUID_CONCAT(smatrixf, name) #define LIQUID_SMATRIX_MANGLE_INT(name) LIQUID_CONCAT(smatrixi, name) // sparse 'alist' matrix type (similar to MacKay, Davey Lafferty convention) // large macro // SMATRIX : name-mangling macro // T : primitive data type #define LIQUID_SMATRIX_DEFINE_API(SMATRIX,T) \ \ /* Sparse matrix object (similar to MacKay, Davey, Lafferty convention) */ \ typedef struct SMATRIX(_s) * SMATRIX(); \ \ /* Create \(M \times N\) sparse matrix, initialized with zeros */ \ /* _m : number of rows in matrix */ \ /* _n : number of columns in matrix */ \ SMATRIX() SMATRIX(_create)(unsigned int _m, \ unsigned int _n); \ \ /* Create \(M \times N\) sparse matrix, initialized on array */ \ /* _x : input matrix, [size: _m x _n] */ \ /* _m : number of rows in input matrix */ \ /* _n : number of columns in input matrix */ \ SMATRIX() SMATRIX(_create_array)(T * _x, \ unsigned int _m, \ unsigned int _n); \ \ /* Destroy object, freeing all internal memory */ \ int SMATRIX(_destroy)(SMATRIX() _q); \ \ /* Print sparse matrix in compact form to stdout */ \ int SMATRIX(_print)(SMATRIX() _q); \ \ /* Print sparse matrix in expanded form to stdout */ \ int SMATRIX(_print_expanded)(SMATRIX() _q); \ \ /* Get size of sparse matrix (number of rows and columns) */ \ /* _q : sparse matrix object */ \ /* _m : number of rows in matrix */ \ /* _n : number of columns in matrix */ \ int SMATRIX(_size)(SMATRIX() _q, \ unsigned int * _m, \ unsigned int * _n); \ \ /* Zero all elements and retain allocated memory */ \ int SMATRIX(_clear)(SMATRIX() _q); \ \ /* Zero all elements and clear memory */ \ int SMATRIX(_reset)(SMATRIX() _q); \ \ /* Determine if value has been set (allocated memory) */ \ /* _q : sparse matrix object */ \ /* _m : row index of value to query */ \ /* _n : column index of value to query */ \ int SMATRIX(_isset)(SMATRIX() _q, \ unsigned int _m, \ unsigned int _n); \ \ /* Insert an element at index, allocating memory as necessary */ \ /* _q : sparse matrix object */ \ /* _m : row index of value to insert */ \ /* _n : column index of value to insert */ \ /* _v : value to insert */ \ int SMATRIX(_insert)(SMATRIX() _q, \ unsigned int _m, \ unsigned int _n, \ T _v); \ \ /* Delete an element at index, freeing memory */ \ /* _q : sparse matrix object */ \ /* _m : row index of value to delete */ \ /* _n : column index of value to delete */ \ int SMATRIX(_delete)(SMATRIX() _q, \ unsigned int _m, \ unsigned int _n); \ \ /* Set the value in matrix at specified row and column, allocating */ \ /* memory if needed */ \ /* _q : sparse matrix object */ \ /* _m : row index of value to set */ \ /* _n : column index of value to set */ \ /* _v : value to set in matrix */ \ int SMATRIX(_set)(SMATRIX() _q, \ unsigned int _m, \ unsigned int _n, \ T _v); \ \ /* Get the value from matrix at specified row and column */ \ /* _q : sparse matrix object */ \ /* _m : row index of value to get */ \ /* _n : column index of value to get */ \ T SMATRIX(_get)(SMATRIX() _q, \ unsigned int _m, \ unsigned int _n); \ \ /* Initialize to identity matrix; set all diagonal elements to 1, all */ \ /* others to 0. This is done with both square and non-square matrices. */ \ int SMATRIX(_eye)(SMATRIX() _q); \ \ /* Multiply two sparse matrices, \( \vec{Z} = \vec{X} \vec{Y} \) */ \ /* _x : sparse matrix object (input) */ \ /* _y : sparse matrix object (input) */ \ /* _z : sparse matrix object (output) */ \ int SMATRIX(_mul)(SMATRIX() _x, \ SMATRIX() _y, \ SMATRIX() _z); \ \ /* Multiply sparse matrix by vector */ \ /* _q : sparse matrix */ \ /* _x : input vector, [size: _n x 1] */ \ /* _y : output vector, [size: _m x 1] */ \ int SMATRIX(_vmul)(SMATRIX() _q, \ T * _x, \ T * _y); \ LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_BOOL, unsigned char) LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_FLOAT, float) LIQUID_SMATRIX_DEFINE_API(LIQUID_SMATRIX_MANGLE_INT, short int) // // smatrix cross methods // // multiply sparse binary matrix by floating-point matrix // _q : sparse matrix, [size: A->M x A->N] // _x : input vector, [size: mx x nx ] // _y : output vector, [size: my x ny ] int smatrixb_mulf(smatrixb _A, float * _x, unsigned int _mx, unsigned int _nx, float * _y, unsigned int _my, unsigned int _ny); // multiply sparse binary matrix by floating-point vector // _q : sparse matrix // _x : input vector, [size: _N x 1] // _y : output vector, [size: _M x 1] int smatrixb_vmulf(smatrixb _q, float * _x, float * _y); // // MODULE : modem (modulator/demodulator) // // Maximum number of allowed bits per symbol #define MAX_MOD_BITS_PER_SYMBOL 8 // Modulation schemes available #define LIQUID_MODEM_NUM_SCHEMES (53) typedef enum { LIQUID_MODEM_UNKNOWN=0, // Unknown modulation scheme // Phase-shift keying (PSK) LIQUID_MODEM_PSK2, LIQUID_MODEM_PSK4, LIQUID_MODEM_PSK8, LIQUID_MODEM_PSK16, LIQUID_MODEM_PSK32, LIQUID_MODEM_PSK64, LIQUID_MODEM_PSK128, LIQUID_MODEM_PSK256, // Differential phase-shift keying (DPSK) LIQUID_MODEM_DPSK2, LIQUID_MODEM_DPSK4, LIQUID_MODEM_DPSK8, LIQUID_MODEM_DPSK16, LIQUID_MODEM_DPSK32, LIQUID_MODEM_DPSK64, LIQUID_MODEM_DPSK128, LIQUID_MODEM_DPSK256, // amplitude-shift keying LIQUID_MODEM_ASK2, LIQUID_MODEM_ASK4, LIQUID_MODEM_ASK8, LIQUID_MODEM_ASK16, LIQUID_MODEM_ASK32, LIQUID_MODEM_ASK64, LIQUID_MODEM_ASK128, LIQUID_MODEM_ASK256, // rectangular quadrature amplitude-shift keying (QAM) LIQUID_MODEM_QAM4, LIQUID_MODEM_QAM8, LIQUID_MODEM_QAM16, LIQUID_MODEM_QAM32, LIQUID_MODEM_QAM64, LIQUID_MODEM_QAM128, LIQUID_MODEM_QAM256, // amplitude phase-shift keying (APSK) LIQUID_MODEM_APSK4, LIQUID_MODEM_APSK8, LIQUID_MODEM_APSK16, LIQUID_MODEM_APSK32, LIQUID_MODEM_APSK64, LIQUID_MODEM_APSK128, LIQUID_MODEM_APSK256, // specific modem types LIQUID_MODEM_BPSK, // Specific: binary PSK LIQUID_MODEM_QPSK, // specific: quaternary PSK LIQUID_MODEM_OOK, // Specific: on/off keying LIQUID_MODEM_SQAM32, // 'square' 32-QAM LIQUID_MODEM_SQAM128, // 'square' 128-QAM LIQUID_MODEM_V29, // V.29 star constellation LIQUID_MODEM_ARB16OPT, // optimal 16-QAM LIQUID_MODEM_ARB32OPT, // optimal 32-QAM LIQUID_MODEM_ARB64OPT, // optimal 64-QAM LIQUID_MODEM_ARB128OPT, // optimal 128-QAM LIQUID_MODEM_ARB256OPT, // optimal 256-QAM LIQUID_MODEM_ARB64VT, // Virginia Tech logo LIQUID_MODEM_PI4DQPSK, // pi/4 differential QPSK // arbitrary modem type LIQUID_MODEM_ARB // arbitrary QAM } modulation_scheme; // structure for holding full modulation type descriptor struct modulation_type_s { const char * name; // short name (e.g. 'bpsk') const char * fullname; // full name (e.g. 'binary phase-shift keying') modulation_scheme scheme; // modulation scheme (e.g. LIQUID_MODEM_BPSK) unsigned int bps; // modulation depth (e.g. 1) }; // full modulation type descriptor extern const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES]; // Print compact list of existing and available modulation schemes int liquid_print_modulation_schemes(); // returns modulation_scheme based on input string modulation_scheme liquid_getopt_str2mod(const char * _str); // query basic modulation types int liquid_modem_is_psk(modulation_scheme _ms); int liquid_modem_is_dpsk(modulation_scheme _ms); int liquid_modem_is_ask(modulation_scheme _ms); int liquid_modem_is_qam(modulation_scheme _ms); int liquid_modem_is_apsk(modulation_scheme _ms); // useful functions // counts the number of different bits between two symbols unsigned int count_bit_errors(unsigned int _s1, unsigned int _s2); // counts the number of different bits between two arrays of symbols // _msg0 : original message, [size: _n x 1] // _msg1 : copy of original message, [size: _n x 1] // _n : message size unsigned int count_bit_errors_array(unsigned char * _msg0, unsigned char * _msg1, unsigned int _n); // converts binary-coded decimal (BCD) to gray, ensuring successive values // differ by exactly one bit unsigned int gray_encode(unsigned int symbol_in); // converts a gray-encoded symbol to binary-coded decimal (BCD) unsigned int gray_decode(unsigned int symbol_in); // pack soft bits into symbol // _soft_bits : soft input bits, [size: _bps x 1] // _bps : bits per symbol // _sym_out : output symbol, value in [0,2^_bps) int liquid_pack_soft_bits(unsigned char * _soft_bits, unsigned int _bps, unsigned int * _sym_out); // unpack soft bits into symbol // _sym_in : input symbol, value in [0,2^_bps) // _bps : bits per symbol // _soft_bits : soft output bits, [size: _bps x 1] int liquid_unpack_soft_bits(unsigned int _sym_in, unsigned int _bps, unsigned char * _soft_bits); // // Linear modem // #define LIQUID_MODEM_MANGLE_FLOAT(name) LIQUID_CONCAT(modemcf,name) // temporary shim to support backwards compatibility between "modemcf" and "modem" #define LIQUID_MODEM_MANGLE_FLOAT_SHIM(name) LIQUID_CONCAT(modem,name) // FIXME: need to point both modem and modemcf pointers to same struct (shim) typedef struct modemcf_s * modemcf; typedef struct modemcf_s * modem; // Macro : MODEM // MODEM : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_MODEM_DEFINE_API(MODEM,T,TC) \ \ /* Linear modulator/demodulator (modem) object */ \ /* FIXME: need to point both modem and modemcf pointers to same struct */ \ /*typedef struct MODEM(_s) * MODEM(); */ \ \ /* Create digital modem object with a particular scheme */ \ /* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ MODEM() MODEM(_create)(modulation_scheme _scheme); \ \ /* Create linear digital modem object with arbitrary constellation */ \ /* points defined by an external table of symbols. Sample points are */ \ /* provided as complex float pairs and converted internally if needed. */ \ /* _table : array of complex constellation points, [size: _M x 1] */ \ /* _M : modulation order and table size, _M must be power of 2 */ \ MODEM() MODEM(_create_arbitrary)(liquid_float_complex * _table, \ unsigned int _M); \ \ /* Recreate modulation scheme, re-allocating memory as necessary */ \ /* _q : modem object */ \ /* _scheme : linear modulation scheme (e.g. LIQUID_MODEM_QPSK) */ \ MODEM() MODEM(_recreate)(MODEM() _q, \ modulation_scheme _scheme); \ \ /* Copy object including all internal objects and state */ \ MODEM() MODEM(_copy)(MODEM() _q); \ \ /* Destroy modem object, freeing all allocated memory */ \ int MODEM(_destroy)(MODEM() _q); \ \ /* Print modem status to stdout */ \ int MODEM(_print)(MODEM() _q); \ \ /* Reset internal state of modem object; note that this is only */ \ /* relevant for modulation types that retain an internal state such as */ \ /* LIQUID_MODEM_DPSK4 as most linear modulation types are stateless */ \ int MODEM(_reset)(MODEM() _q); \ \ /* Generate random symbol for modulation */ \ unsigned int MODEM(_gen_rand_sym)(MODEM() _q); \ \ /* Get number of bits per symbol (bps) of modem object */ \ unsigned int MODEM(_get_bps)(MODEM() _q); \ \ /* Get modulation scheme of modem object */ \ modulation_scheme MODEM(_get_scheme)(MODEM() _q); \ \ /* Modulate input symbol (bits) and generate output complex sample */ \ /* _q : modem object */ \ /* _s : input symbol, 0 <= _s <= M-1 */ \ /* _y : output complex sample */ \ int MODEM(_modulate)(MODEM() _q, \ unsigned int _s, \ TC * _y); \ \ /* Demodulate input sample and provide maximum-likelihood estimate of */ \ /* symbol that would have generated it. */ \ /* The output is a hard decision value on the input sample. */ \ /* This is performed efficiently by taking advantage of symmetry on */ \ /* most modulation types. */ \ /* For example, square and rectangular quadrature amplitude modulation */ \ /* with gray coding can use a bisection search independently on its */ \ /* in-phase and quadrature channels. */ \ /* Arbitrary modulation schemes are relatively slow, however, for large */ \ /* modulation types as the demodulator must compute the distance */ \ /* between the received sample and all possible symbols to derive the */ \ /* optimal symbol. */ \ /* _q : modem object */ \ /* _x : input sample */ \ /* _s : output hard symbol, 0 <= _s <= M-1 */ \ int MODEM(_demodulate)(MODEM() _q, \ TC _x, \ unsigned int * _s); \ \ /* Demodulate input sample and provide (approximate) log-likelihood */ \ /* ratio (LLR, soft bits) as an output. */ \ /* Similarly to the hard-decision demodulation method, this is computed */ \ /* efficiently for most modulation types. */ \ /* _q : modem object */ \ /* _x : input sample */ \ /* _s : output hard symbol, 0 <= _s <= M-1 */ \ /* _soft_bits : output soft bits, [size: log2(M) x 1] */ \ int MODEM(_demodulate_soft)(MODEM() _q, \ TC _x, \ unsigned int * _s, \ unsigned char * _soft_bits); \ \ /* Get demodulator's estimated transmit sample */ \ int MODEM(_get_demodulator_sample)(MODEM() _q, \ TC * _x_hat); \ \ /* Get demodulator phase error */ \ float MODEM(_get_demodulator_phase_error)(MODEM() _q); \ \ /* Get demodulator error vector magnitude */ \ float MODEM(_get_demodulator_evm)(MODEM() _q); \ // define modem APIs LIQUID_MODEM_DEFINE_API(LIQUID_MODEM_MANGLE_FLOAT,float,liquid_float_complex) LIQUID_MODEM_DEFINE_API(LIQUID_MODEM_MANGLE_FLOAT_SHIM,float,liquid_float_complex) // // continuous-phase modulation // // gmskmod : GMSK modulator typedef struct gmskmod_s * gmskmod; // create gmskmod object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskmod gmskmod_create(unsigned int _k, unsigned int _m, float _BT); // Copy object recursively including all internal objects and state gmskmod gmskmod_copy(gmskmod _q); int gmskmod_destroy(gmskmod _q); int gmskmod_print(gmskmod _q); int gmskmod_reset(gmskmod _q); int gmskmod_modulate(gmskmod _q, unsigned int _sym, liquid_float_complex * _y); // gmskdem : GMSK demodulator typedef struct gmskdem_s * gmskdem; // create gmskdem object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskdem gmskdem_create(unsigned int _k, unsigned int _m, float _BT); // Copy object recursively including all internal objects and state gmskdem gmskdem_copy(gmskdem _q); int gmskdem_destroy(gmskdem _q); int gmskdem_print(gmskdem _q); int gmskdem_reset(gmskdem _q); int gmskdem_set_eq_bw(gmskdem _q, float _bw); int gmskdem_demodulate(gmskdem _q, liquid_float_complex * _y, unsigned int * _sym); // // continuous phase frequency-shift keying (CP-FSK) modems // // CP-FSK filter prototypes typedef enum { //LIQUID_CPFSK_UNKNOWN=0 LIQUID_CPFSK_SQUARE=0, // square pulse LIQUID_CPFSK_RCOS_FULL, // raised-cosine (full response) LIQUID_CPFSK_RCOS_PARTIAL, // raised-cosine (partial response) LIQUID_CPFSK_GMSK, // Gauss minimum-shift keying pulse } liquid_cpfsk_filter; // TODO: rename to cpfskmodcf for consistency #define LIQUID_CPFSKMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(cpfskmod,name) #define LIQUID_CPFSKMOD_DEFINE_API(CPFSKMOD,T,TC) \ \ /* Continuous-Phase Frequency-Shift Keying Modulator */ \ typedef struct CPFSKMOD(_s) * CPFSKMOD(); \ \ /* create cpfskmod object (frequency modulator) */ \ /* _bps : bits per symbol, _bps > 0 */ \ /* _h : modulation index, _h > 0 */ \ /* _k : samples/symbol, _k > 1, _k even */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : filter bandwidth parameter, _beta > 0 */ \ /* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, \ float _h, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ int _type); \ \ /* create modulator object for minimum-shift keying */ \ /* _k : samples/symbol, _k > 1, _k even */ \ CPFSKMOD() CPFSKMOD(_create_msk)(unsigned int _k); \ \ /* create modulator object for Gauss minimum-shift keying */ \ /* _k : samples/symbol, _k > 1, _k even */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _BT : bandwidth-time factor, 0 < _BT < 1 */ \ CPFSKMOD() CPFSKMOD(_create_gmsk)(unsigned int _k, \ unsigned int _m, \ float _BT); \ \ /* Copy object including all internal objects and state */ \ CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() _q); \ \ /* Destroy modulator object, freeing all allocate memory */ \ int CPFSKMOD(_destroy)(CPFSKMOD() _q); \ \ /* Print modulator status to stdout */ \ int CPFSKMOD(_print)(CPFSKMOD() _q); \ \ /* Reset internal state of modulator object */ \ int CPFSKMOD(_reset)(CPFSKMOD() _q); \ \ /* Get modulator's number of bits per symbol */ \ unsigned int CPFSKMOD(_get_bits_per_symbol)(CPFSKMOD() _q); \ \ /* Get modulator's modulation index */ \ float CPFSKMOD(_get_modulation_index)(CPFSKMOD() _q); \ \ /* Get modulator's number of samples per symbol */ \ unsigned int CPFSKMOD(_get_samples_per_symbol)(CPFSKMOD() _q); \ \ /* Get modulator's filter delay [symbols] */ \ unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q); \ \ /* Get modulator's bandwidth parameter */ \ float CPFSKMOD(_get_beta)(CPFSKMOD() _q); \ \ /* Get modulator's filter type */ \ int CPFSKMOD(_get_type)(CPFSKMOD() _q); \ \ /* modulate sample */ \ /* _q : frequency modulator object */ \ /* _s : input symbol */ \ /* _y : output sample array, [size: _k x 1] */ \ int CPFSKMOD(_modulate)(CPFSKMOD() _q, \ unsigned int _s, \ TC * _y); \ // define cpfskmod APIs LIQUID_CPFSKMOD_DEFINE_API(LIQUID_CPFSKMOD_MANGLE_FLOAT,float,liquid_float_complex) // TODO: rename to cpfskdemcf for consistency #define LIQUID_CPFSKDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(cpfskdem,name) #define LIQUID_CPFSKDEM_DEFINE_API(CPFSKDEM,T,TC) \ \ /* Continuous-Phase Frequency-Shift Keying Demodulator */ \ typedef struct CPFSKDEM(_s) * CPFSKDEM(); \ \ /* create demodulator object */ \ /* _bps : bits per symbol, _bps > 0 */ \ /* _h : modulation index, _h > 0 */ \ /* _k : samples/symbol, _k > 1, _k even */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _beta : filter bandwidth parameter, _beta > 0 */ \ /* _type : filter type (e.g. LIQUID_CPFSK_SQUARE) */ \ CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, \ float _h, \ unsigned int _k, \ unsigned int _m, \ float _beta, \ int _type); \ \ /* create demodulator object for minimum-shift keying */ \ /* _k : samples/symbol, _k > 1, _k even */ \ CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k); \ \ /* create demodulator object for Gauss minimum-shift keying */ \ /* _k : samples/symbol, _k > 1, _k even */ \ /* _m : filter delay (symbols), _m > 0 */ \ /* _BT : bandwidth-time factor, 0 < _BT < 1 */ \ CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, \ unsigned int _m, \ float _BT); \ \ /* Copy object including all internal objects and state */ \ CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() _q); \ \ /* Destroy demodulator object, freeing all internal memory */ \ int CPFSKDEM(_destroy)(CPFSKDEM() _q); \ \ /* Print demodulator object internals */ \ int CPFSKDEM(_print)(CPFSKDEM() _q); \ \ /* Reset state */ \ int CPFSKDEM(_reset)(CPFSKDEM() _q); \ \ /* Get demodulator's number of bits per symbol */ \ unsigned int CPFSKDEM(_get_bits_per_symbol)(CPFSKDEM() _q); \ \ /* Get demodulator's modulation index */ \ float CPFSKDEM(_get_modulation_index)(CPFSKDEM() _q); \ \ /* Get demodulator's number of samples per symbol */ \ unsigned int CPFSKDEM(_get_samples_per_symbol)(CPFSKDEM() _q); \ \ /* Get demodulator's transmit delay [symbols] */ \ unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q); \ \ /* Get demodulator's bandwidth parameter */ \ float CPFSKDEM(_get_beta)(CPFSKDEM() _q); \ \ /* Get demodulator's filter type */ \ int CPFSKDEM(_get_type)(CPFSKDEM() _q); \ \ /* demodulate array of samples, assuming perfect timing */ \ /* _q : continuous-phase frequency demodulator object */ \ /* _y : input sample array, [size: _k x 1] */ \ unsigned int CPFSKDEM(_demodulate)(CPFSKDEM() _q, \ TC * _y); \ \ /* demodulate_block */ \ // define cpfskmod APIs LIQUID_CPFSKDEM_DEFINE_API(LIQUID_CPFSKDEM_MANGLE_FLOAT,float,liquid_float_complex) // // M-ary frequency-shift keying (MFSK) modems // // FSK modulator typedef struct fskmod_s * fskmod; // create fskmod object (frequency modulator) // _m : bits per symbol, _bps > 0 // _k : samples/symbol, _k >= 2^_m // _bandwidth : total signal bandwidth, (0,0.5) fskmod fskmod_create(unsigned int _m, unsigned int _k, float _bandwidth); // Copy object recursively including all internal objects and state fskmod fskmod_copy(fskmod _q); // destroy fskmod object int fskmod_destroy(fskmod _q); // print fskmod object internals int fskmod_print(fskmod _q); // reset state int fskmod_reset(fskmod _q); // modulate sample // _q : frequency modulator object // _s : input symbol // _y : output sample array, [size: _k x 1] int fskmod_modulate(fskmod _q, unsigned int _s, liquid_float_complex * _y); // FSK demodulator typedef struct fskdem_s * fskdem; // create fskdem object (frequency demodulator) // _m : bits per symbol, _bps > 0 // _k : samples/symbol, _k >= 2^_m // _bandwidth : total signal bandwidth, (0,0.5) fskdem fskdem_create(unsigned int _m, unsigned int _k, float _bandwidth); // Copy object recursively including all internal objects and state fskdem fskdem_copy(fskdem _q); // destroy fskdem object int fskdem_destroy(fskdem _q); // print fskdem object internals int fskdem_print(fskdem _q); // reset state int fskdem_reset(fskdem _q); // demodulate symbol, assuming perfect symbol timing // _q : fskdem object // _y : input sample array, [size: _k x 1] unsigned int fskdem_demodulate(fskdem _q, liquid_float_complex * _y); // get demodulator frequency error float fskdem_get_frequency_error(fskdem _q); // get energy for a particular symbol within a certain range float fskdem_get_symbol_energy(fskdem _q, unsigned int _s, unsigned int _range); // // Analog frequency modulator // #define LIQUID_FREQMOD_MANGLE_FLOAT(name) LIQUID_CONCAT(freqmod,name) // Macro : FREQMOD (analog frequency modulator) // FREQMOD : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_FREQMOD_DEFINE_API(FREQMOD,T,TC) \ \ /* Analog frequency modulation object */ \ typedef struct FREQMOD(_s) * FREQMOD(); \ \ /* Create freqmod object with a particular modulation factor */ \ /* _kf : modulation factor */ \ FREQMOD() FREQMOD(_create)(float _kf); \ \ /* Destroy freqmod object, freeing all internal memory */ \ int FREQMOD(_destroy)(FREQMOD() _q); \ \ /* Print freqmod object internals to stdout */ \ int FREQMOD(_print)(FREQMOD() _q); \ \ /* Reset state */ \ int FREQMOD(_reset)(FREQMOD() _q); \ \ /* Modulate single sample, producing single output sample at complex */ \ /* baseband. */ \ /* _q : frequency modulator object */ \ /* _m : message signal \( m(t) \) */ \ /* _s : complex baseband signal \( s(t) \) */ \ int FREQMOD(_modulate)(FREQMOD() _q, \ T _m, \ TC * _s); \ \ /* Modulate block of samples */ \ /* _q : frequency modulator object */ \ /* _m : message signal \( m(t) \), [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _s : complex baseband signal \( s(t) \), [size: _n x 1] */ \ int FREQMOD(_modulate_block)(FREQMOD() _q, \ T * _m, \ unsigned int _n, \ TC * _s); \ // define freqmod APIs LIQUID_FREQMOD_DEFINE_API(LIQUID_FREQMOD_MANGLE_FLOAT,float,liquid_float_complex) // // Analog frequency demodulator // #define LIQUID_FREQDEM_MANGLE_FLOAT(name) LIQUID_CONCAT(freqdem,name) // Macro : FREQDEM (analog frequency modulator) // FREQDEM : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_FREQDEM_DEFINE_API(FREQDEM,T,TC) \ \ /* Analog frequency demodulator */ \ typedef struct FREQDEM(_s) * FREQDEM(); \ \ /* Create freqdem object (frequency modulator) */ \ /* _kf : modulation factor */ \ FREQDEM() FREQDEM(_create)(float _kf); \ \ /* Destroy freqdem object */ \ int FREQDEM(_destroy)(FREQDEM() _q); \ \ /* Print freqdem object internals */ \ int FREQDEM(_print)(FREQDEM() _q); \ \ /* Reset state */ \ int FREQDEM(_reset)(FREQDEM() _q); \ \ /* Demodulate sample */ \ /* _q : frequency modulator object */ \ /* _r : received signal r(t) */ \ /* _m : output message signal m(t) */ \ int FREQDEM(_demodulate)(FREQDEM() _q, \ TC _r, \ T * _m); \ \ /* Demodulate block of samples */ \ /* _q : frequency demodulator object */ \ /* _r : received signal r(t) [size: _n x 1] */ \ /* _n : number of input, output samples */ \ /* _m : message signal m(t), [size: _n x 1] */ \ int FREQDEM(_demodulate_block)(FREQDEM() _q, \ TC * _r, \ unsigned int _n, \ T * _m); \ // define freqdem APIs LIQUID_FREQDEM_DEFINE_API(LIQUID_FREQDEM_MANGLE_FLOAT,float,liquid_float_complex) // amplitude modulation types typedef enum { LIQUID_AMPMODEM_DSB=0, // double side-band LIQUID_AMPMODEM_USB, // single side-band (upper) LIQUID_AMPMODEM_LSB // single side-band (lower) } liquid_ampmodem_type; typedef struct ampmodem_s * ampmodem; // create ampmodem object // _m : modulation index // _type : AM type (e.g. LIQUID_AMPMODEM_DSB) // _suppressed_carrier : carrier suppression flag ampmodem ampmodem_create(float _mod_index, liquid_ampmodem_type _type, int _suppressed_carrier); // destroy ampmodem object int ampmodem_destroy(ampmodem _q); // print ampmodem object internals int ampmodem_print(ampmodem _q); // reset ampmodem object state int ampmodem_reset(ampmodem _q); // accessor methods unsigned int ampmodem_get_delay_mod (ampmodem _q); unsigned int ampmodem_get_delay_demod(ampmodem _q); // modulate sample int ampmodem_modulate(ampmodem _q, float _x, liquid_float_complex * _y); int ampmodem_modulate_block(ampmodem _q, float * _m, unsigned int _n, liquid_float_complex * _s); // demodulate sample int ampmodem_demodulate(ampmodem _q, liquid_float_complex _y, float * _x); int ampmodem_demodulate_block(ampmodem _q, liquid_float_complex * _r, unsigned int _n, float * _m); // // MODULE : multichannel // #define FIRPFBCH_NYQUIST 0 #define FIRPFBCH_ROOTNYQUIST 1 #define LIQUID_ANALYZER 0 #define LIQUID_SYNTHESIZER 1 // // Finite impulse response polyphase filterbank channelizer // #define LIQUID_FIRPFBCH_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch_crcf,name) #define LIQUID_FIRPFBCH_MANGLE_CCCF(name) LIQUID_CONCAT(firpfbch_cccf,name) // Macro: // FIRPFBCH : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FIRPFBCH_DEFINE_API(FIRPFBCH,TO,TC,TI) \ \ /* Finite impulse response polyphase filterbank channelizer */ \ typedef struct FIRPFBCH(_s) * FIRPFBCH(); \ \ /* Create finite impulse response polyphase filter-bank */ \ /* channelizer object from external coefficients */ \ /* _type : channelizer type, e.g. LIQUID_ANALYZER */ \ /* _M : number of channels */ \ /* _p : number of coefficients for each channel */ \ /* _h : coefficients, [size: _M*_p x 1] */ \ FIRPFBCH() FIRPFBCH(_create)(int _type, \ unsigned int _M, \ unsigned int _p, \ TC * _h); \ \ /* Create FIR polyphase filterbank channelizer object with */ \ /* prototype filter based on windowed Kaiser design */ \ /* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ /* _M : number of channels */ \ /* _m : filter delay (symbols) */ \ /* _As : stop-band attenuation [dB] */ \ FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, \ unsigned int _M, \ unsigned int _m, \ float _As); \ \ /* Create FIR polyphase filterbank channelizer object with */ \ /* prototype root-Nyquist filter */ \ /* _type : type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) */ \ /* _M : number of channels */ \ /* _m : filter delay (symbols) */ \ /* _beta : filter excess bandwidth factor, in [0,1] */ \ /* _ftype : filter prototype (rrcos, rkaiser, etc.) */ \ FIRPFBCH() FIRPFBCH(_create_rnyquist)(int _type, \ unsigned int _M, \ unsigned int _m, \ float _beta, \ int _ftype); \ \ /* Destroy firpfbch object */ \ int FIRPFBCH(_destroy)(FIRPFBCH() _q); \ \ /* Clear/reset firpfbch internal state */ \ int FIRPFBCH(_reset)(FIRPFBCH() _q); \ \ /* Print firpfbch internal parameters to stdout */ \ int FIRPFBCH(_print)(FIRPFBCH() _q); \ \ /* Execute filterbank as synthesizer on block of samples */ \ /* _q : filterbank channelizer object */ \ /* _x : channelized input, [size: num_channels x 1] */ \ /* _y : output time series, [size: num_channels x 1] */ \ int FIRPFBCH(_synthesizer_execute)(FIRPFBCH() _q, \ TI * _x, \ TO * _y); \ \ /* Execute filterbank as analyzer on block of samples */ \ /* _q : filterbank channelizer object */ \ /* _x : input time series, [size: num_channels x 1] */ \ /* _y : channelized output, [size: num_channels x 1] */ \ int FIRPFBCH(_analyzer_execute)(FIRPFBCH() _q, \ TI * _x, \ TO * _y); \ LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) LIQUID_FIRPFBCH_DEFINE_API(LIQUID_FIRPFBCH_MANGLE_CCCF, liquid_float_complex, liquid_float_complex, liquid_float_complex) // // Finite impulse response polyphase filterbank channelizer // with output rate 2 Fs / M // #define LIQUID_FIRPFBCH2_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbch2_crcf,name) // Macro: // FIRPFBCH2 : name-mangling macro // TO : output data type // TC : coefficients data type // TI : input data type #define LIQUID_FIRPFBCH2_DEFINE_API(FIRPFBCH2,TO,TC,TI) \ \ /* Finite impulse response polyphase filterbank channelizer */ \ /* with output rate oversampled by a factor of 2 */ \ typedef struct FIRPFBCH2(_s) * FIRPFBCH2(); \ \ /* Create firpfbch2 object with prototype filter from external */ \ /* coefficients */ \ /* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ /* _M : number of channels (must be even) */ \ /* _m : prototype filter semi-length, length=2*M*m */ \ /* _h : prototype filter coefficient array */ \ FIRPFBCH2() FIRPFBCH2(_create)(int _type, \ unsigned int _M, \ unsigned int _m, \ TC * _h); \ \ /* Create firpfbch2 object using Kaiser window prototype */ \ /* _type : channelizer type (e.g. LIQUID_ANALYZER) */ \ /* _M : number of channels (must be even) */ \ /* _m : prototype filter semi-length, length=2*M*m+1 */ \ /* _As : filter stop-band attenuation [dB] */ \ FIRPFBCH2() FIRPFBCH2(_create_kaiser)(int _type, \ unsigned int _M, \ unsigned int _m, \ float _As); \ \ /* Copy object recursively including all internal objects and state */ \ FIRPFBCH2() FIRPFBCH2(_copy)(FIRPFBCH2() _q); \ \ /* Destroy firpfbch2 object, freeing internal memory */ \ int FIRPFBCH2(_destroy)(FIRPFBCH2() _q); \ \ /* Reset firpfbch2 object internals */ \ int FIRPFBCH2(_reset)(FIRPFBCH2() _q); \ \ /* Print firpfbch2 object internals */ \ int FIRPFBCH2(_print)(FIRPFBCH2() _q); \ \ /* Get type, either LIQUID_ANALYZER or LIQUID_SYNTHESIZER */ \ int FIRPFBCH2(_get_type)(FIRPFBCH2() _q); \ \ /* Get number of channels, M */ \ unsigned int FIRPFBCH2(_get_M)(FIRPFBCH2() _q); \ \ /* Get prototype filter sem-length, m */ \ unsigned int FIRPFBCH2(_get_m)(FIRPFBCH2() _q); \ \ /* Execute filterbank channelizer */ \ /* LIQUID_ANALYZER: input: M/2, output: M */ \ /* LIQUID_SYNTHESIZER: input: M, output: M/2 */ \ /* _x : channelizer input */ \ /* _y : channelizer output */ \ int FIRPFBCH2(_execute)(FIRPFBCH2() _q, \ TI * _x, \ TO * _y); \ LIQUID_FIRPFBCH2_DEFINE_API(LIQUID_FIRPFBCH2_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) // // Finite impulse response polyphase filterbank channelizer with output rate // Fs / decim on each of independent, evenly-spaced channels // #define LIQUID_FIRPFBCHR_MANGLE_CRCF(name) LIQUID_CONCAT(firpfbchr_crcf,name) #define LIQUID_FIRPFBCHR_DEFINE_API(FIRPFBCHR,TO,TC,TI) \ \ /* Finite impulse response polyphase filterbank channelizer */ \ /* with output rational output rate \( P / M \) */ \ typedef struct FIRPFBCHR(_s) * FIRPFBCHR(); \ \ /* create rational rate resampling channelizer (firpfbchr) object by */ \ /* specifying filter coefficients directly */ \ /* _chans : number of output channels in chanelizer */ \ /* _decim : output decimation factor (output rate is 1/decim input) */ \ /* _m : prototype filter semi-length, length=2*chans*m */ \ /* _h : prototype filter coefficient array, [size: 2*chans*m x 1] */ \ FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _chans, \ unsigned int _decim, \ unsigned int _m, \ TC * _h); \ \ /* create rational rate resampling channelizer (firpfbchr) object by */ \ /* specifying filter design parameters for Kaiser prototype */ \ /* _chans : number of output channels in chanelizer */ \ /* _decim : output decimation factor (output rate is 1/decim input) */ \ /* _m : prototype filter semi-length, length=2*chans*m */ \ /* _as : filter stop-band attenuation [dB] */ \ FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _chans, \ unsigned int _decim, \ unsigned int _m, \ float _as); \ \ /* destroy firpfbchr object, freeing internal memory */ \ int FIRPFBCHR(_destroy)(FIRPFBCHR() _q); \ \ /* reset firpfbchr object internal state and buffers */ \ int FIRPFBCHR(_reset)(FIRPFBCHR() _q); \ \ /* print firpfbchr object internals to stdout */ \ int FIRPFBCHR(_print)(FIRPFBCHR() _q); \ \ /* get number of output channels to channelizer */ \ DEPRECATED("use firpfbchr_get_num_channels(...) instead", \ unsigned int FIRPFBCHR(_get_M)(FIRPFBCHR() _q); ) \ unsigned int FIRPFBCHR(_get_num_channels)(FIRPFBCHR() _q); \ \ /* get decimation factor for channelizer */ \ DEPRECATED("use firpfbchr_get_decim_rate(...) instead", \ unsigned int FIRPFBCHR(_get_P)(FIRPFBCHR() _q); ) \ unsigned int FIRPFBCHR(_get_decim_rate)(FIRPFBCHR() _q); \ \ /* get semi-length to channelizer filter prototype */ \ unsigned int FIRPFBCHR(_get_m)(FIRPFBCHR() _q); \ \ /* push buffer of samples into filter bank */ \ /* _q : channelizer object */ \ /* _x : channelizer input, [size: decim x 1] */ \ int FIRPFBCHR(_push)(FIRPFBCHR() _q, \ TI * _x); \ \ /* execute filterbank channelizer, writing complex baseband samples for */ \ /* each channel into output array */ \ /* _q : channelizer object */ \ /* _y : channelizer output, [size: chans x 1] */ \ int FIRPFBCHR(_execute)(FIRPFBCHR() _q, \ TO * _y); \ LIQUID_FIRPFBCHR_DEFINE_API(LIQUID_FIRPFBCHR_MANGLE_CRCF, liquid_float_complex, float, liquid_float_complex) #define OFDMFRAME_SCTYPE_NULL 0 #define OFDMFRAME_SCTYPE_PILOT 1 #define OFDMFRAME_SCTYPE_DATA 2 // initialize default subcarrier allocation // _M : number of subcarriers // _p : output subcarrier allocation array, [size: _M x 1] int ofdmframe_init_default_sctype(unsigned int _M, unsigned char * _p); // initialize default subcarrier allocation // _M : number of subcarriers // _f0 : lower frequency band, _f0 in [-0.5,0.5] // _f1 : upper frequency band, _f1 in [-0.5,0.5] // _p : output subcarrier allocation array, [size: _M x 1] int ofdmframe_init_sctype_range(unsigned int _M, float _f0, float _f1, unsigned char * _p); // validate subcarrier type (count number of null, pilot, and data // subcarriers in the allocation) // _p : subcarrier allocation array, [size: _M x 1] // _M : number of subcarriers // _M_null : output number of null subcarriers // _M_pilot : output number of pilot subcarriers // _M_data : output number of data subcarriers int ofdmframe_validate_sctype(unsigned char * _p, unsigned int _M, unsigned int * _M_null, unsigned int * _M_pilot, unsigned int * _M_data); // print subcarrier allocation to screen // _p : output subcarrier allocation array, [size: _M x 1] // _M : number of subcarriers int ofdmframe_print_sctype(unsigned char * _p, unsigned int _M); // // OFDM frame (symbol) generator // typedef struct ofdmframegen_s * ofdmframegen; // create OFDM framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] ofdmframegen ofdmframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p); int ofdmframegen_destroy(ofdmframegen _q); int ofdmframegen_print(ofdmframegen _q); int ofdmframegen_reset(ofdmframegen _q); // write first S0 symbol int ofdmframegen_write_S0a(ofdmframegen _q, liquid_float_complex *_y); // write second S0 symbol int ofdmframegen_write_S0b(ofdmframegen _q, liquid_float_complex *_y); // write S1 symbol int ofdmframegen_write_S1(ofdmframegen _q, liquid_float_complex *_y); // write data symbol int ofdmframegen_writesymbol(ofdmframegen _q, liquid_float_complex * _x, liquid_float_complex *_y); // write tail int ofdmframegen_writetail(ofdmframegen _q, liquid_float_complex * _x); // // OFDM frame (symbol) synchronizer // typedef int (*ofdmframesync_callback)(liquid_float_complex * _y, unsigned char * _p, unsigned int _M, void * _userdata); typedef struct ofdmframesync_s * ofdmframesync; // create OFDM framing synchronizer object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmframesync ofdmframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmframesync_callback _callback, void * _userdata); int ofdmframesync_destroy(ofdmframesync _q); int ofdmframesync_print(ofdmframesync _q); int ofdmframesync_reset(ofdmframesync _q); int ofdmframesync_is_frame_open(ofdmframesync _q); int ofdmframesync_execute(ofdmframesync _q, liquid_float_complex * _x, unsigned int _n); // query methods float ofdmframesync_get_rssi(ofdmframesync _q); // received signal strength indication float ofdmframesync_get_cfo(ofdmframesync _q); // carrier offset estimate // set methods int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo); // set carrier offset estimate // debugging int ofdmframesync_debug_enable(ofdmframesync _q); int ofdmframesync_debug_disable(ofdmframesync _q); int ofdmframesync_debug_print(ofdmframesync _q, const char * _filename); // // MODULE : nco (numerically-controlled oscillator) // // oscillator type typedef enum { // numerically-controlled oscillator (fastest in all aspects) LIQUID_NCO=0, // "voltage"-controlled oscillator (precise) LIQUID_VCO, LIQUID_VCO_INTERP=LIQUID_VCO, // fast at computing output but having separate limited API, // and each time frequency being set it does dynamic (re-)allocating and // calculating of lookup table with resulting memory size and speed slowdown // proportional to divider coefficient value) LIQUID_VCO_DIRECT } liquid_ncotype; #define LIQUID_NCO_MANGLE_FLOAT(name) LIQUID_CONCAT(nco_crcf, name) // large macro // NCO : name-mangling macro // T : primitive data type // TC : input/output data type #define LIQUID_NCO_DEFINE_API(NCO,T,TC) \ \ /* Numerically-controlled oscillator object */ \ typedef struct NCO(_s) * NCO(); \ \ /* Create nco object with either fixed-point or floating-point phase */ \ /* _type : oscillator type */ \ NCO() NCO(_create)(liquid_ncotype _type); \ \ /* Copy object including all internal objects and state */ \ NCO() NCO(_copy)(NCO() _q); \ \ /* Destroy nco object, freeing all internally allocated memory */ \ int NCO(_destroy)(NCO() _q); \ \ /* Print nco object internals to stdout */ \ int NCO(_print)(NCO() _q); \ \ /* Set phase/frequency to zero and reset the phase-locked loop filter */ \ /* state */ \ int NCO(_reset)(NCO() _q); \ \ /* Get frequency of nco object in radians per sample */ \ T NCO(_get_frequency)(NCO() _q); \ \ /* Set frequency of nco object in radians per sample */ \ /* _q : nco object */ \ /* _dtheta : input frequency [radians/sample] */ \ int NCO(_set_frequency)(NCO() _q, \ T _dtheta); \ \ /* Adjust frequency of nco object by a step size in radians per sample */ \ /* _q : nco object */ \ /* _step : input frequency step [radians/sample] */ \ int NCO(_adjust_frequency)(NCO() _q, \ T _step); \ \ /* Get phase of nco object in radians */ \ T NCO(_get_phase)(NCO() _q); \ \ /* Set phase of nco object in radians */ \ /* _q : nco object */ \ /* _phi : input phase of nco object [radians] */ \ int NCO(_set_phase)(NCO() _q, \ T _phi); \ \ /* Adjust phase of nco object by a step of \(\Delta \phi\) radians */ \ /* _q : nco object */ \ /* _dphi : input nco object phase adjustment [radians] */ \ int NCO(_adjust_phase)(NCO() _q, \ T _dphi); \ \ /* Get frequency of nco object as fraction of sample rate (n/m) */ \ /* _q : nco object */ \ /* _n : pointer to output multiplier coefficient (normalized) */ \ /* _m : pointer to output divider coefficient (normalized) */ \ void NCO(_get_vcodirect_frequency)(NCO() _q, \ int* _n, \ unsigned int* _m); \ \ /* Set frequency of nco object as fraction of sample rate (n/m) */ \ /* _q : nco object */ \ /* _n : input multiplier coefficient */ \ /* _m : input divider coefficient */ \ void NCO(_set_vcodirect_frequency)(NCO() _q, \ int _n, \ unsigned int _m); \ \ /* Increment phase by internal phase step (frequency) */ \ int NCO(_step)(NCO() _q); \ \ /* Compute sine output given internal phase */ \ T NCO(_sin)(NCO() _q); \ \ /* Compute cosine output given internal phase */ \ T NCO(_cos)(NCO() _q); \ \ /* Compute sine and cosine outputs given internal phase */ \ /* _q : nco object */ \ /* _s : output sine component of phase */ \ /* _c : output cosine component of phase */ \ int NCO(_sincos)(NCO() _q, \ T * _s, \ T * _c); \ \ /* Compute complex exponential output given internal phase */ \ /* _q : nco object */ \ /* _y : output complex exponential */ \ int NCO(_cexpf)(NCO() _q, \ TC * _y); \ \ /* Set bandwidth of internal phase-locked loop */ \ /* _q : nco object */ \ /* _bw : input phase-locked loop bandwidth, _bw >= 0 */ \ int NCO(_pll_set_bandwidth)(NCO() _q, \ T _bw); \ \ /* Step internal phase-locked loop given input phase error, adjusting */ \ /* internal phase and frequency proportional to coefficients defined by */ \ /* internal PLL bandwidth */ \ /* _q : nco object */ \ /* _dphi : input phase-locked loop phase error */ \ int NCO(_pll_step)(NCO() _q, \ T _dphi); \ \ /* Rotate input sample up by nco angle. */ \ /* Note that this does not adjust the internal phase or frequency. */ \ /* _q : nco object */ \ /* _x : input complex sample */ \ /* _y : pointer to output sample location */ \ int NCO(_mix_up)(NCO() _q, \ TC _x, \ TC * _y); \ \ /* Rotate input sample down by nco angle. */ \ /* Note that this does not adjust the internal phase or frequency. */ \ /* _q : nco object */ \ /* _x : input complex sample */ \ /* _y : pointer to output sample location */ \ int NCO(_mix_down)(NCO() _q, \ TC _x, \ TC * _y); \ \ /* Rotate input vector up by NCO angle (stepping) */ \ /* Note that this *does* adjust the internal phase as the signal steps */ \ /* through each input sample. */ \ /* _q : nco object */ \ /* _x : array of input samples, [size: _n x 1] */ \ /* _y : array of output samples, [size: _n x 1] */ \ /* _n : number of input (and output) samples */ \ int NCO(_mix_block_up)(NCO() _q, \ TC * _x, \ TC * _y, \ unsigned int _n); \ \ /* Rotate input vector down by NCO angle (stepping) */ \ /* Note that this *does* adjust the internal phase as the signal steps */ \ /* through each input sample. */ \ /* _q : nco object */ \ /* _x : array of input samples, [size: _n x 1] */ \ /* _y : array of output samples, [size: _n x 1] */ \ /* _n : number of input (and output) samples */ \ int NCO(_mix_block_down)(NCO() _q, \ TC * _x, \ TC * _y, \ unsigned int _n); \ // Define nco APIs LIQUID_NCO_DEFINE_API(LIQUID_NCO_MANGLE_FLOAT, float, liquid_float_complex) // nco utilities // unwrap phase of array (basic) void liquid_unwrap_phase(float * _theta, unsigned int _n); // unwrap phase of array (advanced) void liquid_unwrap_phase2(float * _theta, unsigned int _n); #define SYNTH_MANGLE_FLOAT(name) LIQUID_CONCAT(synth_crcf, name) // large macro // SYNTH : name-mangling macro // T : primitive data type // TC : input/output data type #define LIQUID_SYNTH_DEFINE_API(SYNTH,T,TC) \ \ /* Numerically-controlled synthesizer (direct digital synthesis) */ \ /* with internal phase-locked loop (pll) implementation */ \ typedef struct SYNTH(_s) * SYNTH(); \ \ SYNTH() SYNTH(_create)(const TC *_table, unsigned int _length); \ void SYNTH(_destroy)(SYNTH() _q); \ \ void SYNTH(_reset)(SYNTH() _q); \ \ /* get/set/adjust internal frequency/phase */ \ T SYNTH(_get_frequency)( SYNTH() _q); \ void SYNTH(_set_frequency)( SYNTH() _q, T _f); \ void SYNTH(_adjust_frequency)(SYNTH() _q, T _df); \ T SYNTH(_get_phase)( SYNTH() _q); \ void SYNTH(_set_phase)( SYNTH() _q, T _phi); \ void SYNTH(_adjust_phase)( SYNTH() _q, T _dphi); \ \ unsigned int SYNTH(_get_length)(SYNTH() _q); \ TC SYNTH(_get_current)(SYNTH() _q); \ TC SYNTH(_get_half_previous)(SYNTH() _q); \ TC SYNTH(_get_half_next)(SYNTH() _q); \ \ void SYNTH(_step)(SYNTH() _q); \ \ /* pll : phase-locked loop */ \ void SYNTH(_pll_set_bandwidth)(SYNTH() _q, T _bandwidth); \ void SYNTH(_pll_step)(SYNTH() _q, T _dphi); \ \ /* Rotate input sample up by SYNTH angle (no stepping) */ \ void SYNTH(_mix_up)(SYNTH() _q, TC _x, TC *_y); \ \ /* Rotate input sample down by SYNTH angle (no stepping) */ \ void SYNTH(_mix_down)(SYNTH() _q, TC _x, TC *_y); \ \ /* Rotate input vector up by SYNTH angle (stepping) */ \ void SYNTH(_mix_block_up)(SYNTH() _q, \ TC *_x, \ TC *_y, \ unsigned int _N); \ \ /* Rotate input vector down by SYNTH angle (stepping) */ \ void SYNTH(_mix_block_down)(SYNTH() _q, \ TC *_x, \ TC *_y, \ unsigned int _N); \ \ void SYNTH(_spread)(SYNTH() _q, \ TC _x, \ TC *_y); \ \ void SYNTH(_despread)(SYNTH() _q, \ TC *_x, \ TC *_y); \ \ void SYNTH(_despread_triple)(SYNTH() _q, \ TC *_x, \ TC *_early, \ TC *_punctual, \ TC *_late); \ // Define synth APIs LIQUID_SYNTH_DEFINE_API(SYNTH_MANGLE_FLOAT, float, liquid_float_complex) // // MODULE : optimization // // utility function pointer definition typedef float (*utility_function)(void * _userdata, float * _v, unsigned int _n); // One-dimensional utility function pointer definition typedef float (*liquid_utility_1d)(float _v, void * _userdata); // n-dimensional Rosenbrock utility function (minimum at _v = {1,1,1...} // _userdata : user-defined data structure (convenience) // _v : input vector, [size: _n x 1] // _n : input vector size float liquid_rosenbrock(void * _userdata, float * _v, unsigned int _n); // n-dimensional inverse Gauss utility function (minimum at _v = {0,0,0...} // _userdata : user-defined data structure (convenience) // _v : input vector, [size: _n x 1] // _n : input vector size float liquid_invgauss(void * _userdata, float * _v, unsigned int _n); // n-dimensional multimodal utility function (minimum at _v = {0,0,0...} // _userdata : user-defined data structure (convenience) // _v : input vector, [size: _n x 1] // _n : input vector size float liquid_multimodal(void * _userdata, float * _v, unsigned int _n); // n-dimensional spiral utility function (minimum at _v = {0,0,0...} // _userdata : user-defined data structure (convenience) // _v : input vector, [size: _n x 1] // _n : input vector size float liquid_spiral(void * _userdata, float * _v, unsigned int _n); // // Gradient search // #define LIQUID_OPTIM_MINIMIZE (0) #define LIQUID_OPTIM_MAXIMIZE (1) typedef struct gradsearch_s * gradsearch; // Create a gradient search object // _userdata : user data object pointer // _v : array of parameters to optimize // _num_parameters : array length (number of parameters to optimize) // _u : utility function pointer // _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) gradsearch gradsearch_create(void * _userdata, float * _v, unsigned int _num_parameters, utility_function _utility, int _direction); // Destroy a gradsearch object void gradsearch_destroy(gradsearch _q); // Prints current status of search void gradsearch_print(gradsearch _q); // Iterate once float gradsearch_step(gradsearch _q); // Execute the search float gradsearch_execute(gradsearch _q, unsigned int _max_iterations, float _target_utility); // Quadsection search in one dimension... // // // * yn // * yp // * // * y0 // * // +------+------+------+------+--> // [xn x0 xp] typedef struct qs1dsearch_s * qs1dsearch; qs1dsearch qs1dsearch_create(liquid_utility_1d _u, void * _userdata, int _direction); int qs1dsearch_destroy (qs1dsearch _q); qs1dsearch qs1dsearch_copy (qs1dsearch _q); int qs1dsearch_print (qs1dsearch _q); int qs1dsearch_reset (qs1dsearch _q); int qs1dsearch_init (qs1dsearch _q, float _v0); int qs1dsearch_init_direction(qs1dsearch _q, float _v_init, float _step); int qs1dsearch_init_bounds (qs1dsearch _q, float _vn, float _vp); int qs1dsearch_step (qs1dsearch _q); int qs1dsearch_execute (qs1dsearch _q); unsigned int qs1dsearch_get_num_steps (qs1dsearch _q); float qs1dsearch_get_opt_v (qs1dsearch _q); float qs1dsearch_get_opt_u (qs1dsearch _q); // quasi-Newton search typedef struct qnsearch_s * qnsearch; // Create a simple qnsearch object; parameters are specified internally // _userdata : userdata // _v : array of parameters to optimize // _num_parameters : array length // _get_utility : utility function pointer // _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) qnsearch qnsearch_create(void * _userdata, float * _v, unsigned int _num_parameters, utility_function _u, int _direction); // Destroy a qnsearch object int qnsearch_destroy(qnsearch _g); // Prints current status of search int qnsearch_print(qnsearch _g); // Resets internal state int qnsearch_reset(qnsearch _g); // Iterate once int qnsearch_step(qnsearch _g); // Execute the search float qnsearch_execute(qnsearch _g, unsigned int _max_iterations, float _target_utility); // // chromosome (for genetic algorithm search) // typedef struct chromosome_s * chromosome; // create a chromosome object, variable bits/trait chromosome chromosome_create(unsigned int * _bits_per_trait, unsigned int _num_traits); // create a chromosome object, all traits same resolution chromosome chromosome_create_basic(unsigned int _num_traits, unsigned int _bits_per_trait); // create a chromosome object, cloning a parent chromosome chromosome_create_clone(chromosome _parent); // copy existing chromosomes' internal traits (all other internal // parameters must be equal) int chromosome_copy(chromosome _parent, chromosome _child); // Destroy a chromosome object int chromosome_destroy(chromosome _c); // get number of traits in chromosome unsigned int chromosome_get_num_traits(chromosome _c); // Print chromosome values to screen (binary representation) int chromosome_print(chromosome _c); // Print chromosome values to screen (floating-point representation) int chromosome_printf(chromosome _c); // clear chromosome (set traits to zero) int chromosome_reset(chromosome _c); // initialize chromosome on integer values int chromosome_init(chromosome _c, unsigned int * _v); // initialize chromosome on floating-point values int chromosome_initf(chromosome _c, float * _v); // Mutates chromosome _c at _index int chromosome_mutate(chromosome _c, unsigned int _index); // Resulting chromosome _c is a crossover of parents _p1 and _p2 at _threshold int chromosome_crossover(chromosome _p1, chromosome _p2, chromosome _c, unsigned int _threshold); // Initializes chromosome to random value int chromosome_init_random(chromosome _c); // Returns integer representation of chromosome unsigned int chromosome_value(chromosome _c, unsigned int _index); // Returns floating-point representation of chromosome float chromosome_valuef(chromosome _c, unsigned int _index); // // genetic algorithm search // typedef struct gasearch_s * gasearch; typedef float (*gasearch_utility)(void * _userdata, chromosome _c); // Create a simple gasearch object; parameters are specified internally // _utility : chromosome fitness utility function // _userdata : user data, void pointer passed to _get_utility() callback // _parent : initial population parent chromosome, governs precision, etc. // _minmax : search direction gasearch gasearch_create(gasearch_utility _u, void * _userdata, chromosome _parent, int _minmax); // Create a gasearch object, specifying search parameters // _utility : chromosome fitness utility function // _userdata : user data, void pointer passed to _get_utility() callback // _parent : initial population parent chromosome, governs precision, etc. // _minmax : search direction // _population_size : number of chromosomes in population // _mutation_rate : probability of mutating chromosomes gasearch gasearch_create_advanced(gasearch_utility _utility, void * _userdata, chromosome _parent, int _minmax, unsigned int _population_size, float _mutation_rate); // Destroy a gasearch object int gasearch_destroy(gasearch _q); // print search parameter internals int gasearch_print(gasearch _q); // set mutation rate int gasearch_set_mutation_rate(gasearch _q, float _mutation_rate); // set population/selection size // _q : ga search object // _population_size : new population size (number of chromosomes) // _selection_size : selection size (number of parents for new generation) int gasearch_set_population_size(gasearch _q, unsigned int _population_size, unsigned int _selection_size); // Execute the search // _q : ga search object // _max_iterations : maximum number of iterations to run before bailing // _target_utility : target utility float gasearch_run(gasearch _q, unsigned int _max_iterations, float _target_utility); // iterate over one evolution of the search algorithm int gasearch_evolve(gasearch _q); // get optimal chromosome // _q : ga search object // _c : output optimal chromosome // _utility_opt : fitness of _c int gasearch_getopt(gasearch _q, chromosome _c, float * _utility_opt); // // MODULE : quantization // float compress_mulaw(float _x, float _mu); float expand_mulaw(float _x, float _mu); int compress_cf_mulaw(liquid_float_complex _x, float _mu, liquid_float_complex * _y); int expand_cf_mulaw(liquid_float_complex _y, float _mu, liquid_float_complex * _x); //float compress_alaw(float _x, float _a); //float expand_alaw(float _x, float _a); // inline quantizer: 'analog' signal in [-1, 1] unsigned int quantize_adc(float _x, unsigned int _num_bits); float quantize_dac(unsigned int _s, unsigned int _num_bits); // structured quantizer typedef enum { LIQUID_COMPANDER_NONE=0, LIQUID_COMPANDER_LINEAR, LIQUID_COMPANDER_MULAW, LIQUID_COMPANDER_ALAW } liquid_compander_type; #define LIQUID_QUANTIZER_MANGLE_FLOAT(name) LIQUID_CONCAT(quantizerf, name) #define LIQUID_QUANTIZER_MANGLE_CFLOAT(name) LIQUID_CONCAT(quantizercf, name) // large macro // QUANTIZER : name-mangling macro // T : data type #define LIQUID_QUANTIZER_DEFINE_API(QUANTIZER,T) \ \ /* Amplitude quantization object */ \ typedef struct QUANTIZER(_s) * QUANTIZER(); \ \ /* Create quantizer object given compander type, input range, and the */ \ /* number of bits to represent the output */ \ /* _ctype : compander type (linear, mulaw, alaw) */ \ /* _range : maximum abosolute input range (ignored for now) */ \ /* _num_bits : number of bits per sample */ \ QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, \ float _range, \ unsigned int _num_bits); \ \ /* Destroy object, freeing all internally-allocated memory. */ \ int QUANTIZER(_destroy)(QUANTIZER() _q); \ \ /* Print object properties to stdout, including compander type and */ \ /* number of bits per sample */ \ int QUANTIZER(_print)(QUANTIZER() _q); \ \ /* Execute quantizer as analog-to-digital converter, accepting input */ \ /* sample and returning digitized output bits */ \ /* _q : quantizer object */ \ /* _x : input sample */ \ /* _s : output bits */ \ int QUANTIZER(_execute_adc)(QUANTIZER() _q, \ T _x, \ unsigned int * _s); \ \ /* Execute quantizer as digital-to-analog converter, accepting input */ \ /* bits and returning representation of original input sample */ \ /* _q : quantizer object */ \ /* _s : input bits */ \ /* _x : output sample */ \ int QUANTIZER(_execute_dac)(QUANTIZER() _q, \ unsigned int _s, \ T * _x); \ LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_FLOAT, float) LIQUID_QUANTIZER_DEFINE_API(LIQUID_QUANTIZER_MANGLE_CFLOAT, liquid_float_complex) // // MODULE : random (number generators) // // Uniform random number generator, [0,1) float randf(); float randf_pdf(float _x); float randf_cdf(float _x); // Uniform random number generator with arbitrary bounds, [a,b) float randuf(float _a, float _b); float randuf_pdf(float _x, float _a, float _b); float randuf_cdf(float _x, float _a, float _b); // Gauss random number generator, N(0,1) // f(x) = 1/sqrt(2*pi*sigma^2) * exp{-(x-eta)^2/(2*sigma^2)} // // where // eta = mean // sigma = standard deviation // float randnf(); void awgn(float *_x, float _nstd); void crandnf(liquid_float_complex *_y); void cawgn(liquid_float_complex *_x, float _nstd); float randnf_pdf(float _x, float _eta, float _sig); float randnf_cdf(float _x, float _eta, float _sig); // Exponential // f(x) = lambda exp{ -lambda x } // where // lambda = spread parameter, lambda > 0 // x >= 0 float randexpf(float _lambda); float randexpf_pdf(float _x, float _lambda); float randexpf_cdf(float _x, float _lambda); // Weibull // f(x) = (a/b) (x/b)^(a-1) exp{ -(x/b)^a } // where // a = alpha : shape parameter // b = beta : scaling parameter // g = gamma : location (threshold) parameter // float randweibf(float _alpha, float _beta, float _gamma); float randweibf_pdf(float _x, float _a, float _b, float _g); float randweibf_cdf(float _x, float _a, float _b, float _g); // Gamma // x^(a-1) exp(-x/b) // f(x) = ------------------- // Gamma(a) b^a // where // a = alpha : shape parameter, a > 0 // b = beta : scale parameter, b > 0 // Gamma(z) = regular gamma function // x >= 0 float randgammaf(float _alpha, float _beta); float randgammaf_pdf(float _x, float _alpha, float _beta); float randgammaf_cdf(float _x, float _alpha, float _beta); // Nakagami-m // f(x) = (2/Gamma(m)) (m/omega)^m x^(2m-1) exp{-(m/omega)x^2} // where // m : shape parameter, m >= 0.5 // omega : spread parameter, omega > 0 // Gamma(z): regular complete gamma function // x >= 0 float randnakmf(float _m, float _omega); float randnakmf_pdf(float _x, float _m, float _omega); float randnakmf_cdf(float _x, float _m, float _omega); // Rice-K // f(x) = (x/sigma^2) exp{ -(x^2+s^2)/(2sigma^2) } I0( x s / sigma^2 ) // where // s = sqrt( omega*K/(K+1) ) // sigma = sqrt(0.5 omega/(K+1)) // and // K = shape parameter // omega = spread parameter // I0 = modified Bessel function of the first kind // x >= 0 float randricekf(float _K, float _omega); float randricekf_cdf(float _x, float _K, float _omega); float randricekf_pdf(float _x, float _K, float _omega); // Data scrambler : whiten data sequence void scramble_data(unsigned char * _x, unsigned int _len); void unscramble_data(unsigned char * _x, unsigned int _len); void unscramble_data_soft(unsigned char * _x, unsigned int _len); // // MODULE : sequence // // Binary sequence (generic) typedef struct bsequence_s * bsequence; // Create a binary sequence of a specific length (number of bits) bsequence bsequence_create(unsigned int num_bits); // Free memory in a binary sequence int bsequence_destroy(bsequence _bs); // Clear binary sequence (set to 0's) int bsequence_reset(bsequence _bs); // initialize sequence on external array int bsequence_init(bsequence _bs, unsigned char * _v); // Print sequence to the screen int bsequence_print(bsequence _bs); // Push bit into to back of a binary sequence int bsequence_push(bsequence _bs, unsigned int _bit); // circular shift (left) int bsequence_circshift(bsequence _bs); // Correlate two binary sequences together int bsequence_correlate(bsequence _bs1, bsequence _bs2); // compute the binary addition of two bit sequences int bsequence_add(bsequence _bs1, bsequence _bs2, bsequence _bs3); // compute the binary multiplication of two bit sequences int bsequence_mul(bsequence _bs1, bsequence _bs2, bsequence _bs3); // accumulate the 1's in a binary sequence unsigned int bsequence_accumulate(bsequence _bs); // accessor functions unsigned int bsequence_get_length(bsequence _bs); unsigned int bsequence_index(bsequence _bs, unsigned int _i); // Complementary codes // initialize two sequences to complementary codes. sequences must // be of length at least 8 and a power of 2 (e.g. 8, 16, 32, 64,...) // _a : sequence 'a' (bsequence object) // _b : sequence 'b' (bsequence object) int bsequence_create_ccodes(bsequence _a, bsequence _b); // M-Sequence // default m-sequence generators: g (hex) m n #define LIQUID_MSEQUENCE_GENPOLY_M2 0x00000003 // 2 3 #define LIQUID_MSEQUENCE_GENPOLY_M3 0x00000006 // 3 7 #define LIQUID_MSEQUENCE_GENPOLY_M4 0x0000000c // 4 15 #define LIQUID_MSEQUENCE_GENPOLY_M5 0x00000014 // 5 31 #define LIQUID_MSEQUENCE_GENPOLY_M6 0x00000030 // 6 63 #define LIQUID_MSEQUENCE_GENPOLY_M7 0x00000060 // 7 127 #define LIQUID_MSEQUENCE_GENPOLY_M8 0x000000b8 // 8 255 #define LIQUID_MSEQUENCE_GENPOLY_M9 0x00000110 // 9 511 #define LIQUID_MSEQUENCE_GENPOLY_M10 0x00000240 // 10 1,023 #define LIQUID_MSEQUENCE_GENPOLY_M11 0x00000500 // 11 2,047 #define LIQUID_MSEQUENCE_GENPOLY_M12 0x00000e08 // 12 4,095 #define LIQUID_MSEQUENCE_GENPOLY_M13 0x00001c80 // 13 8,191 #define LIQUID_MSEQUENCE_GENPOLY_M14 0x00003802 // 14 16,383 #define LIQUID_MSEQUENCE_GENPOLY_M15 0x00006000 // 15 32,767 #define LIQUID_MSEQUENCE_GENPOLY_M16 0x0000d008 // 16 65,535 #define LIQUID_MSEQUENCE_GENPOLY_M17 0x00012000 // 17 131,071 #define LIQUID_MSEQUENCE_GENPOLY_M18 0x00020400 // 18 262,143 #define LIQUID_MSEQUENCE_GENPOLY_M19 0x00072000 // 19 524,287 #define LIQUID_MSEQUENCE_GENPOLY_M20 0x00090000 // 20 1,048,575 #define LIQUID_MSEQUENCE_GENPOLY_M21 0x00140000 // 21 2,097,151 #define LIQUID_MSEQUENCE_GENPOLY_M22 0x00300000 // 22 4,194,303 #define LIQUID_MSEQUENCE_GENPOLY_M23 0x00420000 // 23 8,388,607 #define LIQUID_MSEQUENCE_GENPOLY_M24 0x00e10000 // 24 16,777,215 #define LIQUID_MSEQUENCE_GENPOLY_M25 0x01000004 // 25 33,554,431 #define LIQUID_MSEQUENCE_GENPOLY_M26 0x02000023 // 26 67,108,863 #define LIQUID_MSEQUENCE_GENPOLY_M27 0x04000013 // 27 134,217,727 #define LIQUID_MSEQUENCE_GENPOLY_M28 0x08000004 // 28 268,435,455 #define LIQUID_MSEQUENCE_GENPOLY_M29 0x10000002 // 29 536,870,911 #define LIQUID_MSEQUENCE_GENPOLY_M30 0x20000029 // 30 1,073,741,823 #define LIQUID_MSEQUENCE_GENPOLY_M31 0x40000004 // 31 2,147,483,647 typedef struct msequence_s * msequence; // create a maximal-length sequence (m-sequence) object with // an internal shift register length of _m bits. // _m : generator polynomial length, sequence length is (2^m)-1 // _g : generator polynomial, starting with most-significant bit // _a : initial shift register state, default: 000...001 msequence msequence_create(unsigned int _m, unsigned int _g, unsigned int _a); // Copy maximal-length sequence (m-sequence) object msequence msequence_copy(msequence q_orig); // create a maximal-length sequence (m-sequence) object from a generator polynomial msequence msequence_create_genpoly(unsigned int _g); // creates a default maximal-length sequence msequence msequence_create_default(unsigned int _m); // destroy an msequence object, freeing all internal memory int msequence_destroy(msequence _m); // prints the sequence's internal state to the screen int msequence_print(msequence _m); // advance msequence on shift register, returning output bit unsigned int msequence_advance(msequence _ms); // generate pseudo-random symbol from shift register by // advancing _bps bits and returning compacted symbol // _ms : m-sequence object // _bps : bits per symbol of output unsigned int msequence_generate_symbol(msequence _ms, unsigned int _bps); // reset msequence shift register to original state, typically '1' int msequence_reset(msequence _ms); // initialize a bsequence object on an msequence object // _bs : bsequence object // _ms : msequence object int bsequence_init_msequence(bsequence _bs, msequence _ms); // get the length of the generator polynomial, g (m) unsigned int msequence_get_genpoly_length(msequence _ms); // get the length of the sequence (n=2^m-1) unsigned int msequence_get_length(msequence _ms); // get the generator polynomial, g unsigned int msequence_get_genpoly(msequence _ms); // get the internal state of the sequence unsigned int msequence_get_state(msequence _ms); // set the internal state of the sequence int msequence_set_state(msequence _ms, unsigned int _a); // measure the period the shift register (should be 2^m-1 with a proper generator polynomial) unsigned int msequence_measure_period(msequence _ms); // measure the period of a generator polynomial unsigned int msequence_genpoly_period(unsigned int _g); // // MODULE : utility // // allocate memory and copy from original location // _orig : pointer to original memory array // _num : number of original elements // _size : size of each element void * liquid_malloc_copy(void * _orig, unsigned int _num, unsigned int _size); // pack binary array with symbol(s) // _src : source array, [size: _n x 1] // _n : input source array length // _k : bit index to write in _src // _b : number of bits in input symbol // _sym_in : input symbol int liquid_pack_array(unsigned char * _src, unsigned int _n, unsigned int _k, unsigned int _b, unsigned char _sym_in); // unpack symbols from binary array // _src : source array, [size: _n x 1] // _n : input source array length // _k : bit index to write in _src // _b : number of bits in output symbol // _sym_out : output symbol int liquid_unpack_array(unsigned char * _src, unsigned int _n, unsigned int _k, unsigned int _b, unsigned char * _sym_out); // pack one-bit symbols into bytes (8-bit symbols) // _sym_in : input symbols array, [size: _sym_in_len x 1] // _sym_in_len : number of input symbols // _sym_out : output symbols // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_pack_bytes(unsigned char * _sym_in, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_len, unsigned int * _num_written); // unpack 8-bit symbols (full bytes) into one-bit symbols // _sym_in : input symbols array, [size: _sym_in_len x 1] // _sym_in_len : number of input symbols // _sym_out : output symbols array // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_unpack_bytes(unsigned char * _sym_in, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_len, unsigned int * _num_written); // repack bytes with arbitrary symbol sizes // _sym_in : input symbols array, [size: _sym_in_len x 1] // _sym_in_bps : number of bits per input symbol // _sym_in_len : number of input symbols // _sym_out : output symbols array // _sym_out_bps : number of bits per output symbol // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_repack_bytes(unsigned char * _sym_in, unsigned int _sym_in_bps, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_bps, unsigned int _sym_out_len, unsigned int * _num_written); // shift array to the left _b bits, filling in zeros // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_lbshift(unsigned char * _src, unsigned int _n, unsigned int _b); // shift array to the right _b bits, filling in zeros // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_rbshift(unsigned char * _src, unsigned int _n, unsigned int _b); // circular shift array to the left _b bits // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_lbcircshift(unsigned char * _src, unsigned int _n, unsigned int _b); // circular shift array to the right _b bits // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_rbcircshift(unsigned char * _src, unsigned int _n, unsigned int _b); // shift array to the left _b bytes, filling in zeros // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_lshift(unsigned char * _src, unsigned int _n, unsigned int _b); // shift array to the right _b bytes, filling in zeros // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_rshift(unsigned char * _src, unsigned int _n, unsigned int _b); // circular shift array to the left _b bytes // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_lcircshift(unsigned char * _src, unsigned int _n, unsigned int _b); // circular shift array to the right _b bytes // _src : source address, [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_rcircshift(unsigned char * _src, unsigned int _n, unsigned int _b); // Count the number of ones in an integer unsigned int liquid_count_ones(unsigned int _x); // count number of ones in an integer, modulo 2 unsigned int liquid_count_ones_mod2(unsigned int _x); // compute bindary dot-product between two integers unsigned int liquid_bdotprod(unsigned int _x, unsigned int _y); // Count leading zeros in an integer unsigned int liquid_count_leading_zeros(unsigned int _x); // Most-significant bit index unsigned int liquid_msb_index(unsigned int _x); // Print string of bits to stdout int liquid_print_bitstring(unsigned int _x, unsigned int _n); // reverse byte, word, etc. unsigned char liquid_reverse_byte( unsigned char _x); unsigned int liquid_reverse_uint16(unsigned int _x); unsigned int liquid_reverse_uint24(unsigned int _x); unsigned int liquid_reverse_uint32(unsigned int _x); // get scale for constant, particularly for plotting purposes // _val : input value (e.g. 100e6) // _unit : output unit character (e.g. 'M') // _scale : output scale (e.g. 1e-6) int liquid_get_scale(float _val, char * _unit, float * _scale); // // MODULE : vector // #define LIQUID_VECTOR_MANGLE_RF(name) LIQUID_CONCAT(liquid_vectorf, name) #define LIQUID_VECTOR_MANGLE_CF(name) LIQUID_CONCAT(liquid_vectorcf,name) // large macro // VECTOR : name-mangling macro // T : data type // TP : data type (primitive) #define LIQUID_VECTOR_DEFINE_API(VECTOR,T,TP) \ \ /* Initialize vector with scalar: x[i] = c (scalar) */ \ void VECTOR(_init)(T _c, \ T * _x, \ unsigned int _n); \ \ /* Add each element pointwise: z[i] = x[i] + y[i] */ \ void VECTOR(_add)(T * _x, \ T * _y, \ unsigned int _n, \ T * _z); \ \ /* Add scalar to each element: y[i] = x[i] + c */ \ void VECTOR(_addscalar)(T * _x, \ unsigned int _n, \ T _c, \ T * _y); \ \ /* Multiply each element pointwise: z[i] = x[i] * y[i] */ \ void VECTOR(_mul)(T * _x, \ T * _y, \ unsigned int _n, \ T * _z); \ \ /* Multiply each element with scalar: y[i] = x[i] * c */ \ void VECTOR(_mulscalar)(T * _x, \ unsigned int _n, \ T _c, \ T * _y); \ \ /* Compute complex phase rotation: x[i] = exp{j theta[i]} */ \ void VECTOR(_cexpj)(TP * _theta, \ unsigned int _n, \ T * _x); \ \ /* Compute angle of each element: theta[i] = arg{ x[i] } */ \ void VECTOR(_carg)(T * _x, \ unsigned int _n, \ TP * _theta); \ \ /* Compute absolute value of each element: y[i] = |x[i]| */ \ void VECTOR(_abs)(T * _x, \ unsigned int _n, \ TP * _y); \ \ /* Compute sum of squares: sum{ |x|^2 } */ \ TP VECTOR(_sumsq)(T * _x, \ unsigned int _n); \ \ /* Compute l-2 norm: sqrt{ sum{ |x|^2 } } */ \ TP VECTOR(_norm)(T * _x, \ unsigned int _n); \ \ /* Compute l-p norm: { sum{ |x|^p } }^(1/p) */ \ TP VECTOR(_pnorm)(T * _x, \ unsigned int _n, \ TP _p); \ \ /* Scale vector elements by l-2 norm: y[i] = x[i]/norm(x) */ \ void VECTOR(_normalize)(T * _x, \ unsigned int _n, \ T * _y); \ LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_RF, float, float) LIQUID_VECTOR_DEFINE_API(LIQUID_VECTOR_MANGLE_CF, liquid_float_complex, float) // // mixed types // #if 0 void liquid_vectorf_add(float * _a, float * _b, unsigned int _n, float * _c); #endif #ifdef __cplusplus } //extern "C" #endif // __cplusplus #endif // __LIQUID_H__ liquid-dsp-1.7.0/include/liquid.internal.h000066400000000000000000002112021474751757600205150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // liquid.internal.h // // Internal header file for liquid DSP for SDR // // This file includes function declarations which are intended // for internal use // #ifndef __LIQUID_INTERNAL_H__ #define __LIQUID_INTERNAL_H__ // Configuration file #include "config.h" #include #include #include "liquid.h" #if defined HAVE_FEC_H && defined HAVE_LIBFEC # define LIBFEC_ENABLED 1 #endif // report error int liquid_error_fl(int _code, const char * _file, int _line, const char * _format, ...); // report error specifically for invalid object configuration void * liquid_error_config_fl(const char * _file, int _line, const char * _format, ...); // macro to get file name and line number for source of error #define liquid_error(code, format, ...) \ liquid_error_fl(code, __FILE__, __LINE__, format, ##__VA_ARGS__); // macro to get file name and line number for source of error (invalid object) #define liquid_error_config(format, ...) \ liquid_error_config_fl(__FILE__, __LINE__, format, ##__VA_ARGS__); // // Debugging macros // #define DEBUG_PRINTF_FLOAT(F,STR,I,V) \ fprintf(F,"%s(%4u) = %12.4e;\n",STR,I+1,V) #define DEBUG_PRINTF_CFLOAT(F,STR,I,V) \ fprintf(F,"%s(%4u) = %12.4e +j*%12.4e;\n",STR,I+1,crealf(V),cimagf(V)) #define PRINTVAL_FLOAT(X,F) printf(#F,crealf(X)); #define PRINTVAL_CFLOAT(X,F) printf(#F "+j*" #F, crealf(X), cimagf(X)); // // MODULE : agc // // // MODULE : audio // // // MODULE : buffer // // // MODULE : dotprod // // // MODULE : fec (forward error-correction) // // fec : basic object struct fec_s { // common fec_scheme scheme; //unsigned int dec_msg_len; //unsigned int enc_msg_len; float rate; // lengths: convolutional, Reed-Solomon unsigned int num_dec_bytes; unsigned int num_enc_bytes; // convolutional : internal memory structure unsigned char * enc_bits; void * vp; // decoder object int * poly; // polynomial unsigned int R; // primitive rate, inverted (e.g. R=3 for 1/3) unsigned int K; // constraint length unsigned int P; // puncturing rate (e.g. p=3 for 3/4) int * puncturing_matrix; // viterbi decoder function pointers void*(*create_viterbi)(int); //void (*set_viterbi_polynomial)(int*); int (*init_viterbi)(void*,int); int (*update_viterbi_blk)(void*,unsigned char*,int); int (*chainback_viterbi)(void*,unsigned char*,unsigned int,unsigned int); void (*delete_viterbi)(void*); // Reed-Solomon int symsize; // symbol size (bits per symbol) int genpoly; // generator polynomial int fcs; // int prim; // int nroots; // number of roots in the polynomial //int ntrials; // unsigned int rspad; // number of implicit padded symbols int nn; // 2^symsize - 1 int kk; // nn - nroots void * rs; // Reed-Solomon internal object // Reed-Solomon decoder unsigned int num_blocks; // number of blocks: ceil(dec_msg_len / nn) unsigned int dec_block_len; // number of decoded bytes per block: unsigned int enc_block_len; // number of encoded bytes per block: unsigned int res_block_len; // residual bytes in last block unsigned int pad; // padding for each block unsigned char * tblock; // decoder input sequence, [size: 1 x n] int * errlocs; // error locations, [size: 1 x n] int * derrlocs; // decoded error locations, [size: 1 x n] int erasures; // number of erasures // encode function pointer int (*encode_func)(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); // decode function pointer int (*decode_func)(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // decode function pointer (soft decision) int (*decode_soft_func)(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); }; // simple type testing int fec_scheme_is_convolutional(fec_scheme _scheme); int fec_scheme_is_punctured(fec_scheme _scheme); int fec_scheme_is_reedsolomon(fec_scheme _scheme); int fec_scheme_is_hamming(fec_scheme _scheme); int fec_scheme_is_repeat(fec_scheme _scheme); // Pass fec fec_pass_create(void *_opts); int fec_pass_destroy(fec _q); int fec_pass_print(fec _q); int fec_pass_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_pass_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // Repeat (3) fec fec_rep3_create(void *_opts); int fec_rep3_destroy(fec _q); int fec_rep3_print(fec _q); int fec_rep3_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_rep3_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_rep3_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // Repeat (5) fec fec_rep5_create(void *_opts); int fec_rep5_destroy(fec _q); int fec_rep5_print(fec _q); int fec_rep5_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_rep5_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_rep5_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // Hamming(7,4) extern unsigned char hamming74_enc_gentab[16]; extern unsigned char hamming74_dec_gentab[128]; fec fec_hamming74_create(void *_opts); int fec_hamming74_destroy(fec _q); int fec_hamming74_print(fec _q); int fec_hamming74_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_hamming74_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_hamming74_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // soft decoding of one symbol unsigned char fecsoft_hamming74_decode(unsigned char * _soft_bits); // Hamming(8,4) extern unsigned char hamming84_enc_gentab[16]; extern unsigned char hamming84_dec_gentab[256]; fec fec_hamming84_create(void *_opts); int fec_hamming84_destroy(fec _q); int fec_hamming84_print(fec _q); int fec_hamming84_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_hamming84_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_hamming84_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // soft decoding of one symbol unsigned char fecsoft_hamming84_decode(unsigned char * _soft_bits); // Hamming(12,8) unsigned int fec_hamming128_encode_symbol(unsigned int _sym_dec); unsigned int fec_hamming128_decode_symbol(unsigned int _sym_enc); extern unsigned short int hamming128_enc_gentab[256]; // encoding table fec fec_hamming128_create(void *_opts); int fec_hamming128_destroy(fec _q); int fec_hamming128_print(fec _q); int fec_hamming128_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_hamming128_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_hamming128_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // soft decoding of one symbol unsigned int fecsoft_hamming128_decode(unsigned char * _soft_bits); extern unsigned char fecsoft_hamming128_n3[256][17]; unsigned int fecsoft_hamming128_decode_n3(unsigned char * _soft_bits); // Hamming(15,11) unsigned int fec_hamming1511_encode_symbol(unsigned int _sym_dec); unsigned int fec_hamming1511_decode_symbol(unsigned int _sym_enc); // Hamming(31,26) unsigned int fec_hamming3126_encode_symbol(unsigned int _sym_dec); unsigned int fec_hamming3126_decode_symbol(unsigned int _sym_enc); // Golay(24,12) unsigned int fec_golay2412_encode_symbol(unsigned int _sym_dec); unsigned int fec_golay2412_decode_symbol(unsigned int _sym_enc); extern unsigned int golay2412_P[12]; extern unsigned int golay2412_Gt[24]; extern unsigned int golay2412_H[12]; // multiply input vector with matrix unsigned int golay2412_matrix_mul(unsigned int _v, unsigned int * _A, unsigned int _n); // search for p[i] such that w(v+p[i]) <= 2, return -1 on fail int golay2412_parity_search(unsigned int _v); fec fec_golay2412_create(void *_opts); int fec_golay2412_destroy(fec _q); int fec_golay2412_print(fec _q); int fec_golay2412_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_golay2412_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // SEC-DED (22,16) // compute parity on 16-bit input unsigned char fec_secded2216_compute_parity(unsigned char * _m); // compute syndrome on 22-bit input unsigned char fec_secded2216_compute_syndrome(unsigned char * _v); // encode symbol // _sym_dec : decoded symbol, [size: 2 x 1] // _sym_enc : encoded symbol, [size: 3 x 1], _sym_enc[0] has only 6 bits int fec_secded2216_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc); // decode symbol, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol, [size: 3 x 1], _sym_enc[0] has only 6 bits // _sym_dec : decoded symbol, [size: 2 x 1] int fec_secded2216_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec); // estimate error vector, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol, [size: 3 x 1], _sym_enc[0] has only 6 bits // _e_hat : estimated error vector, [size: 3 x 1] int fec_secded2216_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat); // parity matrix [6 x 16 bits], [6 x 2 bytes] extern unsigned char secded2216_P[12]; // syndrome vectors of errors with weight exactly equal to 1 extern unsigned char secded2216_syndrome_w1[22]; fec fec_secded2216_create(void *_opts); int fec_secded2216_destroy(fec _q); int fec_secded2216_print(fec _q); int fec_secded2216_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_secded2216_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // SEC-DED (39,32) // compute parity on 32-bit input unsigned char fec_secded3932_compute_parity(unsigned char * _m); // compute syndrome on 39-bit input unsigned char fec_secded3932_compute_syndrome(unsigned char * _v); // encode symbol // _sym_dec : decoded symbol, [size: 4 x 1] // _sym_enc : encoded symbol, [size: 5 x 1], _sym_enc[0] has only 7 bits int fec_secded3932_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc); // estimate error vector, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol, [size: 5 x 1], _sym_enc[0] has only 7 bits // _e_hat : estimated error vector, [size: 5 x 1] int fec_secded3932_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat); // decode symbol, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol (_sym_enc[0] has only 7 bits), [size: 5 x 1] // _sym_dec : decoded symbol, [size: 4 x 1] int fec_secded3932_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec); // parity matrix [7 x 32 bits], [7 x 4 bytes] extern unsigned char secded3932_P[28]; // syndrome vectors of errors with weight exactly equal to 1 extern unsigned char secded3932_syndrome_w1[39]; fec fec_secded3932_create(void *_opts); int fec_secded3932_destroy(fec _q); int fec_secded3932_print(fec _q); int fec_secded3932_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_secded3932_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // SEC-DED (72,64) // compute parity byte on 64-byte input unsigned char fec_secded7264_compute_parity(unsigned char * _v); // compute syndrome on 72-bit input unsigned char fec_secded7264_compute_syndrome(unsigned char * _v); // encode symbol // _sym_dec : input symbol, [size: 8 x 1] // _sym_enc : input symbol, [size: 9 x 1] int fec_secded7264_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc); // estimate error vector, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol, [size: 9 x 1] // _e_hat : estimated error vector, [size: 9 x 1] int fec_secded7264_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat); // decode symbol, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : input symbol, [size: 8 x 1] // _sym_dec : input symbol, [size: 9 x 1] int fec_secded7264_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec); extern unsigned char secded7264_P[64]; extern unsigned char secded7264_syndrome_w1[72]; fec fec_secded7264_create(void *_opts); int fec_secded7264_destroy(fec _q); int fec_secded7264_print(fec _q); int fec_secded7264_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_secded7264_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // Convolutional: r1/2 K=7 // r1/2 K=9 // r1/3 K=9 // r1/6 K=15 // compute encoded message length for block codes // _dec_msg_len : decoded message length (bytes) // _m : input block size (bits) // _k : output block size (bits) unsigned int fec_block_get_enc_msg_len(unsigned int _dec_msg_len, unsigned int _m, unsigned int _k); // compute encoded message length for convolutional codes // _dec_msg_len : decoded message length // _K : constraint length // _p : puncturing rate, r = _p / (_p+1) unsigned int fec_conv_get_enc_msg_len(unsigned int _dec_msg_len, unsigned int _K, unsigned int _p); // convolutional code polynomials extern int fec_conv27_poly[2]; extern int fec_conv29_poly[2]; extern int fec_conv39_poly[3]; extern int fec_conv615_poly[6]; // convolutional code puncturing matrices [R x P] extern int fec_conv27p23_matrix[4]; // [2 x 2] extern int fec_conv27p34_matrix[6]; // [2 x 3] extern int fec_conv27p45_matrix[8]; // [2 x 4] extern int fec_conv27p56_matrix[10]; // [2 x 5] extern int fec_conv27p67_matrix[12]; // [2 x 6] extern int fec_conv27p78_matrix[14]; // [2 x 7] extern int fec_conv29p23_matrix[4]; // [2 x 2] extern int fec_conv29p34_matrix[6]; // [2 x 3] extern int fec_conv29p45_matrix[8]; // [2 x 4] extern int fec_conv29p56_matrix[10]; // [2 x 5] extern int fec_conv29p67_matrix[12]; // [2 x 6] extern int fec_conv29p78_matrix[14]; // [2 x 7] fec fec_conv_create(fec_scheme _fs); int fec_conv_destroy(fec _q); int fec_conv_print(fec _q); int fec_conv_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_conv_decode_hard(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_conv_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_conv_decode(fec _q, unsigned char * _msg_dec); int fec_conv_setlength(fec _q, unsigned int _dec_msg_len); // internal initialization methods (sets r, K, viterbi methods) int fec_conv_init_v27(fec _q); int fec_conv_init_v29(fec _q); int fec_conv_init_v39(fec _q); int fec_conv_init_v615(fec _q); // punctured convolutional codes fec fec_conv_punctured_create(fec_scheme _fs); int fec_conv_punctured_destroy(fec _q); int fec_conv_punctured_print(fec _q); int fec_conv_punctured_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_conv_punctured_decode_hard(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_conv_punctured_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); int fec_conv_punctured_setlength(fec _q, unsigned int _dec_msg_len); // internal initialization methods (sets r, K, viterbi methods, // and puncturing matrix) int fec_conv_init_v27p23(fec _q); int fec_conv_init_v27p34(fec _q); int fec_conv_init_v27p45(fec _q); int fec_conv_init_v27p56(fec _q); int fec_conv_init_v27p67(fec _q); int fec_conv_init_v27p78(fec _q); int fec_conv_init_v29p23(fec _q); int fec_conv_init_v29p34(fec _q); int fec_conv_init_v29p45(fec _q); int fec_conv_init_v29p56(fec _q); int fec_conv_init_v29p67(fec _q); int fec_conv_init_v29p78(fec _q); // Reed-Solomon // compute encoded message length for Reed-Solomon codes // _dec_msg_len : decoded message length // _nroots : number of roots in polynomial // _nn : // _kk : unsigned int fec_rs_get_enc_msg_len(unsigned int _dec_msg_len, unsigned int _nroots, unsigned int _nn, unsigned int _kk); fec fec_rs_create(fec_scheme _fs); int fec_rs_destroy(fec _q); int fec_rs_init_p8(fec _q); int fec_rs_setlength(fec _q, unsigned int _dec_msg_len); int fec_rs_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc); int fec_rs_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec); // phi(x) = -logf( tanhf( x/2 ) ) float sumproduct_phi(float _x); // iterate over the sum-product algorithm: // returns 1 if parity checks, 0 otherwise // _m : rows // _n : cols // _H : sparse binary parity check matrix, [size: _m x _n] // _LLR : received signal (soft bits, LLR) [size: _n x 1] // _c_hat : estimated transmitted signal, [size: _n x 1] // _max_steps : maximum number of steps before bailing int fec_sumproduct(unsigned int _m, unsigned int _n, smatrixb _H, float * _LLR, unsigned char * _c_hat, unsigned int _max_steps); // sum-product algorithm, returns 1 if parity checks, 0 otherwise // _m : rows // _n : cols // _H : sparse binary parity check matrix, [size: _m x _n] // _c_hat : estimated transmitted signal, [size: _n x 1] // // internal state arrays // _Lq : [size: _m x _n] // _Lr : [size: _m x _n] // _Lc : [size: _n x 1] // _LQ : [size: _n x 1] // _parity : _H * _c_hat, [size: _m x 1] int fec_sumproduct_step(unsigned int _m, unsigned int _n, smatrixb _H, unsigned char * _c_hat, float * _Lq, float * _Lr, float * _Lc, float * _LQ, unsigned char * _parity); // // packetizer // #define PACKETIZER_VERSION (1) // // MODULE : fft (fast discrete Fourier transform) // // fast fourier transform method typedef enum { LIQUID_FFT_METHOD_UNKNOWN=0, // unknown method LIQUID_FFT_METHOD_RADIX2, // Radix-2 (decimation in time) LIQUID_FFT_METHOD_MIXED_RADIX, // Cooley-Tukey mixed-radix FFT (decimation in time) LIQUID_FFT_METHOD_RADER, // Rader's method for FFTs of prime length LIQUID_FFT_METHOD_RADER2, // Rader's method for FFTs of prime length (alternate) LIQUID_FFT_METHOD_DFT, // regular discrete Fourier transform } liquid_fft_method; // Macro : FFT (internal) // FFT : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_FFT_DEFINE_INTERNAL_API(FFT,T,TC) \ \ /* print plan recursively */ \ int FFT(_print_plan_recursive)(FFT(plan) _q, \ unsigned int _level); \ \ /* type definitions for create/destroy/execute functions */ \ typedef FFT(plan)(FFT(_create_t)) (unsigned int _nfft, \ TC * _x, \ TC * _y, \ int _dir, \ int _flags); \ typedef int (FFT(_destroy_t))(FFT(plan) _q); \ typedef int (FFT(_execute_t))(FFT(plan) _q); \ \ /* FFT create methods */ \ FFT(_create_t) FFT(_create_plan_dft); \ FFT(_create_t) FFT(_create_plan_radix2); \ FFT(_create_t) FFT(_create_plan_mixed_radix); \ FFT(_create_t) FFT(_create_plan_rader); \ FFT(_create_t) FFT(_create_plan_rader2); \ \ /* FFT destroy methods */ \ FFT(_destroy_t) FFT(_destroy_plan_dft); \ FFT(_destroy_t) FFT(_destroy_plan_radix2); \ FFT(_destroy_t) FFT(_destroy_plan_mixed_radix); \ FFT(_destroy_t) FFT(_destroy_plan_rader); \ FFT(_destroy_t) FFT(_destroy_plan_rader2); \ \ /* FFT execute methods */ \ FFT(_execute_t) FFT(_execute_dft); \ FFT(_execute_t) FFT(_execute_radix2); \ FFT(_execute_t) FFT(_execute_mixed_radix); \ FFT(_execute_t) FFT(_execute_rader); \ FFT(_execute_t) FFT(_execute_rader2); \ \ /* specific codelets for small DFTs */ \ FFT(_execute_t) FFT(_execute_dft_2); \ FFT(_execute_t) FFT(_execute_dft_3); \ FFT(_execute_t) FFT(_execute_dft_4); \ FFT(_execute_t) FFT(_execute_dft_5); \ FFT(_execute_t) FFT(_execute_dft_6); \ FFT(_execute_t) FFT(_execute_dft_7); \ FFT(_execute_t) FFT(_execute_dft_8); \ FFT(_execute_t) FFT(_execute_dft_16); \ \ /* additional methods */ \ unsigned int FFT(_estimate_mixed_radix)(unsigned int _nfft); \ \ /* discrete cosine transform (DCT) prototypes */ \ int FFT(_execute_REDFT00)(FFT(plan) _q); /* DCT-I */ \ int FFT(_execute_REDFT10)(FFT(plan) _q); /* DCT-II */ \ int FFT(_execute_REDFT01)(FFT(plan) _q); /* DCT-III */ \ int FFT(_execute_REDFT11)(FFT(plan) _q); /* DCT-IV */ \ \ /* discrete sine transform (DST) prototypes */ \ int FFT(_execute_RODFT00)(FFT(plan) _q); /* DST-I */ \ int FFT(_execute_RODFT10)(FFT(plan) _q); /* DST-II */ \ int FFT(_execute_RODFT01)(FFT(plan) _q); /* DST-III */ \ int FFT(_execute_RODFT11)(FFT(plan) _q); /* DST-IV */ \ \ /* destroy real-to-real one-dimensional plan */ \ int FFT(_destroy_plan_r2r_1d)(FFT(plan) _q); \ \ /* print real-to-real one-dimensional plan */ \ int FFT(_print_plan_r2r_1d)(FFT(plan) _q); \ // determine best FFT method based on size liquid_fft_method liquid_fft_estimate_method(unsigned int _nfft); // is input radix-2? int fft_is_radix2(unsigned int _n); // miscellaneous functions unsigned int fft_reverse_index(unsigned int _i, unsigned int _n); LIQUID_FFT_DEFINE_INTERNAL_API(LIQUID_FFT_MANGLE_FLOAT, float, liquid_float_complex) // Use fftw library if installed (and not overridden with configuration), // otherwise use internal (less efficient) fft library. #if HAVE_FFTW3_H && !defined LIQUID_FFTOVERRIDE # include # define FFT_PLAN fftwf_plan # define FFT_CREATE_PLAN fftwf_plan_dft_1d # define FFT_DESTROY_PLAN fftwf_destroy_plan # define FFT_EXECUTE fftwf_execute # define FFT_DIR_FORWARD FFTW_FORWARD # define FFT_DIR_BACKWARD FFTW_BACKWARD # define FFT_METHOD FFTW_ESTIMATE # define FFT_MALLOC fftwf_malloc # define FFT_FREE fftwf_free #else # define FFT_PLAN fftplan # define FFT_CREATE_PLAN fft_create_plan # define FFT_DESTROY_PLAN fft_destroy_plan # define FFT_EXECUTE fft_execute # define FFT_DIR_FORWARD LIQUID_FFT_FORWARD # define FFT_DIR_BACKWARD LIQUID_FFT_BACKWARD # define FFT_METHOD 0 # define FFT_MALLOC malloc # define FFT_FREE free #endif // // MODULE : filter // // estimate required filter length given transition bandwidth and // stop-band attenuation (algorithm from [Vaidyanathan:1993]) // _df : transition bandwidth (0 < _df < 0.5) // _as : stop-band attenuation [dB] (_as > 0) float estimate_req_filter_len_Kaiser(float _df, float _as); // estimate required filter length given transition bandwidth and // stop-band attenuation (algorithm from [Herrmann:1973]) // _df : transition bandwidth (0 < _df < 0.5) // _as : stop-band attenuation [dB] (_as > 0) float estimate_req_filter_len_Herrmann(float _df, float _as); // firdes : finite impulse response filter design // Find approximate bandwidth adjustment factor rho based on // filter delay and desired excess bandwidth factor. // // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) float rkaiser_approximate_rho(unsigned int _m, float _beta); // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc using the quadratic method. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter, [size: 2*_k*_m+1] // _rho : transition bandwidth adjustment, 0 < _rho < 1 int liquid_firdes_rkaiser_quadratic(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h, float * _rho); // compute filter coefficients and determine resulting ISI // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _rho : transition bandwidth adjustment, 0 < _rho < 1 // _h : filter buffer, [size: 2*_k*_m+1] float liquid_firdes_rkaiser_internal_isi(unsigned int _k, unsigned int _m, float _beta, float _dt, float _rho, float * _h); // Design flipped Nyquist/root-Nyquist filters int liquid_firdes_fnyquist(liquid_firfilt_type _type, int _root, unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // flipped exponential frequency response int liquid_firdes_fexp_freqresponse(unsigned int _k, unsigned int _m, float _beta, float * _H); // flipped hyperbolic secant frequency response int liquid_firdes_fsech_freqresponse(unsigned int _k, unsigned int _m, float _beta, float * _H); // flipped hyperbolic secant frequency response int liquid_firdes_farcsech_freqresponse(unsigned int _k, unsigned int _m, float _beta, float * _H); // iirdes : infinite impulse response filter design // Sorts array _z of complex numbers into complex conjugate pairs to // within a tolerance. Conjugate pairs are ordered by increasing real // component with the negative imaginary element first. All pure-real // elements are placed at the end of the array. // // Example: // v: liquid_cplxpair(v): // 10 + j*3 -3 - j*4 // 5 + j*0 3 + j*4 // -3 + j*4 10 - j*3 // 10 - j*3 10 + j*3 // 3 + j*0 3 + j*0 // -3 + j*4 5 + j*0 // // _z : complex array (size _n) // _n : number of elements in _z // _tol : tolerance for finding complex pairs // _p : resulting pairs, pure real values of _z at end int liquid_cplxpair(float complex * _z, unsigned int _n, float _tol, float complex * _p); // post-process cleanup used with liquid_cplxpair // // once pairs have been identified and ordered, this method // will clean up the result by ensuring the following: // * pairs are perfect conjugates // * pairs have negative imaginary component first // * pairs are ordered by increasing real component // * pure-real elements are ordered by increasing value // // _p : pre-processed complex array, [size: _n x 1] // _n : array length // _num_pairs : number of complex conjugate pairs int liquid_cplxpair_cleanup(float complex * _p, unsigned int _n, unsigned int _num_pairs); // Jacobian elliptic functions (src/filter/src/ellip.c) // Landen transformation (_n iterations) int landenf(float _k, unsigned int _n, float * _v); // compute elliptic integral K(k) for _n recursions int ellipkf(float _k, unsigned int _n, float * _K, float * _Kp); // elliptic degree float ellipdegf(float _N, float _k1, unsigned int _n); // elliptic cd() function (_n recursions) float complex ellip_cdf(float complex _u, float _k, unsigned int _n); // elliptic inverse cd() function (_n recursions) float complex ellip_acdf(float complex _u, float _k, unsigned int _n); // elliptic sn() function (_n recursions) float complex ellip_snf(float complex _u, float _k, unsigned int _n); // elliptic inverse sn() function (_n recursions) float complex ellip_asnf(float complex _u, float _k, unsigned int _n); // // MODULE : framing // // // bpacket // #define BPACKET_VERSION (101+PACKETIZER_VERSION) // generator void bpacketgen_compute_packet_len(bpacketgen _q); void bpacketgen_assemble_pnsequence(bpacketgen _q); void bpacketgen_assemble_header(bpacketgen _q); // // flexframe // // flexframe protocol #define FLEXFRAME_PROTOCOL (101+PACKETIZER_VERSION) // header description #define FLEXFRAME_H_USER_DEFAULT (14) // default length for user-defined array #define FLEXFRAME_H_DEC (6) // decoded length #define FLEXFRAME_H_CRC (LIQUID_CRC_32) // header CRC #define FLEXFRAME_H_FEC0 (LIQUID_FEC_SECDED7264) // header FEC (inner) #define FLEXFRAME_H_FEC1 (LIQUID_FEC_HAMMING84) // header FEC (outer) #define FLEXFRAME_H_MOD (LIQUID_MODEM_QPSK) // modulation scheme // // gmskframe // #define GMSKFRAME_VERSION (3+PACKETIZER_VERSION) // header description #define GMSKFRAME_H_USER_DEFAULT (8) // user-defined array #define GMSKFRAME_H_DEC (5) // decoded length #define GMSKFRAME_H_CRC (LIQUID_CRC_32) // header CRC #define GMSKFRAME_H_FEC (LIQUID_FEC_HAMMING128) // header FEC // // ofdmflexframe // #define OFDMFLEXFRAME_PROTOCOL (104+PACKETIZER_VERSION) // header description #define OFDMFLEXFRAME_H_USER_DEFAULT (8) // default length for user-defined array #define OFDMFLEXFRAME_H_DEC (6) // decoded length #define OFDMFLEXFRAME_H_CRC (LIQUID_CRC_32) // header CRC #define OFDMFLEXFRAME_H_FEC0 (LIQUID_FEC_GOLAY2412) // header FEC (inner) #define OFDMFLEXFRAME_H_FEC1 (LIQUID_FEC_NONE) // header FEC (outer) #define OFDMFLEXFRAME_H_MOD (LIQUID_MODEM_BPSK) // modulation scheme // // dsssframe // #define DSSSFRAME_PROTOCOL (101 + PACKETIZER_VERSION) #define DSSSFRAME_H_USER_DEFAULT (8) #define DSSSFRAME_H_DEC (5) #define DSSSFRAME_H_CRC (LIQUID_CRC_32) #define DSSSFRAME_H_FEC0 (LIQUID_FEC_GOLAY2412) #define DSSSFRAME_H_FEC1 (LIQUID_FEC_NONE) // // multi-signal source for testing (no meaningful data, just signals) // #define LIQUID_QSOURCE_MANGLE_CFLOAT(name) LIQUID_CONCAT(qsourcecf,name) #define LIQUID_QSOURCE_DEFINE_API(QSOURCE,TO) \ \ /* Multi-signal source generator object */ \ typedef struct QSOURCE(_s) * QSOURCE(); \ \ /* Create default qsource object, type uninitialized */ \ QSOURCE() QSOURCE(_create)(unsigned int _M, \ unsigned int _m, \ float _as, \ float _fc, \ float _bw, \ float _gain); \ \ /* Copy object recursively, including all internal objects and state */ \ QSOURCE() QSOURCE(_copy)(QSOURCE() _q); \ \ /* Initialize user-defined qsource object */ \ int QSOURCE(_init_user)(QSOURCE() _q, \ void * _userdata, \ void * _callback); \ \ /* Initialize qsource tone object */ \ int QSOURCE(_init_tone)(QSOURCE() _q); \ \ /* Add chirp to signal generator, returning id of signal */ \ /* _q : signal source object */ \ /* _duration : duration of chirp [samples] */ \ /* _negate : negate frequency direction */ \ /* _repeat : repeat signal? or just run once */ \ int QSOURCE(_init_chirp)(QSOURCE() _q, \ float _duration, \ int _negate, \ int _repeat); \ \ /* Initialize qsource noise object */ \ int QSOURCE(_init_noise)(QSOURCE() _q); \ \ /* Initialize qsource linear modem object */ \ int QSOURCE(_init_modem)(QSOURCE() _q, \ int _ms, \ unsigned int _m, \ float _beta); \ \ /* Initialize frequency-shift keying modem signal source */ \ /* _q : signal source object */ \ /* _m : bits per symbol, _bps > 0 */ \ /* _k : samples/symbol, _k >= 2^_m */ \ int QSOURCE(_init_fsk)(QSOURCE() _q, \ unsigned int _m, \ unsigned int _k); \ \ /* Initialize qsource GMSK modem object */ \ int QSOURCE(_init_gmsk)(QSOURCE() _q, \ unsigned int _m, \ float _bt); \ \ /* Destroy qsource object */ \ int QSOURCE(_destroy)(QSOURCE() _q); \ \ /* Print qsource object */ \ int QSOURCE(_print)(QSOURCE() _q); \ \ /* Reset qsource object */ \ int QSOURCE(_reset)(QSOURCE() _q); \ \ /* Get/set source id */ \ int QSOURCE(_set_id)(QSOURCE() _q, int _id); \ int QSOURCE(_get_id)(QSOURCE() _q); \ \ int QSOURCE(_enable)(QSOURCE() _q); \ int QSOURCE(_disable)(QSOURCE() _q); \ \ /* Get number of samples generated by the object so far */ \ /* _q : msource object */ \ /* _gain : signal gain output [dB] */ \ uint64_t QSOURCE(_get_num_samples)(QSOURCE() _q); \ \ int QSOURCE(_set_gain)(QSOURCE() _q, \ float _gain_dB); \ \ float QSOURCE(_get_gain)(QSOURCE() _q); \ \ int QSOURCE(_set_frequency)(QSOURCE() _q, \ float _dphi); \ \ float QSOURCE(_get_frequency)(QSOURCE() _q); \ \ /* get center frequency of signal applied by channelizer alignment */ \ float QSOURCE(_get_frequency_index)(QSOURCE() _q); \ \ int QSOURCE(_generate)(QSOURCE() _q, \ TO * _v); \ \ int QSOURCE(_generate_into)(QSOURCE() _q, \ TO * _buf); \ LIQUID_QSOURCE_DEFINE_API(LIQUID_QSOURCE_MANGLE_CFLOAT, liquid_float_complex) // // MODULE : math // // // basic trigonometric functions // float liquid_sinf(float _x); float liquid_cosf(float _x); float liquid_tanf(float _x); void liquid_sincosf(float _x, float * _sinf, float * _cosf); float liquid_expf(float _x); float liquid_logf(float _x); // // complex math operations // // complex square root float complex liquid_csqrtf(float complex _z); // complex exponent, logarithm float complex liquid_cexpf(float complex _z); float complex liquid_clogf(float complex _z); // complex arcsin, arccos, arctan float complex liquid_casinf(float complex _z); float complex liquid_cacosf(float complex _z); float complex liquid_catanf(float complex _z); // faster approximation to arg{*} //float liquid_cargf_approx(float complex _z); // internal trig helper functions // complex rotation vector: cexpf(_Complex_I*THETA) #define liquid_cexpjf(THETA) (cosf(THETA) + _Complex_I*sinf(THETA)) // internal polynomial root-finding methods // finds the complex roots of the polynomial using the Durand-Kerner method // _p : polynomial array, ascending powers, [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots, [size: _k-1 x 1] int liquid_poly_findroots_durandkerner(double * _p, unsigned int _k, double complex * _roots); // finds the complex roots of the polynomial using Bairstow's method // _p : polynomial array, ascending powers, [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots, [size: _k-1 x 1] int liquid_poly_findroots_bairstow(double * _p, unsigned int _k, double complex * _roots); // iterate over Bairstow's method, finding quadratic factor x^2 + u*x + v // _p : polynomial array, ascending powers, [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _p1 : reduced polynomial (output) [size: _k-2 x 1] // _u : input: initial estimate for u; output: resulting u // _v : input: initial estimate for v; output: resulting v int liquid_poly_findroots_bairstow_recursion(double * _p, unsigned int _k, double * _p1, double * _u, double * _v); // run multiple iterations of Bairstow's method with different starting // conditions looking for convergence int liquid_poly_findroots_bairstow_persistent(double * _p, unsigned int _k, double * _p1, double * _u, double * _v); // compare roots for sorting int liquid_poly_sort_roots_compare(const void * _a, const void * _b); // // MODULE : matrix // // large macro // MATRIX : name-mangling macro // T : data type #define LIQUID_MATRIX_DEFINE_INTERNAL_API(MATRIX,T) \ T MATRIX(_det2x2)(T * _x, \ unsigned int _rx, \ unsigned int _cx); LIQUID_MATRIX_DEFINE_INTERNAL_API(LIQUID_MATRIX_MANGLE_FLOAT, float) LIQUID_MATRIX_DEFINE_INTERNAL_API(LIQUID_MATRIX_MANGLE_DOUBLE, double) LIQUID_MATRIX_DEFINE_INTERNAL_API(LIQUID_MATRIX_MANGLE_CFLOAT, liquid_float_complex) LIQUID_MATRIX_DEFINE_INTERNAL_API(LIQUID_MATRIX_MANGLE_CDOUBLE, liquid_double_complex) // search for index placement in list unsigned short int smatrix_indexsearch(unsigned short int * _list, unsigned int _num_elements, unsigned short int _value); // // MODULE : modem // // 'Square' QAM #define QAM4_ALPHA (1./sqrt(2)) #define QAM8_ALPHA (1./sqrt(6)) #define QAM16_ALPHA (1./sqrt(10)) #define QAM32_ALPHA (1./sqrt(20)) #define QAM64_ALPHA (1./sqrt(42)) #define QAM128_ALPHA (1./sqrt(82)) #define QAM256_ALPHA (1./sqrt(170)) #define QAM1024_ALPHA (1./sqrt(682)) #define QAM4096_ALPHA (1./sqrt(2730)) // Rectangular QAM #define RQAM4_ALPHA QAM4_ALPHA #define RQAM8_ALPHA QAM8_ALPHA #define RQAM16_ALPHA QAM16_ALPHA #define RQAM32_ALPHA (1./sqrt(26)) #define RQAM64_ALPHA QAM64_ALPHA #define RQAM128_ALPHA (1./sqrt(106)) #define RQAM256_ALPHA QAM256_ALPHA #define RQAM512_ALPHA (1./sqrt(426)) #define RQAM1024_ALPHA QAM1024_ALPHA #define RQAM2048_ALPHA (1./sqrt(1706)) #define RQAM4096_ALPHA QAM4096_ALPHA // ASK #define ASK2_ALPHA (1.) #define ASK4_ALPHA (1./sqrt(5)) #define ASK8_ALPHA (1./sqrt(21)) #define ASK16_ALPHA (1./sqrt(85)) #define ASK32_ALPHA (1./sqrt(341)) #define ASK64_ALPHA (1./sqrt(1365)) #define ASK128_ALPHA (1./sqrt(5461)) #define ASK256_ALPHA (1./sqrt(21845)) // Macro : MODEM // MODEM : name-mangling macro // T : primitive data type // TC : primitive data type (complex) #define LIQUID_MODEM_DEFINE_INTERNAL_API(MODEM,T,TC) \ \ /* initialize a generic modem object */ \ int MODEM(_init)(MODEM() _q, unsigned int _bits_per_symbol); \ \ /* initialize symbol map for fast modulation */ \ int MODEM(_init_map)(MODEM() _q); \ \ /* generic modem create routines */ \ MODEM() MODEM(_create_ask)( unsigned int _bits_per_symbol); \ MODEM() MODEM(_create_qam)( unsigned int _bits_per_symbol); \ MODEM() MODEM(_create_psk)( unsigned int _bits_per_symbol); \ MODEM() MODEM(_create_dpsk)(unsigned int _bits_per_symbol); \ MODEM() MODEM(_create_apsk)(unsigned int _bits_per_symbol); \ MODEM() MODEM(_create_arb)( unsigned int _bits_per_symbol); \ \ /* Initialize arbitrary modem constellation */ \ int MODEM(_arb_init)(MODEM() _q, \ float complex * _symbol_map, \ unsigned int _len); \ \ /* Initialize arb modem constellation from external file */ \ int MODEM(_arb_init_file)(MODEM() _q, char * _filename); \ \ /* specific modem create routines */ \ MODEM() MODEM(_create_bpsk)(void); \ MODEM() MODEM(_create_qpsk)(void); \ MODEM() MODEM(_create_ook)(void); \ MODEM() MODEM(_create_sqam32)(void); \ MODEM() MODEM(_create_sqam128)(void); \ MODEM() MODEM(_create_V29)(void); \ MODEM() MODEM(_create_arb16opt)(void); \ MODEM() MODEM(_create_arb32opt)(void); \ MODEM() MODEM(_create_arb64opt)(void); \ MODEM() MODEM(_create_arb128opt)(void); \ MODEM() MODEM(_create_arb256opt)(void); \ MODEM() MODEM(_create_arb64vt)(void); \ MODEM() MODEM(_create_pi4dqpsk)(void); \ \ /* Scale arbitrary modem energy to unity */ \ int MODEM(_arb_scale)(MODEM() _q); \ \ /* Balance I/Q */ \ int MODEM(_arb_balance_iq)(MODEM() _q); \ \ /* modulate using symbol map (look-up table) */ \ int MODEM(_modulate_map)(MODEM() _q, \ unsigned int _sym_in, \ TC * _y); \ \ /* modem modulate routines */ \ int MODEM(_modulate_ask) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_qam) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_psk) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_dpsk) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_arb) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_apsk) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_bpsk) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_qpsk) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_ook) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_sqam32) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_sqam128) ( MODEM(), unsigned int, TC *); \ int MODEM(_modulate_pi4dqpsk) ( MODEM(), unsigned int, TC *); \ \ /* modem demodulate routines */ \ int MODEM(_demodulate_ask) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_qam) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_psk) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_dpsk) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_arb) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_apsk) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_bpsk) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_qpsk) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_ook) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_sqam32) ( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_sqam128)( MODEM(), TC, unsigned int *); \ int MODEM(_demodulate_pi4dqpsk)(MODEM(), TC, unsigned int *); \ \ /* modem demodulate (soft) routines */ \ int MODEM(_demodulate_soft_bpsk)(MODEM() _q, \ TC _x, \ unsigned int * _sym_out, \ unsigned char * _soft_bits); \ int MODEM(_demodulate_soft_qpsk)(MODEM() _q, \ TC _x, \ unsigned int * _sym_out, \ unsigned char * _soft_bits); \ int MODEM(_demodulate_soft_pi4dqpsk)(MODEM() _q, \ TC _x, \ unsigned int * _sym_out, \ unsigned char* _soft_bits);\ int MODEM(_demodulate_soft_arb)( MODEM() _q, \ TC _x, \ unsigned int * _sym_out, \ unsigned char * _soft_bits); \ \ /* generate soft demodulation look-up table */ \ int MODEM(_demodsoft_gentab)(MODEM() _q, \ unsigned int _p); \ \ /* generic soft demodulation routine using nearest-neighbors */ \ /* look-up table */ \ int MODEM(_demodulate_soft_table)(MODEM() _q, \ TC _x, \ unsigned int * _sym_out, \ unsigned char * _soft_bits); \ \ /* Demodulate a linear symbol constellation using */ \ /* referenced lookup table */ \ /* _v : input value */ \ /* _m : bits per symbol */ \ /* _ref : array of thresholds */ \ /* _s : demodulated symbol */ \ /* _res : residual */ \ int MODEM(_demodulate_linear_array_ref)(T _v, \ unsigned int _m, \ T * _ref, \ unsigned int * _s, \ T * _res); \ // define internal modem APIs LIQUID_MODEM_DEFINE_INTERNAL_API(LIQUID_MODEM_MANGLE_FLOAT,float,float complex) // APSK constants (container for apsk structure definitions) struct liquid_apsk_s { modulation_scheme scheme; // APSK modulation scheme unsigned int num_levels; // number of rings unsigned int * p; // number of symbols per ring float * r; // radius of each ring float * phi; // phase offset of each ring float * r_slicer; // radius slicer unsigned char * map; // symbol mapping }; extern struct liquid_apsk_s liquid_apsk4; extern struct liquid_apsk_s liquid_apsk8; extern struct liquid_apsk_s liquid_apsk16; extern struct liquid_apsk_s liquid_apsk32; extern struct liquid_apsk_s liquid_apsk64; extern struct liquid_apsk_s liquid_apsk128; extern struct liquid_apsk_s liquid_apsk256; // 'square' 32-QAM (first quadrant) extern const float complex modem_arb_sqam32[8]; // 'square' 128-QAM (first quadrant) extern const float complex modem_arb_sqam128[32]; // V.29 star constellation extern const float complex modem_arb_V29[16]; // Virginia Tech logo extern const float complex modem_arb_vt64[64]; // optimal QAM constellations extern const float complex modem_arb16opt[16]; extern const float complex modem_arb32opt[32]; extern const float complex modem_arb64opt[64]; extern const float complex modem_arb128opt[128]; extern const float complex modem_arb256opt[256]; // // MODULE : multichannel // // ofdm frame (common) // generate short sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S0 : output symbol (freq) // _s0 : output symbol (time) // _M_S0 : total number of enabled subcarriers in S0 int ofdmframe_init_S0(unsigned char * _p, unsigned int _M, float complex * _S0, float complex * _s0, unsigned int * _M_S0); // generate long sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S1 : output symbol (freq) // _s1 : output symbol (time) // _M_S1 : total number of enabled subcarriers in S1 int ofdmframe_init_S1(unsigned char * _p, unsigned int _M, float complex * _S1, float complex * _s1, unsigned int * _M_S1); // // MODULE : nco (numerically-controlled oscillator) // // Numerically-controlled synthesizer (direct digital synthesis) #define LIQUID_SYNTH_DEFINE_INTERNAL_API(SYNTH,T,TC) \ \ /* constrain phase/frequency to be in [-pi,pi) */ \ void SYNTH(_constrain_phase)(SYNTH() _q); \ void SYNTH(_constrain_frequency)(SYNTH() _q); \ void SYNTH(_compute_synth)(SYNTH() _q); \ \ /* reset internal phase-locked loop filter */ \ void SYNTH(_pll_reset)(SYNTH() _q); \ // Define nco internal APIs LIQUID_SYNTH_DEFINE_INTERNAL_API(SYNTH_MANGLE_FLOAT, float, liquid_float_complex) // // MODULE : optim (non-linear optimization) // // optimization threshold switch // _u0 : first utility // _u1 : second utility // _minimize : minimize flag // // returns: // (_u0 > _u1) if (_minimize == 1) // (_u0 < _u1) otherwise int optim_threshold_switch(float _u0, float _u1, int _minimize); // compute the gradient of a function at a particular point // _utility : user-defined function // _userdata : user-defined data object // _x : operating point, [size: _n x 1] // _n : dimensionality of search // _delta : step value for which to compute gradient // _gradient : resulting gradient void gradsearch_gradient(utility_function _utility, void * _userdata, float * _x, unsigned int _n, float _delta, float * _gradient); // execute line search; loosely solve: // // min|max phi(alpha) := f(_x - alpha*_p) // // and return best guess at alpha that achieves this // // _utility : user-defined function // _userdata : user-defined data object // _direction : search direction (e.g. LIQUID_OPTIM_MINIMIZE) // _n : dimensionality of search // _x : operating point, [size: _n x 1] // _p : normalized gradient, [size: _n x 1] // _alpha : initial step size float gradsearch_linesearch(utility_function _utility, void * _userdata, int _direction, unsigned int _n, float * _x, float * _p, float _alpha); // normalize vector, returning its l2-norm float gradsearch_norm(float * _v, unsigned int _n); // Chromosome structure used in genetic algorithm searches struct chromosome_s { unsigned int num_traits; // number of represented traits unsigned int * bits_per_trait; // bits to represent each trait unsigned long * max_value; // maximum representable integer value unsigned long * traits; // chromosome data unsigned int num_bits; // total number of bits }; struct gasearch_s { chromosome * population; // population of chromosomes unsigned int population_size; // size of the population unsigned int selection_size; // number of float mutation_rate; // rate of mutation unsigned int num_parameters; // number of parameters to optimize unsigned int bits_per_chromosome; // total number of bits in each chromosome float *utility; // utility array unsigned int *rank; // rank indices of chromosomes (best to worst) chromosome c; // copy of best chromosome, optimal solution float utility_opt; // optimum utility (fitness of best solution) // External utility function. // // The success of a GA search algorithm is contingent upon the // design of a good utility function. It should meet the following // criteria: // - monotonically increasing (never flat) // - efficient to compute // - maps the [0,1] bounded output vector to desired range // - for multiple objectives, utility should be high \em only when // all objectives are met (multiplicative, not additive) gasearch_utility get_utility; // utility function pointer void * userdata; // object to optimize int minimize; // minimize/maximize utility (search direction) }; // // gasearch internal methods // // evaluate fitness of entire population int gasearch_evaluate(gasearch _q); // crossover population int gasearch_crossover(gasearch _q); // mutate population int gasearch_mutate(gasearch _q); // rank population by fitness int gasearch_rank(gasearch _q); // sort values by index // _v : input values, [size: _len x 1] // _rank : output rank array (indices) [size: _len x 1] // _len : length of input array // _descending : descending/ascending void optim_sort(float *_v, unsigned int * _rank, unsigned int _len, int _descending); // // MODULE : random // #define randf_inline() ((float) rand() / (float) RAND_MAX) float complex icrandnf(); // generate x ~ Gamma(delta,1) float randgammaf_delta(float _delta); // data scrambler masks #define LIQUID_SCRAMBLE_MASK0 (0xb4) #define LIQUID_SCRAMBLE_MASK1 (0x6a) #define LIQUID_SCRAMBLE_MASK2 (0x8b) #define LIQUID_SCRAMBLE_MASK3 (0xc5) // // MODULE : sequence // // // MODULE : utility // // number of ones in a byte // 0 0000 0000 : 0 // 1 0000 0001 : 1 // 2 0000 0010 : 1 // 3 0000 0011 : 2 // 4 0000 0100 : 1 // ... // 126 0111 1110 : 6 // 127 0111 1111 : 7 // 128 1000 0000 : 1 // 129 1000 0001 : 2 // ... // 253 1111 1101 : 7 // 254 1111 1110 : 7 // 255 1111 1111 : 8 extern const unsigned char liquid_c_ones[256]; // Count the number of ones in an integer, inline insertion #define liquid_count_ones_uint16(x) ( \ liquid_c_ones[ (x) & 0xff ] + \ liquid_c_ones[ ((x)>>8) & 0xff ]) #define liquid_count_ones_uint24(x) ( \ liquid_c_ones[ (x) & 0xff ] + \ liquid_c_ones[ ((x)>> 8) & 0xff ] + \ liquid_c_ones[ ((x)>>16) & 0xff ]) #define liquid_count_ones_uint32(x) ( \ liquid_c_ones[ (x) & 0xff ] + \ liquid_c_ones[ ((x)>> 8) & 0xff ] + \ liquid_c_ones[ ((x)>>16) & 0xff ] + \ liquid_c_ones[ ((x)>>24) & 0xff ]) // number of ones in a byte, modulo 2 // 0 0000 0000 : 0 // 1 0000 0001 : 1 // 2 0000 0010 : 1 // 3 0000 0011 : 0 // 4 0000 0100 : 1 // ... // 126 0111 1110 : 0 // 127 0111 1111 : 1 // 128 1000 0000 : 1 // 129 1000 0001 : 0 // ... // 253 1111 1101 : 1 // 254 1111 1110 : 1 // 255 1111 1111 : 0 extern const unsigned char liquid_c_ones_mod2[256]; // Count the number of ones in an integer modulo 2, inline insertion #define liquid_count_ones_mod2_uint16(x) (( \ liquid_c_ones_mod2[ (x) & 0xff ] + \ liquid_c_ones_mod2[ ((x)>>8) & 0xff ]) % 2) #define liquid_count_ones_mod2_uint32(x) (( \ liquid_c_ones_mod2[ (x) & 0xff ] + \ liquid_c_ones_mod2[ ((x)>> 8) & 0xff ] + \ liquid_c_ones_mod2[ ((x)>>16) & 0xff ] + \ liquid_c_ones_mod2[ ((x)>>24) & 0xff ]) % 2) // compute binary dot-products (inline pre-processor macros) #define liquid_bdotprod_uint8(x,y) liquid_c_ones_mod2[(x)&(y)] #define liquid_bdotprod_uint16(x,y) liquid_count_ones_mod2_uint16((x)&(y)) #define liquid_bdotprod_uint32(x,y) liquid_count_ones_mod2_uint32((x)&(y)) // number of leading zeros in byte extern unsigned int liquid_c_leading_zeros[256]; // byte reversal and manipulation extern const unsigned char liquid_reverse_byte_gentab[256]; #endif // __LIQUID_INTERNAL_H__ liquid-dsp-1.7.0/library.json000066400000000000000000000021641474751757600161630ustar00rootroot00000000000000{ "name": "liquid-dsp", "version": "1.7.0", "description": "Software-defined radio digital signal processing library", "homepage": "https://liquidsdr.org", "keywords": [ "digital signal processing","DSP", "software-defined radio", "SDR", "Fourier transform,","FFT", "filter","resample","interpolate","decimate", "error correction","modulation" ], "repository": { "type": "git", "url": "https://github.com/jgaeddert/liquid-dsp.git" }, "authors": { "name": "Joseph D. Gaeddert", "email": "joseph@liquidsdr.org", "url": "https://liquidsdr.org/colophon", "maintainer": true }, "license": "MIT", "build": { "extraScript": "scripts/generate_headers.py", "flags": [ "-I.", "-Wno-deprecated-declarations" ], "srcFilter": [ "+<*.c>", "+<*/src/*.c>", "-<.git/>", "-<*/src/*.proto.c>", "-<*/src/*.av.c>", "-<*/src/*.neon.c>", "-<*/src/*.sse.c>", "-<*/src/*.avx.c>", "-<*/src/*.avx512f.c>", "-<*/src/*.x86.s>" ] }, "headers":"liquid.h" } liquid-dsp-1.7.0/makefile.in000066400000000000000000001706661474751757600157460ustar00rootroot00000000000000# Copyright (c) 2007 - 2024 Joseph Gaeddert # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # Makefile for liquid-dsp libraries # # Targets: # all : dynamic shared-library object (e.g. libliquid.so) # install : install the dynamic shared library object and headers # uninstall : uninstall the library and header file(s) # clean : clean all targets (bench, check, examples, etc) # distclean : removes everything except the originally distributed files # check : build and run autotest program # bench : build and run benchmarking program # examples : build all examples # sandbox : build all sandbox examples # programs : build all programs, but don't run anything # world : build absolutely everything (but don't install) # # clean-modules : clean all modules # clean-examples : clean examples programs # clean-sandbox : clean sandbox programs # clean-check : clean autotest program # clean-bench : clean benchmark program # # autoconf initialization macros NAME := @PACKAGE_NAME@ VERSION := @PACKAGE_VERSION@ BUGREPORT := @PACKAGE_BUGREPORT@ AR_LIB := @AR_LIB@ SH_LIB := @SH_LIB@ SOVERSION := 1 # paths prefix := @prefix@ exec_prefix := @exec_prefix@ VPATH := @srcdir@ srcdir := @srcdir@ libdir := @libdir@ include_dirs := . ./include # programs CC := @CC@ CXX := g++ MV := mv -f RM := rm -f SED := @SED@ GREP := @GREP@ AR := @AR@ LIBTOOL := @LIBTOOL@ RANLIB := @RANLIB@ # flags INCLUDE_CFLAGS = $(addprefix -I,$(include_dirs)) COVERAGE_FLAGS = @COVERAGE_OPTION@ # dynamic library linker needs separate flag CONFIG_CFLAGS = @CFLAGS@ @DEBUG_MSG_OPTION@ @ARCH_OPTION@ ${COVERAGE_FLAGS} CPPFLAGS = @CPPFLAGS@ $(INCLUDE_CFLAGS) CFLAGS = $(CONFIG_CFLAGS) -Wall -fPIC -Wno-deprecated -Wno-deprecated-declarations CXXFLAGS = $(CFLAGS) -std=c++14 -Wno-return-type-c-linkage LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ PATHSEP = / # # liquid headers # headers_install := liquid.h headers := $(headers_install) liquid.internal.h include_headers := $(addprefix include/,$(headers)) ## ## liquid-dsp modules ## all: # additional targets to clean extra_clean := # additional autotest objects autotest_extra_obj := # additional benchmark objects benchmark_extra_obj := # # MODULE : agc - automatic gain control # # object files agc_objects = \ src/agc/src/agc_crcf.o \ src/agc/src/agc_rrrf.o \ agc_prototypes := \ src/agc/src/agc.proto.c \ # explicit targets and dependencies src/agc/src/agc_crcf.o : %.o : %.c $(include_headers) $(agc_prototypes) src/agc/src/agc_rrrf.o : %.o : %.c $(include_headers) $(agc_prototypes) # autotests agc_autotests := \ src/agc/tests/agc_crcf_autotest.c \ # benchmarks agc_benchmarks := \ src/agc/bench/agc_crcf_benchmark.c \ # # MODULE : audio # # described below audio_objects := \ src/audio/src/cvsd.o \ src/cvsd/src/cvsd.o : %.o : %.c $(include_headers) audio_autotests := \ src/audio/tests/cvsd_autotest.c \ audio_benchmarks := \ src/audio/bench/cvsd_benchmark.c \ # # MODULE : buffer # buffer_objects := \ src/buffer/src/bufferf.o \ src/buffer/src/buffercf.o \ # src/buffer/src/buffer.proto.c buffer_prototypes := \ src/buffer/src/cbuffer.proto.c \ src/buffer/src/wdelay.proto.c \ src/buffer/src/window.proto.c \ src/buffer/src/bufferf.o : %.o : %.c $(include_headers) $(buffer_prototypes) src/buffer/src/buffercf.o : %.o : %.c $(include_headers) $(buffer_prototypes) buffer_autotests := \ src/buffer/tests/cbuffer_autotest.c \ src/buffer/tests/wdelay_autotest.c \ src/buffer/tests/buffer_window_autotest.c \ buffer_benchmarks := \ src/buffer/bench/cbuffercf_benchmark.c \ src/buffer/bench/window_push_benchmark.c \ src/buffer/bench/window_read_benchmark.c \ # # MODULE : channel # channel_objects := \ src/channel/src/channel_cccf.o \ channel_prototypes := \ src/channel/src/channel.proto.c \ src/channel/src/tvmpch.proto.c \ src/channel/src/channel_cccf.o : %.o : %.c $(include_headers) $(channel_prototypes) channel_autotests := \ src/channel/tests/channel_copy_autotest.c \ src/channel/tests/tvmpch_copy_autotest.c \ #src/channel/tests/channel_cccf_autotest.c channel_benchmarks := \ #src/channel/bench/channel_cccf_benchmark.c # # MODULE : dotprod # dotprod_objects := \ @MLIBS_DOTPROD@ \ src/dotprod/src/dotprod_cccf.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod.proto.c src/dotprod/src/dotprod_crcf.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod.proto.c src/dotprod/src/dotprod_rrrf.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod.proto.c src/dotprod/src/sumsq.o : %.o : %.c $(include_headers) # specific machine architectures # AltiVec src/dotprod/src/dotprod_rrrf.av.o : %.o : %.c $(include_headers) # MMX/SSE2 src/dotprod/src/dotprod_rrrf.mmx.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod_crcf.mmx.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod_cccf.mmx.o : %.o : %.c $(include_headers) src/dotprod/src/sumsq.mmx.o : %.o : %.c $(include_headers) # SSE4.1/2 src/dotprod/src/dotprod_rrrf.sse4.o : %.o : %.c $(include_headers) # AVX src/dotprod/src/sumsq.avx.o : %.o : %.c $(include_headers) # ARM Neon src/dotprod/src/dotprod_rrrf.neon.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod_crcf.neon.o : %.o : %.c $(include_headers) src/dotprod/src/dotprod_cccf.neon.o : %.o : %.c $(include_headers) dotprod_autotests := \ src/dotprod/tests/dotprod_rrrf_autotest.c \ src/dotprod/tests/dotprod_crcf_autotest.c \ src/dotprod/tests/dotprod_cccf_autotest.c \ src/dotprod/tests/sumsqf_autotest.c \ src/dotprod/tests/sumsqcf_autotest.c \ dotprod_benchmarks := \ src/dotprod/bench/dotprod_cccf_benchmark.c \ src/dotprod/bench/dotprod_crcf_benchmark.c \ src/dotprod/bench/dotprod_rrrf_benchmark.c \ src/dotprod/bench/sumsqf_benchmark.c \ src/dotprod/bench/sumsqcf_benchmark.c \ # # MODULE : equalization # equalization_objects := \ src/equalization/src/equalizer_cccf.o \ src/equalization/src/equalizer_rrrf.o \ equalization_prototypes := \ src/equalization/src/eqlms.proto.c \ src/equalization/src/eqrls.proto.c \ $(equalization_objects) : %.o : %.c $(include_headers) $(equalization_prototypes) # autotests equalization_autotests := \ src/equalization/tests/eqlms_cccf_autotest.c \ src/equalization/tests/eqrls_rrrf_autotest.c \ # benchmarks equalization_benchmarks := \ src/equalization/bench/eqlms_cccf_benchmark.c \ src/equalization/bench/eqrls_cccf_benchmark.c \ # # MODULE : fec - forward error-correction # fec_objects := \ src/fec/src/crc.o \ src/fec/src/fec.o \ src/fec/src/fec_conv.o \ src/fec/src/fec_conv_poly.o \ src/fec/src/fec_conv_pmatrix.o \ src/fec/src/fec_conv_punctured.o \ src/fec/src/fec_golay2412.o \ src/fec/src/fec_hamming74.o \ src/fec/src/fec_hamming84.o \ src/fec/src/fec_hamming128.o \ src/fec/src/fec_hamming1511.o \ src/fec/src/fec_hamming3126.o \ src/fec/src/fec_hamming128_gentab.o \ src/fec/src/fec_pass.o \ src/fec/src/fec_rep3.o \ src/fec/src/fec_rep5.o \ src/fec/src/fec_rs.o \ src/fec/src/fec_secded2216.o \ src/fec/src/fec_secded3932.o \ src/fec/src/fec_secded7264.o \ src/fec/src/interleaver.o \ src/fec/src/packetizer.o \ src/fec/src/sumproduct.o \ # list explicit targets and dependencies here $(fec_objects) : %.o : %.c $(include_headers) # autotests fec_autotests := \ src/fec/tests/crc_autotest.c \ src/fec/tests/fec_autotest.c \ src/fec/tests/fec_config_autotest.c \ src/fec/tests/fec_copy_autotest.c \ src/fec/tests/fec_soft_autotest.c \ src/fec/tests/fec_golay2412_autotest.c \ src/fec/tests/fec_hamming74_autotest.c \ src/fec/tests/fec_hamming84_autotest.c \ src/fec/tests/fec_hamming128_autotest.c \ src/fec/tests/fec_hamming1511_autotest.c \ src/fec/tests/fec_hamming3126_autotest.c \ src/fec/tests/fec_reedsolomon_autotest.c \ src/fec/tests/fec_rep3_autotest.c \ src/fec/tests/fec_rep5_autotest.c \ src/fec/tests/fec_secded2216_autotest.c \ src/fec/tests/fec_secded3932_autotest.c \ src/fec/tests/fec_secded7264_autotest.c \ src/fec/tests/interleaver_autotest.c \ src/fec/tests/packetizer_copy_autotest.c \ src/fec/tests/packetizer_autotest.c \ # benchmarks fec_benchmarks := \ src/fec/bench/crc_benchmark.c \ src/fec/bench/fec_encode_benchmark.c \ src/fec/bench/fec_decode_benchmark.c \ src/fec/bench/fecsoft_decode_benchmark.c \ src/fec/bench/sumproduct_benchmark.c \ src/fec/bench/interleaver_benchmark.c \ src/fec/bench/packetizer_decode_benchmark.c \ # # MODULE : fft - fast Fourier transforms, discrete sine/cosine transforms, etc. # fft_objects := \ src/fft/src/fftf.o \ src/fft/src/spgramcf.o \ src/fft/src/spgramf.o \ src/fft/src/fft_utilities.o \ # explicit targets and dependencies fft_prototypes := \ src/fft/src/fft_common.proto.c \ src/fft/src/fft_dft.proto.c \ src/fft/src/fft_radix2.proto.c \ src/fft/src/fft_mixed_radix.proto.c \ src/fft/src/fft_rader.proto.c \ src/fft/src/fft_rader2.proto.c \ src/fft/src/fft_r2r_1d.proto.c \ src/fft/src/fftf.o : %.o : %.c $(include_headers) $(fft_prototypes) src/fft/src/asgram.o : %.o : %.c $(include_headers) src/fft/src/dct.o : %.o : %.c $(include_headers) src/fft/src/fftf.o : %.o : %.c $(include_headers) src/fft/src/fft_utilities.o : %.o : %.c $(include_headers) src/fft/src/mdct.o : %.o : %.c $(include_headers) src/fft/src/spgramcf.o : %.o : %.c $(include_headers) src/fft/src/asgram.proto.c src/fft/src/spgram.proto.c src/fft/src/spwaterfall.proto.c src/fft/src/spgramf.o : %.o : %.c $(include_headers) src/fft/src/asgram.proto.c src/fft/src/spgram.proto.c src/fft/src/spwaterfall.proto.c # fft autotest scripts fft_autotests := \ src/fft/tests/asgram_autotest.c \ src/fft/tests/fft_small_autotest.c \ src/fft/tests/fft_radix2_autotest.c \ src/fft/tests/fft_composite_autotest.c \ src/fft/tests/fft_prime_autotest.c \ src/fft/tests/fft_r2r_autotest.c \ src/fft/tests/fft_shift_autotest.c \ src/fft/tests/spgram_autotest.c \ src/fft/tests/spwaterfall_autotest.c \ # additional autotest objects autotest_extra_obj += \ src/fft/tests/fft_runtest.o \ src/fft/tests/data/fft_data_2.o \ src/fft/tests/data/fft_data_3.o \ src/fft/tests/data/fft_data_4.o \ src/fft/tests/data/fft_data_5.o \ src/fft/tests/data/fft_data_6.o \ src/fft/tests/data/fft_data_7.o \ src/fft/tests/data/fft_data_8.o \ src/fft/tests/data/fft_data_9.o \ src/fft/tests/data/fft_data_10.o \ src/fft/tests/data/fft_data_16.o \ src/fft/tests/data/fft_data_17.o \ src/fft/tests/data/fft_data_20.o \ src/fft/tests/data/fft_data_21.o \ src/fft/tests/data/fft_data_22.o \ src/fft/tests/data/fft_data_24.o \ src/fft/tests/data/fft_data_26.o \ src/fft/tests/data/fft_data_30.o \ src/fft/tests/data/fft_data_32.o \ src/fft/tests/data/fft_data_35.o \ src/fft/tests/data/fft_data_36.o \ src/fft/tests/data/fft_data_43.o \ src/fft/tests/data/fft_data_48.o \ src/fft/tests/data/fft_data_63.o \ src/fft/tests/data/fft_data_64.o \ src/fft/tests/data/fft_data_79.o \ src/fft/tests/data/fft_data_92.o \ src/fft/tests/data/fft_data_96.o \ src/fft/tests/data/fft_data_120.o \ src/fft/tests/data/fft_data_130.o \ src/fft/tests/data/fft_data_157.o \ src/fft/tests/data/fft_data_192.o \ src/fft/tests/data/fft_data_317.o \ src/fft/tests/data/fft_data_509.o \ src/fft/tests/data/fft_r2rdata_8.o \ src/fft/tests/data/fft_r2rdata_27.o \ src/fft/tests/data/fft_r2rdata_32.o \ # fft benchmark scripts fft_benchmarks := \ src/fft/bench/fft_composite_benchmark.c \ src/fft/bench/fft_prime_benchmark.c \ src/fft/bench/fft_radix2_benchmark.c \ src/fft/bench/fft_r2r_benchmark.c \ src/fft/bench/spgramcf_benchmark.c \ # additional benchmark objects benchmark_extra_obj := \ src/fft/bench/fft_runbench.o \ # # MODULE : filter # filter_objects := \ src/filter/src/bessel.o \ src/filter/src/butter.o \ src/filter/src/cheby1.o \ src/filter/src/cheby2.o \ src/filter/src/ellip.o \ src/filter/src/filter_rrrf.o \ src/filter/src/filter_crcf.o \ src/filter/src/filter_cccf.o \ src/filter/src/firdes.o \ src/filter/src/firdespm.o \ src/filter/src/firdespm_halfband.o \ src/filter/src/fnyquist.o \ src/filter/src/gmsk.o \ src/filter/src/group_delay.o \ src/filter/src/hM3.o \ src/filter/src/iirdes.pll.o \ src/filter/src/iirdes.o \ src/filter/src/lpc.o \ src/filter/src/rcos.o \ src/filter/src/rkaiser.o \ src/filter/src/rrcos.o \ # list explicit targets and dependencies here filter_prototypes := \ src/filter/src/autocorr.proto.c \ src/filter/src/dds.proto.c \ src/filter/src/fdelay.proto.c \ src/filter/src/fftfilt.proto.c \ src/filter/src/firdecim.proto.c \ src/filter/src/firfarrow.proto.c \ src/filter/src/firfilt.proto.c \ src/filter/src/firhilb.proto.c \ src/filter/src/firinterp.proto.c \ src/filter/src/firpfb.proto.c \ src/filter/src/iirdecim.proto.c \ src/filter/src/iirfilt.proto.c \ src/filter/src/iirfiltsos.proto.c \ src/filter/src/iirhilb.proto.c \ src/filter/src/iirinterp.proto.c \ src/filter/src/msresamp.proto.c \ src/filter/src/msresamp2.proto.c \ src/filter/src/ordfilt.proto.c \ src/filter/src/rresamp.proto.c \ src/filter/src/resamp.fixed.proto.c \ src/filter/src/resamp2.proto.c \ src/filter/src/symsync.proto.c \ src/filter/src/bessel.o : %.o : %.c $(include_headers) src/filter/src/bessel.o : %.o : %.c $(include_headers) src/filter/src/butter.o : %.o : %.c $(include_headers) src/filter/src/cheby1.o : %.o : %.c $(include_headers) src/filter/src/cheby2.o : %.o : %.c $(include_headers) src/filter/src/ellip.o : %.o : %.c $(include_headers) src/filter/src/filter_rrrf.o : %.o : %.c $(include_headers) $(filter_prototypes) src/filter/src/filter_crcf.o : %.o : %.c $(include_headers) $(filter_prototypes) src/filter/src/filter_cccf.o : %.o : %.c $(include_headers) $(filter_prototypes) src/filter/src/firdes.o : %.o : %.c $(include_headers) src/filter/src/firdespm.o : %.o : %.c $(include_headers) src/filter/src/group_delay.o : %.o : %.c $(include_headers) src/filter/src/hM3.o : %.o : %.c $(include_headers) src/filter/src/iirdes.pll.o : %.o : %.c $(include_headers) src/filter/src/iirdes.o : %.o : %.c $(include_headers) src/filter/src/lpc.o : %.o : %.c $(include_headers) src/filter/src/rcos.o : %.o : %.c $(include_headers) src/filter/src/rkaiser.o : %.o : %.c $(include_headers) src/filter/src/rrcos.o : %.o : %.c $(include_headers) filter_autotests := \ src/filter/tests/dds_cccf_autotest.c \ src/filter/tests/fdelay_rrrf_autotest.c \ src/filter/tests/fftfilt_xxxf_autotest.c \ src/filter/tests/filter_crosscorr_autotest.c \ src/filter/tests/firdecim_autotest.c \ src/filter/tests/firdecim_xxxf_autotest.c \ src/filter/tests/firdes_autotest.c \ src/filter/tests/firdespm_autotest.c \ src/filter/tests/firfilt_autotest.c \ src/filter/tests/firfilt_cccf_notch_autotest.c \ src/filter/tests/firfilt_coefficients_autotest.c \ src/filter/tests/firfilt_rnyquist_autotest.c \ src/filter/tests/firfilt_xxxf_autotest.c \ src/filter/tests/firfilt_copy_autotest.c \ src/filter/tests/firhilb_autotest.c \ src/filter/tests/firinterp_autotest.c \ src/filter/tests/firpfb_autotest.c \ src/filter/tests/groupdelay_autotest.c \ src/filter/tests/iirdecim_autotest.c \ src/filter/tests/iirdes_autotest.c \ src/filter/tests/iirdes_support_autotest.c \ src/filter/tests/iirfilt_autotest.c \ src/filter/tests/iirfilt_xxxf_autotest.c \ src/filter/tests/iirfiltsos_autotest.c \ src/filter/tests/iirhilb_autotest.c \ src/filter/tests/iirinterp_autotest.c \ src/filter/tests/lpc_autotest.c \ src/filter/tests/msresamp_crcf_autotest.c \ src/filter/tests/msresamp2_crcf_autotest.c \ src/filter/tests/ordfilt_autotest.c \ src/filter/tests/rresamp_crcf_autotest.c \ src/filter/tests/rresamp_crcf_partition_autotest.c \ src/filter/tests/resamp_crcf_autotest.c \ src/filter/tests/resamp2_crcf_autotest.c \ src/filter/tests/rkaiser_autotest.c \ src/filter/tests/symsync_copy_autotest.c \ src/filter/tests/symsync_crcf_autotest.c \ src/filter/tests/symsync_rrrf_autotest.c \ # additional autotest objects autotest_extra_obj += \ src/filter/tests/fftfilt_runtest.o \ \ src/filter/tests/data/fftfilt_rrrf_data_h4x256.o \ src/filter/tests/data/fftfilt_crcf_data_h4x256.o \ src/filter/tests/data/fftfilt_cccf_data_h4x256.o \ \ src/filter/tests/data/fftfilt_rrrf_data_h7x256.o \ src/filter/tests/data/fftfilt_crcf_data_h7x256.o \ src/filter/tests/data/fftfilt_cccf_data_h7x256.o \ \ src/filter/tests/data/fftfilt_rrrf_data_h13x256.o \ src/filter/tests/data/fftfilt_crcf_data_h13x256.o \ src/filter/tests/data/fftfilt_cccf_data_h13x256.o \ \ src/filter/tests/data/fftfilt_rrrf_data_h23x256.o \ src/filter/tests/data/fftfilt_crcf_data_h23x256.o \ src/filter/tests/data/fftfilt_cccf_data_h23x256.o \ \ src/filter/tests/firdecim_runtest.o \ \ src/filter/tests/data/firdecim_rrrf_data_M2h4x20.o \ src/filter/tests/data/firdecim_crcf_data_M2h4x20.o \ src/filter/tests/data/firdecim_cccf_data_M2h4x20.o \ \ src/filter/tests/data/firdecim_rrrf_data_M3h7x30.o \ src/filter/tests/data/firdecim_crcf_data_M3h7x30.o \ src/filter/tests/data/firdecim_cccf_data_M3h7x30.o \ \ src/filter/tests/data/firdecim_rrrf_data_M4h13x40.o \ src/filter/tests/data/firdecim_crcf_data_M4h13x40.o \ src/filter/tests/data/firdecim_cccf_data_M4h13x40.o \ \ src/filter/tests/data/firdecim_rrrf_data_M5h23x50.o \ src/filter/tests/data/firdecim_crcf_data_M5h23x50.o \ src/filter/tests/data/firdecim_cccf_data_M5h23x50.o \ \ src/filter/tests/firfilt_runtest.o \ \ src/filter/tests/data/firfilt_rrrf_data_h4x8.o \ src/filter/tests/data/firfilt_crcf_data_h4x8.o \ src/filter/tests/data/firfilt_cccf_data_h4x8.o \ \ src/filter/tests/data/firfilt_rrrf_data_h7x16.o \ src/filter/tests/data/firfilt_crcf_data_h7x16.o \ src/filter/tests/data/firfilt_cccf_data_h7x16.o \ \ src/filter/tests/data/firfilt_rrrf_data_h13x32.o \ src/filter/tests/data/firfilt_crcf_data_h13x32.o \ src/filter/tests/data/firfilt_cccf_data_h13x32.o \ \ src/filter/tests/data/firfilt_rrrf_data_h23x64.o \ src/filter/tests/data/firfilt_crcf_data_h23x64.o \ src/filter/tests/data/firfilt_cccf_data_h23x64.o \ \ src/filter/tests/iirfilt_runtest.o \ \ src/filter/tests/data/iirfilt_rrrf_data_h3x64.o \ src/filter/tests/data/iirfilt_crcf_data_h3x64.o \ src/filter/tests/data/iirfilt_cccf_data_h3x64.o \ \ src/filter/tests/data/iirfilt_rrrf_data_h5x64.o \ src/filter/tests/data/iirfilt_crcf_data_h5x64.o \ src/filter/tests/data/iirfilt_cccf_data_h5x64.o \ \ src/filter/tests/data/iirfilt_rrrf_data_h7x64.o \ src/filter/tests/data/iirfilt_crcf_data_h7x64.o \ src/filter/tests/data/iirfilt_cccf_data_h7x64.o \ filter_benchmarks := \ src/filter/bench/fftfilt_crcf_benchmark.c \ src/filter/bench/firdecim_crcf_benchmark.c \ src/filter/bench/firhilb_benchmark.c \ src/filter/bench/firinterp_crcf_benchmark.c \ src/filter/bench/firfilt_crcf_benchmark.c \ src/filter/bench/iirdecim_crcf_benchmark.c \ src/filter/bench/iirfilt_crcf_benchmark.c \ src/filter/bench/iirinterp_crcf_benchmark.c \ src/filter/bench/rresamp_crcf_benchmark.c \ src/filter/bench/resamp_crcf_benchmark.c \ src/filter/bench/resamp2_crcf_benchmark.c \ src/filter/bench/symsync_crcf_benchmark.c \ # # MODULE : framing # framing_objects := \ src/framing/src/bpacketgen.o \ src/framing/src/bpacketsync.o \ src/framing/src/detector_cccf.o \ src/framing/src/dsssframe64gen.o \ src/framing/src/dsssframe64sync.o \ src/framing/src/dsssframegen.o \ src/framing/src/dsssframesync.o \ src/framing/src/framedatastats.o \ src/framing/src/framesyncstats.o \ src/framing/src/framegen64.o \ src/framing/src/framesync64.o \ src/framing/src/framingcf.o \ src/framing/src/framing_rrrf.o \ src/framing/src/framing_crcf.o \ src/framing/src/framing_cccf.o \ src/framing/src/flexframegen.o \ src/framing/src/flexframesync.o \ src/framing/src/fskframegen.o \ src/framing/src/fskframesync.o \ src/framing/src/gmskframegen.o \ src/framing/src/gmskframesync.o \ src/framing/src/ofdmflexframegen.o \ src/framing/src/ofdmflexframesync.o \ src/framing/src/qpilotgen.o \ src/framing/src/qpilotsync.o \ # list explicit targets and dependencies here framing_prototypes_gen := \ src/framing/src/msource.proto.c \ src/framing/src/qpacketmodem.proto.c \ src/framing/src/qsource.proto.c \ src/framing/src/symstream.proto.c \ src/framing/src/symstreamr.proto.c \ framing_prototypes_sync := \ src/framing/src/bpresync.proto.c \ src/framing/src/bsync.proto.c \ src/framing/src/presync.proto.c \ src/framing/src/qdetector.proto.c \ src/framing/src/qdsync.proto.c \ src/framing/src/symtrack.proto.c \ src/framing/src/framingcf.o : %.o : %.c $(include_headers) ${framing_prototypes_gen} src/framing/src/framing_rrrf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} src/framing/src/framing_crcf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} src/framing/src/framing_cccf.o : %.o : %.c $(include_headers) ${framing_prototypes_sync} framing_autotests := \ src/framing/tests/bpacketsync_autotest.c \ src/framing/tests/bsync_autotest.c \ src/framing/tests/detector_autotest.c \ src/framing/tests/dsssframe64_autotest.c \ src/framing/tests/dsssframesync_autotest.c \ src/framing/tests/flexframesync_autotest.c \ src/framing/tests/framesync64_autotest.c \ src/framing/tests/fskframesync_autotest.c \ src/framing/tests/gmskframe_autotest.c \ src/framing/tests/msource_autotest.c \ src/framing/tests/ofdmflexframe_autotest.c \ src/framing/tests/qdetector_cccf_autotest.c \ src/framing/tests/qdetector_cccf_copy_autotest.c \ src/framing/tests/qdsync_cccf_autotest.c \ src/framing/tests/qpacketmodem_autotest.c \ src/framing/tests/qpilotsync_autotest.c \ src/framing/tests/qsource_autotest.c \ src/framing/tests/symstreamcf_autotest.c \ src/framing/tests/symstreamcf_delay_autotest.c \ src/framing/tests/symstreamrcf_autotest.c \ src/framing/tests/symstreamrcf_delay_autotest.c \ src/framing/tests/symtrack_cccf_autotest.c \ framing_benchmarks := \ src/framing/bench/presync_benchmark.c \ src/framing/bench/bpacketsync_benchmark.c \ src/framing/bench/bpresync_benchmark.c \ src/framing/bench/bsync_benchmark.c \ src/framing/bench/detector_benchmark.c \ src/framing/bench/flexframesync_benchmark.c \ src/framing/bench/framesync64_benchmark.c \ src/framing/bench/gmskframesync_benchmark.c \ src/framing/bench/qdetector_benchmark.c \ # # MODULE : math # math_objects := \ src/math/src/poly.o \ src/math/src/polyc.o \ src/math/src/polyf.o \ src/math/src/polycf.o \ src/math/src/math.o \ src/math/src/math.bessel.o \ src/math/src/math.gamma.o \ src/math/src/math.complex.o \ src/math/src/math.trig.o \ src/math/src/modular_arithmetic.o \ src/math/src/poly.findroots.o \ src/math/src/windows.o \ poly_prototypes := \ src/math/src/poly.common.proto.c \ src/math/src/poly.expand.proto.c \ src/math/src/poly.lagrange.proto.c \ src/math/src/poly.o : %.o : %.c $(include_headers) $(poly_prototypes) src/math/src/polyc.o : %.o : %.c $(include_headers) $(poly_prototypes) src/math/src/polyf.o : %.o : %.c $(include_headers) $(poly_prototypes) src/math/src/polycf.o : %.o : %.c $(include_headers) $(poly_prototypes) src/math/src/math.o : %.o : %.c $(include_headers) src/math/src/math.bessel.o : %.o : %.c $(include_headers) src/math/src/math.gamma.o : %.o : %.c $(include_headers) src/math/src/math.complex.o : %.o : %.c $(include_headers) src/math/src/math.trig.o : %.o : %.c $(include_headers) src/math/src/modular_arithmetic.o : %.o : %.c $(include_headers) src/math/src/windows.o : %.o : %.c $(include_headers) math_autotests := \ src/math/tests/gcd_autotest.c \ src/math/tests/math_window_autotest.c \ src/math/tests/math_autotest.c \ src/math/tests/math_bessel_autotest.c \ src/math/tests/math_gamma_autotest.c \ src/math/tests/math_complex_autotest.c \ src/math/tests/polynomial_autotest.c \ src/math/tests/polynomial_findroots_autotest.c \ src/math/tests/prime_autotest.c \ math_benchmarks := \ src/math/bench/polyfit_benchmark.c \ # # MODULE : matrix # matrix_objects := \ src/matrix/src/matrix.o \ src/matrix/src/matrixf.o \ src/matrix/src/matrixc.o \ src/matrix/src/matrixcf.o \ src/matrix/src/smatrix.common.o \ src/matrix/src/smatrixb.o \ src/matrix/src/smatrixf.o \ src/matrix/src/smatrixi.o \ matrix_prototypes := \ src/matrix/src/matrix.base.proto.c \ src/matrix/src/matrix.cgsolve.proto.c \ src/matrix/src/matrix.chol.proto.c \ src/matrix/src/matrix.gramschmidt.proto.c \ src/matrix/src/matrix.inv.proto.c \ src/matrix/src/matrix.linsolve.proto.c \ src/matrix/src/matrix.ludecomp.proto.c \ src/matrix/src/matrix.qrdecomp.proto.c \ src/matrix/src/matrix.math.proto.c \ src/matrix/src/matrix.o : %.o : %.c $(include_headers) $(matrix_prototypes) src/matrix/src/matrixc.o : %.o : %.c $(include_headers) $(matrix_prototypes) src/matrix/src/matrixf.o : %.o : %.c $(include_headers) $(matrix_prototypes) src/matrix/src/matrixcf.o : %.o : %.c $(include_headers) $(matrix_prototypes) src/matrix/src/smatrixb.o : %.o : %.c $(include_headers) src/matrix/src/smatrix.proto.c src/matrix/src/smatrixf.o : %.o : %.c $(include_headers) src/matrix/src/smatrix.proto.c src/matrix/src/smatrixi.o : %.o : %.c $(include_headers) src/matrix/src/smatrix.proto.c # matrix autotest scripts matrix_autotests := \ src/matrix/tests/matrixcf_autotest.c \ src/matrix/tests/matrixf_autotest.c \ src/matrix/tests/smatrixb_autotest.c \ src/matrix/tests/smatrixf_autotest.c \ src/matrix/tests/smatrixi_autotest.c \ # additional autotest objects autotest_extra_obj += \ src/matrix/tests/data/matrixf_data_add.o \ src/matrix/tests/data/matrixf_data_aug.o \ src/matrix/tests/data/matrixf_data_cgsolve.o \ src/matrix/tests/data/matrixf_data_chol.o \ src/matrix/tests/data/matrixf_data_gramschmidt.o \ src/matrix/tests/data/matrixf_data_inv.o \ src/matrix/tests/data/matrixf_data_linsolve.o \ src/matrix/tests/data/matrixf_data_ludecomp.o \ src/matrix/tests/data/matrixf_data_mul.o \ src/matrix/tests/data/matrixf_data_qrdecomp.o \ src/matrix/tests/data/matrixf_data_transmul.o \ \ src/matrix/tests/data/matrixcf_data_add.o \ src/matrix/tests/data/matrixcf_data_aug.o \ src/matrix/tests/data/matrixcf_data_chol.o \ src/matrix/tests/data/matrixcf_data_inv.o \ src/matrix/tests/data/matrixcf_data_linsolve.o \ src/matrix/tests/data/matrixcf_data_ludecomp.o \ src/matrix/tests/data/matrixcf_data_mul.o \ src/matrix/tests/data/matrixcf_data_qrdecomp.o \ src/matrix/tests/data/matrixcf_data_transmul.o \ matrix_benchmarks := \ src/matrix/bench/matrixf_inv_benchmark.c \ src/matrix/bench/matrixf_linsolve_benchmark.c \ src/matrix/bench/matrixf_mul_benchmark.c \ src/matrix/bench/smatrixf_mul_benchmark.c \ # # MODULE : modem # modem_objects := \ src/modem/src/ampmodem.o \ src/modem/src/fskdem.o \ src/modem/src/fskmod.o \ src/modem/src/gmskdem.o \ src/modem/src/gmskmod.o \ src/modem/src/modem.shim.o \ src/modem/src/modemcf.o \ src/modem/src/modem_utilities.o \ src/modem/src/modem_apsk_const.o \ src/modem/src/modem_arb_const.o \ # explicit targets and dependencies modem_prototypes := \ src/modem/src/cpfskdem.proto.c \ src/modem/src/cpfskmod.proto.c \ src/modem/src/freqdem.proto.c \ src/modem/src/freqmod.proto.c \ src/modem/src/modem_common.proto.c \ src/modem/src/modem_psk.proto.c \ src/modem/src/modem_dpsk.proto.c \ src/modem/src/modem_ask.proto.c \ src/modem/src/modem_qam.proto.c \ src/modem/src/modem_apsk.proto.c \ src/modem/src/modem_bpsk.proto.c \ src/modem/src/modem_qpsk.proto.c \ src/modem/src/modem_ook.proto.c \ src/modem/src/modem_pi4dqpsk.proto.c \ src/modem/src/modem_sqam32.proto.c \ src/modem/src/modem_sqam128.proto.c \ src/modem/src/modem_arb.proto.c \ #src/modem/src/modem_demod_soft_const.c src/modem/src/modemcf.o : %.o : %.c $(include_headers) $(modem_prototypes) src/modem/src/modem.shim.o : %.o : %.c $(include_headers) src/modem/src/gmskmod.o : %.o : %.c $(include_headers) src/modem/src/gmskdem.o : %.o : %.c $(include_headers) src/modem/src/ampmodem.o : %.o : %.c $(include_headers) src/modem/src/freqmodem.o : %.o : %.c $(include_headers) src/modem/src/modem_utilities.o : %.o : %.c $(include_headers) src/modem/src/modem_apsk_const.o : %.o : %.c $(include_headers) src/modem/src/modem_arb_const.o : %.o : %.c $(include_headers) modem_autotests := \ src/modem/tests/ampmodem_autotest.c \ src/modem/tests/cpfskmodem_autotest.c \ src/modem/tests/freqmodem_autotest.c \ src/modem/tests/fskmodem_autotest.c \ src/modem/tests/gmskmodem_autotest.c \ src/modem/tests/modem_autotest.c \ src/modem/tests/modem_config_autotest.c \ src/modem/tests/modem_demodsoft_autotest.c \ src/modem/tests/modem_demodstats_autotest.c \ src/modem/tests/modem_utilities_autotest.c \ modem_benchmarks := \ src/modem/bench/freqdem_benchmark.c \ src/modem/bench/freqmod_benchmark.c \ src/modem/bench/fskdem_benchmark.c \ src/modem/bench/fskmod_benchmark.c \ src/modem/bench/gmskmodem_benchmark.c \ src/modem/bench/modem_modulate_benchmark.c \ src/modem/bench/modem_demodulate_benchmark.c \ src/modem/bench/modem_demodsoft_benchmark.c \ # # MODULE : multichannel # multichannel_objects := \ src/multichannel/src/firpfbch_crcf.o \ src/multichannel/src/firpfbch_cccf.o \ src/multichannel/src/ofdmframe.common.o \ src/multichannel/src/ofdmframegen.o \ src/multichannel/src/ofdmframesync.o \ $(multichannel_objects) : %.o : %.c $(include_headers) # list explicit targets and dependencies here multichannel_prototypes := \ src/multichannel/src/firpfbch.proto.c \ src/multichannel/src/firpfbch2.proto.c \ src/multichannel/src/firpfbchr.proto.c \ src/multichannel/src/firpfbch_crcf.o : %.o : %.c $(include_headers) $(multichannel_prototypes) src/multichannel/src/firpfbch_cccf.o : %.o : %.c $(include_headers) $(multichannel_prototypes) # autotests multichannel_autotests := \ src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c \ src/multichannel/tests/firpfbch_crcf_analyzer_autotest.c \ src/multichannel/tests/firpfbch_crcf_autotest.c \ src/multichannel/tests/firpfbch2_crcf_autotest.c \ src/multichannel/tests/firpfbchr_crcf_autotest.c \ src/multichannel/tests/ofdmframe_autotest.c \ # benchmarks multichannel_benchmarks := \ src/multichannel/bench/firpfbch_crcf_benchmark.c \ src/multichannel/bench/firpfbch2_crcf_benchmark.c \ src/multichannel/bench/firpfbchr_crcf_benchmark.c \ src/multichannel/bench/ofdmframesync_acquire_benchmark.c \ src/multichannel/bench/ofdmframesync_rxsymbol_benchmark.c \ # # MODULE : nco - numerically-controlled oscillator # nco_objects := \ src/nco/src/nco_crcf.o \ src/nco/src/nco.utilities.o \ nco_prototypes := \ src/nco/src/nco.proto.c \ src/nco/src/synth.proto.c \ src/nco/src/nco_crcf.o : %.o : %.c $(include_headers) $(nco_prototypes) src/nco/src/nco.utilities.o : %.o : %.c $(include_headers) # autotests nco_autotests := \ src/nco/tests/nco_crcf_autotest.c \ src/nco/tests/nco_crcf_frequency_autotest.c \ src/nco/tests/nco_crcf_mix_autotest.c \ src/nco/tests/nco_crcf_phase_autotest.c \ src/nco/tests/nco_crcf_pll_autotest.c \ src/nco/tests/nco_crcf_spectrum_autotest.c \ src/nco/tests/unwrap_phase_autotest.c \ # additional autotest objects autotest_extra_obj += \ src/nco/tests/data/nco_sincos_fsqrt1_2.o \ src/nco/tests/data/nco_sincos_fsqrt1_3.o \ src/nco/tests/data/nco_sincos_fsqrt1_5.o \ src/nco/tests/data/nco_sincos_fsqrt1_7.o \ # benchmarks nco_benchmarks := \ src/nco/bench/nco_benchmark.c \ src/nco/bench/vco_benchmark.c \ # # MODULE : optim - optimization # optim_objects := \ src/optim/src/chromosome.o \ src/optim/src/gasearch.o \ src/optim/src/gradsearch.o \ src/optim/src/optim.common.o \ src/optim/src/qnsearch.o \ src/optim/src/qs1dsearch.o \ src/optim/src/utilities.o \ $(optim_objects) : %.o : %.c $(include_headers) # autotests optim_autotests := \ src/optim/tests/gasearch_autotest.c \ src/optim/tests/gradsearch_autotest.c \ src/optim/tests/qnsearch_autotest.c \ src/optim/tests/qs1dsearch_autotest.c \ src/optim/tests/utility_autotest.c \ # benchmarks optim_benchmarks := # # MODULE : quantization # quantization_objects := \ src/quantization/src/compand.o \ src/quantization/src/quantizercf.o \ src/quantization/src/quantizerf.o \ src/quantization/src/quantizer.inline.o \ quantization_prototypes := \ src/quantization/src/quantizer.proto.c \ src/quantization/src/compand.o : %.o : %.c $(include_headers) src/quantization/src/quantizercf.o : %.o : %.c $(include_headers) $(quantization_prototypes) src/quantization/src/quantizerf.o : %.o : %.c $(include_headers) $(quantization_prototypes) src/quantization/src/quantizer.inline.o : %.o : %.c $(include_headers) # autotests quantization_autotests := \ src/quantization/tests/compand_autotest.c \ src/quantization/tests/quantize_autotest.c \ # benchmarks quantization_benchmarks := \ src/quantization/bench/quantizer_benchmark.c \ src/quantization/bench/compander_benchmark.c \ # # MODULE : random # random_objects := \ src/random/src/rand.o \ src/random/src/randn.o \ src/random/src/randexp.o \ src/random/src/randweib.o \ src/random/src/randgamma.o \ src/random/src/randnakm.o \ src/random/src/randricek.o \ src/random/src/scramble.o \ $(random_objects) : %.o : %.c $(include_headers) # autotests random_autotests := \ src/random/tests/scramble_autotest.c \ src/random/tests/random_autotest.c \ src/random/tests/random_distributions_autotest.c \ # benchmarks random_benchmarks := \ src/random/bench/random_benchmark.c \ # # MODULE : sequence # sequence_objects := \ src/sequence/src/bsequence.o \ src/sequence/src/msequence.o \ $(sequence_objects) : %.o : %.c $(include_headers) # autotests sequence_autotests := \ src/sequence/tests/bsequence_autotest.c \ src/sequence/tests/complementary_codes_autotest.c \ src/sequence/tests/msequence_autotest.c \ # benchmarks sequence_benchmarks := \ src/sequence/bench/bsequence_benchmark.c \ # # MODULE : utility # utility_objects := \ src/utility/src/bshift_array.o \ src/utility/src/byte_utilities.o \ src/utility/src/memory.o \ src/utility/src/msb_index.o \ src/utility/src/pack_bytes.o \ src/utility/src/shift_array.o \ src/utility/src/utility.o \ $(utility_objects) : %.o : %.c $(include_headers) # autotests utility_autotests := \ src/utility/tests/bshift_array_autotest.c \ src/utility/tests/count_bits_autotest.c \ src/utility/tests/pack_bytes_autotest.c \ src/utility/tests/shift_array_autotest.c \ # benchmarks utility_benchmarks := \ src/utility/bench/byte_utilities_benchmark.c \ # # MODULE : vector # # main objects list vector_objects := \ @MLIBS_VECTOR@ \ # portable builds src/vector/src/vectorf_add.port.o : %.o : %.c $(include_headers) src/vector/src/vector_add.proto.c src/vector/src/vectorf_norm.port.o : %.o : %.c $(include_headers) src/vector/src/vector_norm.proto.c src/vector/src/vectorf_mul.port.o : %.o : %.c $(include_headers) src/vector/src/vector_mul.proto.c src/vector/src/vectorf_trig.port.o : %.o : %.c $(include_headers) src/vector/src/vector_trig.proto.c src/vector/src/vectorcf_add.port.o : %.o : %.c $(include_headers) src/vector/src/vector_add.proto.c src/vector/src/vectorcf_norm.port.o : %.o : %.c $(include_headers) src/vector/src/vector_norm.proto.c src/vector/src/vectorcf_mul.port.o : %.o : %.c $(include_headers) src/vector/src/vector_mul.proto.c src/vector/src/vectorcf_trig.port.o : %.o : %.c $(include_headers) src/vector/src/vector_trig.proto.c # builds for specific architectures # ... # vector autotest scripts vector_autotests := # additional autotest objects autotest_extra_obj += # vector benchmark scripts vector_benchmarks := # Target collection # # Information about targets for each module is collected # in these variables objects := \ src/libliquid.o \ $(agc_objects) \ $(audio_objects) \ $(buffer_objects) \ $(channel_objects) \ $(dotprod_objects) \ $(equalization_objects) \ $(fec_objects) \ $(fft_objects) \ $(filter_objects) \ $(framing_objects) \ $(math_objects) \ $(matrix_objects) \ $(modem_objects) \ $(multichannel_objects) \ $(nco_objects) \ $(optim_objects) \ $(quantization_objects) \ $(random_objects) \ $(sequence_objects) \ $(utility_objects) \ $(vector_objects) \ $(objects) : %.o : %.c $(include_headers) autotest_sources := \ autotest/null_autotest.c \ autotest/libliquid_autotest.c \ $(agc_autotests) \ $(audio_autotests) \ $(buffer_autotests) \ $(channel_autotests) \ $(dotprod_autotests) \ $(equalization_autotests) \ $(fec_autotests) \ $(fft_autotests) \ $(filter_autotests) \ $(framing_autotests) \ $(math_autotests) \ $(matrix_autotests) \ $(modem_autotests) \ $(multichannel_autotests) \ $(nco_autotests) \ $(optim_autotests) \ $(quantization_autotests) \ $(random_autotests) \ $(sequence_autotests) \ $(utility_autotests) \ $(vector_autotests) \ benchmark_sources := \ bench/null_benchmark.c \ $(agc_benchmarks) \ $(audio_benchmarks) \ $(buffer_benchmarks) \ $(channel_benchmarks) \ $(dotprod_benchmarks) \ $(equalization_benchmarks) \ $(fec_benchmarks) \ $(fft_benchmarks) \ $(filter_benchmarks) \ $(framing_benchmarks) \ $(math_benchmarks) \ $(matrix_benchmarks) \ $(modem_benchmarks) \ $(multichannel_benchmarks) \ $(nco_benchmarks) \ $(optim_benchmarks) \ $(quantization_benchmarks) \ $(random_benchmarks) \ $(sequence_benchmarks) \ $(utility_benchmarks) \ $(vector_benchmarks) \ ## ## TARGET : all - build shared library (default) ## .PHONY: all # Shared library targets ARCHIVE_LIB = libliquid.${AR_LIB} SHARED_LIB = libliquid.${SH_LIB} # # darwin # libliquid.ar : $(objects) ${LIBTOOL} -static -o $@ $^ # gcc -dynamiclib -install_name libliquid.dylib -o libliquid.dylib libmodem.a libutility.a libliquid.dylib : $(objects) $(CC) -dynamiclib ${COVERAGE_FLAGS} -install_name $@ -o $@ $^ $(LDFLAGS) $(LIBS) # # linux, et al # libliquid.a : $(objects) ${AR} r $@ $^ ${RANLIB} $@ libliquid.so : libliquid.a $(CC) $(CFLAGS) $(LDFLAGS) -shared -Xlinker -soname=libliquid.so.$(SOVERSION) -o $@ -Wl,-whole-archive $^ -Wl,-no-whole-archive $(LIBS) # static archive and library objects all: ${ARCHIVE_LIB} ${SHARED_LIB} ## ## TARGET : help - print list of targets ## # look for all occurrences of '## TARGET : ' and print rest of line to screen help: @echo "Targets for liquid-dsp makefile:" @$(GREP) -E "^## TARGET : " [Mm]akefile | $(SED) 's/## TARGET : / /' ## ## TARGET : install - installs the libraries and header files in the host system ## install: all @echo "installing..." @echo "" mkdir -p $(DESTDIR)$(prefix)/include/liquid mkdir -p $(DESTDIR)$(libdir) install -m 644 -p libliquid.${AR_LIB} $(DESTDIR)$(libdir)/libliquid.${AR_LIB} install -m 644 -p libliquid.${SH_LIB} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} install -m 644 -p include/liquid.h $(DESTDIR)$(prefix)/include/liquid/liquid.h ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB} ln -sf libliquid.${SH_LIB}.${VERSION} $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${SOVERSION} @echo "" @echo "---------------------------------------------------------" @echo " liquid-dsp was successfully installed. " @echo "" @echo " On some machines (e.g. Linux) you should rebind your" @echo " libraries by running 'ldconfig' to make the shared" @echo " object available. You might also need to modify your" @echo " LD_LIBRARY_PATH environment variable to include the" @echo " directory $(DESTDIR)$(exec_prefix)" @echo "" @echo " Please report bugs to $(BUGREPORT)" @echo "---------------------------------------------------------" @echo "" ## ## TARGET : uninstall - uninstalls the libraries and header files in the host system ## #$(RM) $(addprefix $(DESTDIR)$(prefix)/include/liquid/, $(headers_install)) uninstall: @echo "uninstalling..." $(RM) $(DESTDIR)$(prefix)/include/liquid/liquid.h $(RM) $(DESTDIR)$(libdir)/libliquid.${AR_LIB} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${VERSION} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB}.${SOVERSION} $(RM) $(DESTDIR)$(libdir)/libliquid.${SH_LIB} @echo "done." ## ## autoscript ## autoscript : scripts/autoscript scripts/autoscript.o scripts/main.o : %.o : %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< scripts/autoscript : scripts/autoscript.o scripts/main.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) clean-autoscript : $(RM) scripts/autoscript.o scripts/main.o scripts/autoscript ## ## TARGET : check - build and run autotest scripts ## # Autotests are used to check the validity and accuracy of the # DSP libraries. .PHONY: autotest autotest_prog = xautotest # run the autotest generator script to create autotest_include.h autotest_include.h : scripts/autoscript $(autotest_sources) $(include_headers) ./scripts/autoscript $(PATHSEP) autotest $(autotest_sources) > $@ # autotest objects # NOTE: by default, gcc compiles any file with a '.h' extension as a 'pre-compiled # header' so we need to explicitly tell it to compile as a c source file with # the '-x c' flag autotest_obj = $(patsubst %.c,%.o,$(autotest_sources)) $(autotest_obj) $(autotest_extra_obj) autotest/autotest.o : %.o : %.c $(include_headers) autotest/autotest.h $(CC) $(CPPFLAGS) $(CFLAGS) $< -c -o $@ # compile the autotest program without linking $(autotest_prog).o : autotest/xautotest.c autotest/autotest.h autotest_include.h $(CC) $(CPPFLAGS) $(CFLAGS) $< -c -o $@ # link the autotest program with the objects # NOTE: linked libraries must come _after_ the target program $(autotest_prog): $(autotest_prog).o $(autotest_obj) $(autotest_extra_obj) autotest/autotest.o ${ARCHIVE_LIB} $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) # run the autotest program check: $(autotest_prog) ./$(autotest_prog) -v -o autotest.json # let 'make test' be an alias for 'make check' test: check # clean the generated files clean-check: $(RM) autotest_include.h $(autotest_prog).o $(autotest_prog) $(RM) $(autotest_obj) $(RM) $(autotest_extra_obj) $(RM) autotest/autotest.o $(RM) autotest.json $(RM) autotest/logs/*.m autotest/logs/*.dat $(RM) autotest/logs/*.bin autotest/logs/*.gnu autotest/logs/*.png ## ## TARGET : check-doc - build and run basic documentation checks ## readme.c.example.c : README.rst ${SED} -n '19,39p' $< | ${SED} "s//\"liquid.h\"/g" > $@ readme.c.example.o : %.o : %.c ${include_headers} ${CC} ${CPPFLAGS} ${CFLAGS} $< -c -o $@ readme.c.example : % : %.o ${ARCHIVE_LIB} ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LIBS} readme.cc.example.cc : README.rst ${SED} -n '190,210p' $< | ${SED} "s//\"liquid.h\"/g" > $@ readme.cc.example.o : %.o : %.cc ${include_headers} ${CXX} ${CPPFLAGS} ${CXXFLAGS} $< -c -o $@ readme.cc.example : % : %.o ${ARCHIVE_LIB} ${CXX} ${CXXFLAGS} ${LDFLAGS} $^ -o $@ ${LIBS} check-doc-c : readme.c.example ; ./readme.c.example check-doc-cc : readme.cc.example ; ./readme.cc.example check-doc : check-doc-c check-doc-cc clean-check-doc: ${RM} readme.*.example* ## ## TARGET : coverage - run coverage test and produce report ## coverage: coverage.out tail -n5 $< ${autotest_prog}.gcda : %.gcda : % ./${autotest_prog} coverage.out : ${autotest_prog}.gcda gcovr --root=src --exclude-directories=src/.*/tests --print-summary > $@ clean-coverage: $(RM) src/*.gcda src/*/src/*.gcda src/*/tests/*.gcda src/*/tests/data/*.gcda autotest/*.gcda scripts/*.gcda $(RM) src/*.gcno src/*/src/*.gcno src/*/tests/*.gcno src/*/tests/data/*.gcno autotest/*.gcno scripts/*.gcno $(RM) autotest/*.gcda bench/*.gcda examples/*.gcda sandbox/*.gcda $(RM) autotest/*.gcno bench/*.gcno examples/*.gcno sandbox/*.gcno $(RM) *.gcda *.gcno coverage.out ## ## TARGET : bench - build and run all benchmarks ## # Benchmarks measure the relative speed of the DSP algorithms running # on the target platform. .PHONY: bench bench_prog = benchmark BENCH_CPPFLAGS = $(CPPFLAGS) BENCH_CFLAGS = -Wall $(CFLAGS) BENCH_LDFLAGS = $(LDFLAGS) BENCH_LIBS = $(LIBS) # run the benchmark generator script to create benchmark_include.h benchmark_include.h : scripts/autoscript $(benchmark_sources) $(include_headers) ./scripts/autoscript $(PATHSEP) benchmark $(benchmark_sources) > $@ # benchmark objects # NOTE: by default, gcc compiles any file with a '.h' extension as a 'pre-compiled # header' so we need to explicitly tell it to compile as a c source file with # the '-x c' flag benchmark_obj = $(patsubst %.c,%.o,$(benchmark_sources)) $(benchmark_obj) : %.o : %.c $(include_headers) $(CC) $(BENCH_CPPFLAGS) $(BENCH_CFLAGS) $< -c -o $@ # additional benchmark objects $(benchmark_extra_obj) : %.o : %.c $(include_headers) # compile the benchmark program without linking $(bench_prog).o: bench/bench.c benchmark_include.h bench/bench.c $(CC) $(BENCH_CPPFLAGS) $(BENCH_CFLAGS) $< -c -o $(bench_prog).o # link the benchmark program with the library objects # NOTE: linked libraries must come _after_ the target program $(bench_prog): $(bench_prog).o $(benchmark_obj) $(benchmark_extra_obj) ${ARCHIVE_LIB} $(CC) $(BENCH_CFLAGS) $(BENCH_LDFLAGS) $^ -o $(bench_prog) $(BENCH_LIBS) # run the benchmark program bench: $(bench_prog) ./$(bench_prog) -o benchmark.json # fftbench program bench/fftbench.o : %.o : %.c $(CC) $(BENCH_CPPFLAGS) $(BENCH_CFLAGS) $< -c -o $@ bench/fftbench : % : %.o ${ARCHIVE_LIB} $(CC) $(BENCH_CFLAGS) $(BENCH_LDFLAGS) $^ -o $@ $(BENCH_LIBS) # clean up the generated files clean-bench: $(RM) benchmark_include.h $(bench_prog).o $(bench_prog) $(RM) $(benchmark_obj) $(RM) $(benchmark_extra_obj) $(RM) bench/fftbench.o $(RM) bench/fftbench ## ## TARGET : examples - build all examples binaries ## .PHONY: examples example_programs := \ examples/agc_crcf_example \ examples/agc_crcf_squelch_example \ examples/agc_crcf_qpsk_example \ examples/agc_rrrf_example \ examples/ampmodem_example \ examples/asgramcf_example \ examples/asgramf_example \ examples/autocorr_cccf_example \ examples/bpacketsync_example \ examples/bpresync_example \ examples/bsequence_example \ examples/cbufferf_example \ examples/cgsolve_example \ examples/channel_cccf_example \ examples/compand_example \ examples/compand_cf_example \ examples/complementary_codes_example \ examples/conversion_example \ examples/crc_example \ examples/cpfskmodem_example \ examples/cpfskmodem_psd_example \ examples/cvsd_example \ examples/detector_cccf_example \ examples/dds_cccf_example \ examples/dsssframe64sync_performance_example \ examples/dsssframe64sync_example \ examples/dsssframesync_example \ examples/dotprod_rrrf_example \ examples/dotprod_cccf_example \ examples/eqlms_cccf_block_example \ examples/eqlms_cccf_blind_example \ examples/eqlms_cccf_decisiondirected_example \ examples/eqlms_cccf_example \ examples/eqrls_cccf_example \ examples/error_handling_example \ examples/fec_example \ examples/fec_soft_example \ examples/fdelay_rrrf_example \ examples/fft_example \ examples/fftfilt_crcf_example \ examples/firdecim_crcf_example \ examples/firfarrow_rrrf_example \ examples/firfilt_cccf_example \ examples/firfilt_cccf_notch_example \ examples/firfilt_crcf_copy_example \ examples/firfilt_crcf_example \ examples/firfilt_crcf_dcblocker_example \ examples/firfilt_rrrf_example \ examples/firdes_doppler_example \ examples/firdes_kaiser_example \ examples/firdespm_callback_example \ examples/firdespm_halfband_example \ examples/firdespm_example \ examples/firdespm_lowpass_example \ examples/firhilb_example \ examples/firhilb_decim_example \ examples/firhilb_filter_example \ examples/firhilb_interp_example \ examples/firpfb_rrrf_example \ examples/firpfbch2_crcf_example \ examples/firpfbch2_crcf_reconstruct_example \ examples/firpfbchr_crcf_example \ examples/firinterp_crcf_example \ examples/firinterp_firdecim_crcf_example \ examples/firinterp_rrrf_linear_example \ examples/firinterp_rrrf_window_example \ examples/firpfbch_crcf_example \ examples/firpfbch_crcf_analysis_example \ examples/firpfbch_crcf_msource_example \ examples/firpfbch_crcf_synthesis_example \ examples/flexframesync_debug_example \ examples/flexframesync_example \ examples/flexframesync_reconfig_example \ examples/framesync64_example \ examples/framesync64_performance_example \ examples/freqmodem_example \ examples/fskframesync_example \ examples/fskmodem_example \ examples/fskmodem_waterfall_example \ examples/gasearch_example \ examples/gasearch_knapsack_example \ examples/gmskframesync_example \ examples/gmskmodem_example \ examples/gmskmodem_ber_example \ examples/gmsk_eqlms_example \ examples/gmsk_tracking_example \ examples/gradsearch_datafit_example \ examples/gradsearch_example \ examples/interleaver_example \ examples/interleaver_soft_example \ examples/interleaver_scatterplot_example \ examples/iirdes_example \ examples/iirdes_analog_example \ examples/iirdes_pll_example \ examples/iirdecim_crcf_example \ examples/iirfilt_cccf_example \ examples/iirfilt_crcf_example \ examples/iirfilt_crcf_dcblocker_example \ examples/iirfilt_rrrf_integrator_example \ examples/iirhilb_example \ examples/iirhilb_filter_example \ examples/iirinterp_crcf_example \ examples/kaiser_window_example \ examples/kbd_window_example \ examples/lpc_example \ examples/libliquid_example \ examples/matched_filter_example \ examples/math_lngamma_example \ examples/math_primitive_root_example \ examples/modem_arb_example \ examples/modem_ber_example \ examples/modem_example \ examples/modem_pi4dqpsk_example \ examples/modem_soft_example \ examples/modular_arithmetic_example \ examples/msequence_autocorr_example \ examples/msequence_example \ examples/msequence_generator_example \ examples/msourcecf_example \ examples/msresamp_crcf_example \ examples/msresamp_crcf_noise_example \ examples/msresamp2_crcf_example \ examples/nco_crcf_mix_example \ examples/nco_crcf_tone_example \ examples/nco_example \ examples/nco_pll_example \ examples/nco_pll_real_example \ examples/nco_pll_modem_example \ examples/nyquist_filter_example \ examples/ofdmflexframesync_example \ examples/ofdmframesync_example \ examples/ordfilt_rrrf_example \ examples/packetizer_example \ examples/packetizer_soft_example \ examples/pll_example \ examples/polyfit_comparison_example \ examples/polyfit_example \ examples/polyfit_lagrange_example \ examples/poly_findroots_example \ examples/qdetector_cccf_example \ examples/qdsync_cccf_example \ examples/qdsync_cccf_performance_example \ examples/qpacketmodem_performance_example \ examples/qpacketmodem_example \ examples/qpilotsync_example \ examples/qnsearch_example \ examples/qs1dsearch_example \ examples/quantize_example \ examples/random_histogram_example \ examples/repack_bytes_example \ examples/rresamp_crcf_example \ examples/rresamp_crcf_partition_example \ examples/rresamp_crcf_rnyquist_example \ examples/rresamp_rrrf_example \ examples/resamp_crcf_example \ examples/resamp_crcf_noise_example \ examples/resamp_crcf_rate_match_example \ examples/resamp2_cccf_example \ examples/resamp2_crcf_example \ examples/resamp2_crcf_decim_example \ examples/resamp2_crcf_filter_example \ examples/resamp2_crcf_interp_example \ examples/ricek_channel_example \ examples/scramble_example \ examples/smatrix_example \ examples/spgramcf_example \ examples/spgramf_example \ examples/spwaterfallcf_example \ examples/symsync_crcf_example \ examples/symsync_crcf_full_example \ examples/symsync_crcf_kaiser_example \ examples/symstreamcf_delay_example \ examples/symstreamcf_example \ examples/symstreamrcf_delay_example \ examples/symstreamrcf_example \ examples/symtrack_cccf_example \ examples/wdelayf_example \ examples/windowf_example \ examples/window_enbw_example \ examples/windowing_example \ # examples/metadata_example # examples/ofdmframegen_example # examples/gmskframe_example # examples/fading_generator_example example_objects = $(patsubst %,%.o,$(example_programs)) examples: $(example_programs) # NOTE: linked libraries must come _after_ the target program $(example_objects): %.o : %.c $(example_programs): % : %.o ${ARCHIVE_LIB} $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) # clean examples clean-examples: $(RM) examples/*.o $(RM) $(example_programs) ## ## TARGET : sandbox - build all sandbox binaries ## # NOTE: sandbox _requires_ fftw3 to build .PHONY: sandbox sandbox_programs = \ sandbox/am_demod_dsb_peak_detect_test \ sandbox/am_demod_dsb_pll_carrier_test \ sandbox/am_demod_dsb_pll_costas_test \ sandbox/am_demod_ssb_pll_carrier_test \ sandbox/bpresync_test \ sandbox/chromosome_test \ sandbox/cpmodem_test \ sandbox/count_ones_gentab \ sandbox/crc_gentab \ sandbox/ellip_func_test \ sandbox/ellip_test \ sandbox/eqlms_cccf_test \ sandbox/fecsoft_ber_test \ sandbox/fec_g2412product_test \ sandbox/fec_golay2412_test \ sandbox/fec_golay_test \ sandbox/fec_hamming3126_example \ sandbox/fec_hamming128_test \ sandbox/fec_hamming128_gentab \ sandbox/fec_hamming128_example \ sandbox/fec_hamming74_gentab \ sandbox/fec_hamming84_gentab \ sandbox/fec_hamming_test \ sandbox/fec_ldpc_test \ sandbox/fec_rep3_test \ sandbox/fec_rep5_test \ sandbox/fec_secded2216_test \ sandbox/fec_secded3932_test \ sandbox/fec_secded7264_test \ sandbox/fec_spc2216_test \ sandbox/fec_secded_punctured_test \ sandbox/fecsoft_conv_test \ sandbox/fecsoft_hamming128_gentab \ sandbox/fecsoft_ldpc_test \ sandbox/fec_sumproduct_test \ sandbox/fskcorr_test \ sandbox/fskmodem_test \ sandbox/fft_dual_radix_test \ sandbox/fft_mixed_radix_test \ sandbox/fft_recursive_plan_test \ sandbox/fft_recursive_test \ sandbox/fft_rader_prime_test \ sandbox/fft_rader_prime_radix2_test \ sandbox/fft_r2r_test \ sandbox/firdes_energy_test \ sandbox/firdes_fexp_test \ sandbox/firdes_gmskrx_test \ sandbox/firdes_group_delay_test \ sandbox/firdes_length_test \ sandbox/firdespm_halfband_test \ sandbox/firfarrow_rrrf_test \ sandbox/firfilt_dcblocker_test \ sandbox/firpfbch_analysis_alignment_test \ sandbox/firpfbch2_analysis_equivalence_test \ sandbox/firpfbch2_test \ sandbox/firpfbch2_flatness_test \ sandbox/firpfbch_analysis_equivalence_test \ sandbox/firpfbch_synthesis_equivalence_test \ sandbox/gmskmodem_test \ sandbox/gmskmodem_coherent_test \ sandbox/gmskmodem_equalizer_test \ sandbox/gmskmodem_psd_filter_compare_test \ sandbox/householder_test \ sandbox/iirdes_test \ sandbox/iirdes_gradsearch_test \ sandbox/iirfilt_intdiff_test \ sandbox/levinson_test \ sandbox/matched_filter_test \ sandbox/matched_filter_cfo_test \ sandbox/math_lngamma_test \ sandbox/math_cacosf_test \ sandbox/math_casinf_test \ sandbox/math_catanf_test \ sandbox/math_cexpf_test \ sandbox/math_clogf_test \ sandbox/math_csqrtf_test \ sandbox/matrix_test \ sandbox/minsearch_test \ sandbox/minsearch2_test \ sandbox/matrix_eig_test \ sandbox/modem_demodulate_arb_gentab \ sandbox/modem_demodulate_soft_test \ sandbox/modem_demodulate_soft_gentab \ sandbox/mskmodem_test \ sandbox/msresamp_crcf_test \ sandbox/ofdmoqam_firpfbch_test \ sandbox/ofdm_ber_test \ sandbox/ofdmframe_papr_test \ sandbox/ofdmframesync_cfo_test \ sandbox/pll_3rd_order_test \ sandbox/pll_design_test \ sandbox/predemod_sync_test \ sandbox/quasinewton_test \ sandbox/recursive_qpsk_test \ sandbox/resamp2_crcf_filterbank_test \ sandbox/resamp2_crcf_interp_recreate_test \ sandbox/reverse_byte_gentab \ sandbox/rhamming_test \ sandbox/rkaiser2_test \ sandbox/shadowing_test \ sandbox/simplex_test \ sandbox/symsync_crcf_test \ sandbox/symsync_eqlms_test \ sandbox/svd_test \ sandbox/thiran_allpass_iir_test \ sandbox/vectorcf_test \ # sandbox/packetizer_persistent_ber_test # firpfbch_analysis_test # sandbox/ofdmoqam_firpfbch_cfo_test # sandbox/mdct_test # sandbox/fct_test # sandbox/throttle_test # needs -lrt for certain gcc versions, rpi3 sandbox_objects = $(patsubst %,%.o,$(sandbox_programs)) sandbox: $(sandbox_programs) SANDBOX_LDFLAGS = $(LDFLAGS) -lfftw3f # NOTE: linked libraries must come _after_ the target program $(sandbox_objects): %.o : %.c $(sandbox_programs): % : %.o ${ARCHIVE_LIB} $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(LIBS) # clean sandbox clean-sandbox: $(RM) sandbox/*.o $(RM) $(sandbox_programs) ## ## TARGET : check-link- test linking to installed library ## # run program, ensuring proper error code check-link: scripts/liquid_linker_test ; ./$< # use subset of compiler flags so we don't try to build or link against # local files scripts/liquid_linker_test.o : %.o : %.c $(CC) -c -Wall -O2 -o $@ $< scripts/liquid_linker_test : % : %.o $(CC) -Wall -O2 -o $@ $< -L/usr/local/lib ${LIBS} -lliquid extra_clean += scripts/liquid_linker_test.o scripts/liquid_linker_test ## ## TARGET : programs - build all programs, but don't run anything ## programs: all xautotest benchmark examples sandbox ## ## TARGET : world - build absolutely everything ## world : all bench check check-doc examples sandbox ## ## TARGET : clean - clean build (objects, dependencies, libraries, etc.) ## .PHONY: clean clean-modules: @echo "cleaning modules..." $(RM) src/*/src/*.o src/*/bench/*.o src/*/tests/*.o $(RM) src/libliquid.o clean: clean-modules clean-autoscript clean-check clean-coverage clean-bench clean-examples clean-sandbox clean-check-doc $(RM) ${ARCHIVE_LIB} ${SHARED_LIB} $(extra_clean) ## ## TARGET : distclean - removes everything except the originally distributed files ## distclean: clean @echo "cleaning distribution..." $(RM) octave-core *_example.m $(RM) configure config.h config.h.in config.h.in~ config.log config.status $(RM) -r autom4te.cache $(RM) aclocal.m4 $(RM) makefile liquid-dsp-1.7.0/sandbox/000077500000000000000000000000001474751757600152575ustar00rootroot00000000000000liquid-dsp-1.7.0/sandbox/.gitignore000066400000000000000000000001111474751757600172400ustar00rootroot00000000000000# ignore all temporary file *.m *.swp # ignore all program files *_test liquid-dsp-1.7.0/sandbox/CMakeLists.txt000066400000000000000000000056341474751757600200270ustar00rootroot00000000000000# build configuration for sandbox programs set(SANDBOX am_demod_dsb_peak_detect_test am_demod_dsb_pll_carrier_test am_demod_dsb_pll_costas_test am_demod_ssb_pll_carrier_test bpresync_test chromosome_test count_ones_gentab cpmodem_test crc_gentab ellip_func_test ellip_test eqlms_cccf_test #fct_test fec_g2412product_test fec_golay2412_test fec_golay_test fec_hamming128_example fec_hamming128_gentab fec_hamming128_test fec_hamming3126_example fec_hamming74_gentab fec_hamming84_gentab fec_hamming_test fec_ldpc_test fec_rep3_test fec_rep5_test fec_secded2216_test fec_secded3932_test fec_secded7264_test fec_secded_punctured_test fec_spc2216_test fec_sumproduct_test fecsoft_ber_test fecsoft_conv_test fecsoft_hamming128_gentab fecsoft_ldpc_test fft_dual_radix_test fft_mixed_radix_test fft_r2r_test fft_rader_prime_radix2_test fft_rader_prime_test fft_recursive_plan_test fft_recursive_test firdes_energy_test firdes_fexp_test firdes_gmskrx_test firdes_group_delay_test firdes_length_test firdespm_halfband_test firfarrow_rrrf_test firfilt_dcblocker_test firpfbch2_analysis_equivalence_test firpfbch2_flatness_test firpfbch2_test firpfbch_analysis_alignment_test firpfbch_analysis_equivalence_test #firpfbch_analysis_test firpfbch_synthesis_equivalence_test fskcorr_test fskmodem_test gmskmodem_coherent_test gmskmodem_equalizer_test gmskmodem_psd_filter_compare_test gmskmodem_test householder_test iirdes_gradsearch_test iirdes_test iirfilt_intdiff_test levinson_test matched_filter_cfo_test matched_filter_test math_cacosf_test math_casinf_test math_catanf_test math_cexpf_test math_clogf_test math_csqrtf_test math_lngamma_test matrix_eig_test matrix_test #mdct_test minsearch2_test minsearch_test modem_demodulate_arb_gentab modem_demodulate_soft_gentab modem_demodulate_soft_test mskmodem_test msresamp_crcf_test #newbench_example ofdm_ber_test ofdmframe_papr_test ofdmframesync_cfo_test #ofdmoqam_firpfbch_cfo_test ofdmoqam_firpfbch_test #packetizer_persistent_ber_test pll_3rd_order_test pll_design_test predemod_sync_test quasinewton_test recursive_qpsk_test resamp2_crcf_filterbank_test resamp2_crcf_interp_recreate_test reverse_byte_gentab rhamming_test rkaiser2_test shadowing_test simplex_test svd_test symsync_crcf_test symsync_eqlms_test thiran_allpass_iir_test throttle_test vectorcf_test ) foreach(example IN LISTS SANDBOX) add_executable(${example} ${example}.c) target_include_directories(${example} PRIVATE ${INCLUDE}) target_link_libraries(${example} ${LIBNAME}) endforeach() liquid-dsp-1.7.0/sandbox/README.md000066400000000000000000000007301474751757600165360ustar00rootroot00000000000000 liquid-dsp sandbox ================== This directory is the sandbox for prototyping DSP processing elements in liquid. It contains a number of scripts which are used for testing and prototyping certain signal processing algorithms. Its primary function is to validate functional correctness without adding unnecessary code to the main project files. All the programs in this directory can be build by invoking 'make' from the root directory, viz. $ make sandbox liquid-dsp-1.7.0/sandbox/am_demod_dsb_peak_detect_test.c000066400000000000000000000076401474751757600234160ustar00rootroot00000000000000// Test double side-band (DSB) amplitude modulation (AM) using // very simple peak-detection (non-coherent). #include #include #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options float mod_index = 0.5f; // modulation index (bandwidth) float phi = 0.8f; // carrier phase offset [radians] float dphi = 0.10f; // carrier frequency offset [radians/sample] float SNRdB = 30.0f; // signal-to-noise ratio (set very high for testing) unsigned int num_samples = 2400; // number of samples const char * filename = "am_demod_dsb_peak_detect_test.m"; // buffers unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; // generate 'audio' signal (simple windowed sum of tones) unsigned int nw = (unsigned int)(0.90*num_samples); // window length unsigned int nt = (unsigned int)(0.05*num_samples); // taper length for (i=0; i M_PI) phi -= 2*M_PI; while (phi < -M_PI) phi += 2*M_PI; } // demodulate signal (non-coherent) float delay = 0; iirfilt_rrrf dcblock = iirfilt_rrrf_create_dc_blocker(0.02f); for (i=0; i #include #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options float mod_index = 0.5f; // modulation index (bandwidth) float phi = 0.8f; // carrier phase offset [radians] float dphi = 0.10f; // carrier frequency offset [radians/sample] float SNRdB = 30.0f; // signal-to-noise ratio (set very high for testing) unsigned int num_samples = 2400; // number of samples const char * filename = "am_demod_dsb_pll_carrier_test.m"; // buffers unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; // generate 'audio' signal (simple windowed sum of tones) unsigned int nw = (unsigned int)(0.90*num_samples); // window length unsigned int nt = (unsigned int)(0.05*num_samples); // taper length for (i=0; i M_PI) phi -= 2*M_PI; while (phi < -M_PI) phi += 2*M_PI; } // demodulate signal float delay = 0; nco_crcf mixer = nco_crcf_create(LIQUID_VCO); nco_crcf_pll_set_bandwidth(mixer,0.01f); iirfilt_crcf dcblock = iirfilt_crcf_create_dc_blocker(0.02f); for (i=0; i #include #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options float mod_index = 1.0f; // modulation index float phi = 0.8f; // carrier phase offset [radians] float dphi = 0.10f; // carrier frequency offset [radians/sample] float SNRdB = 30.0f; // signal-to-noise ratio (set very high for testing) unsigned int num_samples = 2400; // number of samples const char * filename = "am_demod_dsb_pll_costas_test.m"; // buffers unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; float p[num_samples]; // phase error // generate 'audio' signal (simple windowed sum of tones) unsigned int nw = (unsigned int)(0.90*num_samples); // window length unsigned int nt = (unsigned int)(0.05*num_samples); // taper length for (i=0; i M_PI) phi -= 2*M_PI; while (phi < -M_PI) phi += 2*M_PI; } // demodulate signal float delay = 0; nco_crcf mixer = nco_crcf_create(LIQUID_VCO); nco_crcf_pll_set_bandwidth(mixer,0.01f); for (i=0; i #include #include #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options float mod_index = 0.5f; // modulation index (bandwidth) int usb = 1; // upper (or lower) side band float phi = 0.8f; // carrier phase offset [radians] float dphi = 0.10f; // carrier frequency offset [radians/sample] float SNRdB = 30.0f; // signal-to-noise ratio (set very high for testing) unsigned int num_samples = 2400; // number of samples unsigned int m = 25; // Hilbert transform semi-length float As = 60.0f; // Hilbert transform stop-band suppression const char * filename = "am_demod_ssb_pll_carrier_test.m"; // buffers unsigned int i; float x[num_samples]; float complex y[num_samples]; float z[num_samples]; // generate 'audio' signal (simple windowed sum of tones) unsigned int nw = (unsigned int)(0.80*num_samples); // window length unsigned int nt = (unsigned int)(0.05*num_samples); // taper length for (i=0; i M_PI) phi -= 2*M_PI; while (phi < -M_PI) phi += 2*M_PI; } // demodulate signal float delay = 4*m; nco_crcf mixer = nco_crcf_create(LIQUID_VCO); nco_crcf_pll_set_bandwidth(mixer,0.001f); iirfilt_crcf dcblock = iirfilt_crcf_create_dc_blocker(0.02f); firhilbf_reset(hilbert); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "bpresync_test.m" // print usage/help message void usage() { printf("bpresync_test -- test binary pre-demodulation synchronization\n"); printf(" h : print usage/help\n"); printf(" v : increase output verbosity\n"); printf(" q : decrease output verbosity\n"); printf(" k : samples/symbol, default: 2\n"); printf(" n : number of data symbols, default: 64\n"); printf(" F : carrier frequency offset, default: 0.02\n"); printf(" S : SNR [dB], default: 20\n"); printf(" t : number of trials, default: 1000\n"); } void bpresync_test(bpresync_cccf _q, float complex * _x, unsigned int _n, float _SNRdB, float _dphi_max, float * _rxy_max, float * _dphi_err, float * _delay_err, unsigned int _num_trials, unsigned int _verbosity); int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int num_sync_symbols = 64; // number of synchronization symbols float SNRdB = 20.0f; // signal-to-noise ratio [dB] float dphi_max = 0.02f; // maximum carrier frequency offset unsigned int num_trials = 1000; // number of trials to run int verbosity = 1; // verbosity level int dopt; while ((dopt = getopt(argc,argv,"hvqk:n:F:S:t:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'v': verbosity++; break; case 'q': verbosity--; break; case 'k': k = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'F': dphi_max = atof(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': num_trials = atoi(optarg); break; default: exit(1); } } unsigned int i; // arrays float complex seq[k*num_sync_symbols]; // synchronization pattern (samples) float rxy_max[num_trials]; float dphi_err[num_trials]; float delay_err[num_trials]; // generate synchronization pattern (BPSK) and interpolate unsigned int n=0; for (i=0; i _rxy_max[t] ) { _rxy_max[t] = cabsf(rxy); _dphi_err[t] = dphi_est - dphi; _delay_err[t] = (float)i - (float)(_n + delay + (h_len-1)/2) + 1.0f + dt; } } if (_verbosity == 0) { // do nothing } else if (_verbosity == 1) { // print progress bar if ( (t%100)==0 || t==_num_trials-1 ) { float percent = (float)(t+1) / (float)_num_trials; unsigned int bars = (unsigned int) (percent*60); printf("["); for (i=0; i<60; i++) printf("%c", i < bars ? '#' : ' '); printf("] %5.1f%%\r", percent*100); fflush(stdout); } } else { // print every trial printf(" %6u: rxy_max=%12.8f, dphi-err=%12.8f, delay-err=%12.8f\n", t, _rxy_max[t], _dphi_err[t], _delay_err[t]); } } // destroy Farrow filter firfarrow_crcf_destroy(fdelay); } liquid-dsp-1.7.0/sandbox/chromosome_test.c000066400000000000000000000035121474751757600206360ustar00rootroot00000000000000// // chromosome_example.c // #include #include #include "liquid.internal.h" int main() { unsigned int bits_per_trait[] = {4, 8, 8, 4}; chromosome p1 = chromosome_create(bits_per_trait, 4); chromosome p2 = chromosome_create(bits_per_trait, 4); chromosome c = chromosome_create(bits_per_trait, 4); // 0000 11111111 00000000 1111 p1->traits[0] = 0x0; p1->traits[1] = 0xFF; p1->traits[2] = 0x00; p1->traits[3] = 0xF; // 0101 01010101 01010101 0101 p2->traits[0] = 0x5; p2->traits[1] = 0x55; p2->traits[2] = 0x55; p2->traits[3] = 0x5; printf("parent [1]:\n"); chromosome_print(p1); printf("parent [2]:\n"); chromosome_print(p2); printf("\n\n"); // // test crossover // printf("testing crossover...\n"); chromosome_crossover(p1, p2, c, 0); // .... ........ ........ .... // 0101 01010101 01010101 0101 chromosome_print(c); chromosome_crossover(p1, p2, c, 4); // 0000 ........ ........ .... // .... 01010101 01010101 0101 chromosome_print(c); chromosome_crossover(p1, p2, c, 6); // 0000 11...... ........ .... // .... ..010101 01010101 0101 chromosome_print(c); chromosome_crossover(p1, p2, c, 14); // 0000 11111111 00...... .... // .... ........ ..010101 0101 chromosome_print(c); chromosome_crossover(p1, p2, c, 24); // 0000 11111111 00000000 1111 // .... ........ ........ .... chromosome_print(c); // // test mutation // printf("testing mutation...\n"); unsigned int i; for (i=0; i<24; i++) { chromosome_reset(c); chromosome_mutate(c,i); // 0000 01000000 00000000 0000 chromosome_print(c); } chromosome_destroy(p1); chromosome_destroy(p2); chromosome_destroy(c); return 0; } liquid-dsp-1.7.0/sandbox/count_ones_gentab.c000066400000000000000000000047371474751757600211320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // generate tables for counting ones in a byte // #include #include // slow implementation counting ones in a byte unsigned int count_ones(unsigned char _x) { unsigned int n=0; unsigned int i; for (i=0; i<8; i++) n += (_x >> i) & 0x01; return n; } int main() { unsigned int i; printf("// auto-generated file (do not edit)\n"); printf("\n"); printf("// number of ones in a byte\n"); printf("unsigned const char liquid_c_ones[256] = {\n "); for (i=0; i<256; i++) { // unsigned int n = count_ones((unsigned char)i); // print results printf("%1u", n); if ( i != 255 ) { printf(","); if ( ((i+1)%16)==0 ) printf("\n "); else printf(" "); } } printf("};\n\n"); // do the same modulo 2 printf("// number of ones in a byte modulo 2\n"); printf("unsigned const char liquid_c_ones_mod2[256] = {\n "); for (i=0; i<256; i++) { // unsigned int n = count_ones((unsigned char)i); // print results printf("%1u", n % 2); if ( i != 255 ) { printf(","); if ( ((i+1)%16)==0 ) printf("\n "); else printf(" "); } } printf("};\n\n"); return 0; } liquid-dsp-1.7.0/sandbox/cpmodem_test.c000066400000000000000000000115571474751757600201170ustar00rootroot00000000000000// // cpmodem_test.c // // This example demonstrates how the use the nco/pll object // (numerically-controlled oscillator with phase-locked loop) interface for // tracking to a complex sinusoid. The loop bandwidth, phase offset, and // other parameter can be specified via the command-line interface. // // SEE ALSO: nco_example.c // nco_pll_modem_example.c // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "cpmodem_test.m" // print usage/help message void usage() { printf("cpmodem_test [options]\n"); printf(" h : print usage\n"); printf(" m : bits per symbol, default: 2\n"); printf(" n : number of symbols, default: 20\n"); printf(" p : phase offset (radians), default: pi/4\n"); printf(" f : frequency offset (radians), default: 0.3\n"); } int main(int argc, char*argv[]) { srand( time(NULL) ); // parameters float phase_offset = M_PI / 4.0f; float frequency_offset = 0.1f; unsigned int m = 2; // bits per symbol unsigned int num_symbols=20; // number of iterations int dopt; while ((dopt = getopt(argc,argv,"uhm:n:p:f:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 'p': phase_offset = atof(optarg); break; case 'f': frequency_offset= atof(optarg); break; default: exit(1); } } // derived values unsigned int M = 1< #include // generator polynomial #define CRC32_POLY 0xEDB88320 // 0x04C11DB7 int main() { unsigned int crc; unsigned int mask; unsigned int crcpoly = CRC32_POLY; unsigned int crc_gentab[256]; // generate table unsigned int i, j; for (i=0; i<256; i++) { crc = i; for (j=0; j<8; j++) { mask = -(crc & 0x01); crc = (crc >> 1) ^ (crcpoly & mask); } crc_gentab[i] = crc; } printf("\n"); printf("unsigned char crc_gentab[%u] = {\n ", 256); for (i=0; i<256; i++) { printf("0x%.2x", crc_gentab[i]); if (i==255) printf("};\n"); else if (((i+1)%8)==0) printf(",\n "); else printf(", "); } // test it... return 0; } liquid-dsp-1.7.0/sandbox/ellip_func_test.c000066400000000000000000000015651474751757600206110ustar00rootroot00000000000000// // ellip_func_test.c // // gcc -I. -I./include -lm libliquid.a ellip_func_test.c -o ellip_func_test // #include #include #include "include/liquid.h" #include "src/filter/src/ellip.c" int main() { float complex u = 0.7f; float k = 0.8f; unsigned int n=7; float complex cd = ellip_cdf(u,k,n); float complex sn = ellip_snf(u,k,n); printf("u : %12.8f + j*%12.8f\n", crealf(u), cimagf(u)); printf("k : %12.8f\n", k); printf("cd : %12.8f + j*%12.8f\n", crealf(cd), cimagf(cd)); printf("sn : %12.8f + j*%12.8f\n", crealf(sn), cimagf(sn)); printf("\n"); float complex acd = ellip_acdf(cd,k,n); float complex asn = ellip_asnf(sn,k,n); printf("acd : %12.8f + j*%12.8f\n", crealf(acd), cimagf(acd)); printf("asn : %12.8f + j*%12.8f\n", crealf(asn), cimagf(asn)); printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/ellip_test.c000066400000000000000000000050201474751757600175640ustar00rootroot00000000000000// // elliptest.c // // gcc -I. -I./include -lm libliquid.a elliptest.c -o elliptest // #include #include #include "include/liquid.h" #include "src/filter/src/ellip.c" int main() { // filter specifications float fp = 4.0f; float fs = 4.5f; float Gp = 0.95f; float Gs = 0.05f; unsigned int n=7; // number of iterations float Wp = 2*M_PI*fp; float Ws = 2*M_PI*fs; // ripples passband, stopband float ep = sqrtf(1.0f/(Gp*Gp) - 1.0f); float es = sqrtf(1.0f/(Gs*Gs) - 1.0f); printf("ep, es : %12.8f, %12.8f\n", ep, es); float k = Wp/Ws; // 0.8889f; float k1 = ep/es; // 0.0165f; float K, Kp; float K1, K1p; ellipkf(k, n, &K, &Kp); // K = 2.23533416, Kp = 1.66463780 ellipkf(k1,n, &K1, &K1p); // K1 = 1.57090271, K1p = 5.49361753 printf("K, Kp : %12.8f, %12.8f\n", K, Kp); printf("K1, K1p : %12.8f, %12.8f\n", K1, K1p); float Nexact = (K1p/K1)/(Kp/K); // 4.69604063 float N = ceilf(Nexact); // 5 printf("N (exact) : %12.8f\n", Nexact); printf("N : %12.8f\n", N); k = ellipdegf(N,k1,n); // 0.91427171 printf("k : %12.8f\n", k); float fs_new = fp/k; // 4.37506723 printf("fs_new : %12.8f\n", fs_new); unsigned int L = (unsigned int)(floorf(N/2.0f)); // 2 //unsigned int r = ((unsigned int)N) % 2; float u[L]; unsigned int i; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "eqlms_cccf_test.m" int main() { // options unsigned int k=2; // samples/symbol unsigned int m=3; float beta = 0.3f; //float dt = 0.4f; // timing offset unsigned int num_symbols = 256; unsigned int hc_len=1; // channel impulse response length unsigned int p=13; // equalizer filter length float mu = 0.05f; // TODO : validate input // derived values unsigned int num_samples = k*num_symbols; // data arrays float complex s[num_symbols]; // original QPSK symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // received samples float complex z[num_samples]; // recovered samples // generate data sequence unsigned int i; for (i=0; i 0.0f ? 1.0f : -1.0f) + (cimagf(d_hat) > 0.0f ? 1.0f : -1.0f) * _Complex_I; // compute error float complex alpha = d_prime - d_hat; // compute signal energy float ex2 = 1.414f; // update weighting vector for (j=0; j #include #include #include "liquid.h" int main() { unsigned int n=16; float x[n]; // time-domain 'signal' float y[n]; // fft(x) float z[n]; // ifft(y) unsigned int i; for (i=0; i #include #include #include #include "liquid.internal.h" #define DEBUG (0) typedef struct g2412p_s * g2412p; g2412p g2412p_create (); void g2412p_destroy (g2412p _q); void g2412p_print (g2412p _q); void g2412p_encode (g2412p _q, unsigned char * _msg_org, unsigned char * _msg_enc); void g2412p_decode (g2412p _q, unsigned char * _msg_rec, unsigned char * _msg_dec); int g2412p_iterate (g2412p _q); int g2412p_step (g2412p _q); void g2412p_load_row(g2412p _q, unsigned int _row); void g2412p_save_row(g2412p _q, unsigned int _row); void g2412p_load_col(g2412p _q, unsigned int _col); void g2412p_save_col(g2412p _q, unsigned int _col); // pack 24-value soft-bit message into integer unsigned int g2412p_pack_symbol(unsigned char * _msg_soft); // unpack 24-bit integer into soft array void g2412p_unpack_symbol(unsigned int _msg_hard, unsigned char * _msg_soft); unsigned int liquid_hard_decision(unsigned char _soft_bit); void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; printf(" "); for (i=0; i<_n; i++) printf("%1u ", (_x >> (_n-i-1)) & 1); printf("\n"); } int main(int argc, char*argv[]) { unsigned int i; unsigned int j; unsigned char msg_org[144]; unsigned char msg_enc[576]; unsigned char msg_rec[576]; unsigned char msg_dec[144]; // create object to handle encoding/decoding g2412p q = g2412p_create(); // initialize input array unsigned char p = 0x01; for (i=0; i<144; i++) { //msg_org[i] = i % 2; msg_org[i] = p & 1; p = ((p << 1) & 0xfe) | liquid_bdotprod(p,0xad); msg_org[i] = 0; } #if DEBUG // print original message printf("msg_org:\n"); for (i=0; i<12; i++) { printf("%3u: ", i); for (j=0; j<12; j++) printf("%2u", msg_org[12*i+j]); printf("\n"); } #endif // encode message g2412p_encode(q, msg_org, msg_enc); #if DEBUG // print encoded message printf("msg_enc:\n"); for (i=0; i<24; i++) { printf("%3u: ", i); for (j=0; j<24; j++) printf("%2u", msg_enc[24*i+j]); printf("\n"); } #endif #if 0 // corrupt message for (i=0; i<576; i++) msg_rec[i] = msg_enc[i] ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; msg_rec[ 0] = 255 - msg_rec[ 0]; msg_rec[ 24] = 255 - msg_rec[ 24]; msg_rec[ 48] = 255 - msg_rec[ 48]; msg_rec[ 72] = 255 - msg_rec[ 72]; msg_rec[ 96] = 255 - msg_rec[ 96]; msg_rec[120] = 255 - msg_rec[120]; #else // modulate, add noise, demodulate soft float SNRdB = -4.0f; float nstd = powf(10.0f, -SNRdB/20.0f); modemcf mod = modemcf_create(LIQUID_MODEM_BPSK); for (i=0; i<576; i++) { float complex v; unsigned int s; modemcf_modulate(mod, msg_enc[i], &v); v += nstd*(randnf() + randnf()*_Complex_I) * M_SQRT1_2; modemcf_demodulate_soft(mod, v, &s, &msg_rec[i]); } modemcf_destroy(mod); #endif // decode message g2412p_decode(q, msg_rec, msg_dec); // print decoded message printf("msg_org:\n"); for (i=0; i<12; i++) { printf("%3u: ", i); for (j=0; j<12; j++) printf("%2u", msg_dec[12*i+j]); printf("\n"); } // count errors unsigned int num_errors = 0; for (i=0; i<144; i++) num_errors += (msg_dec[i] & 1) == (msg_org[i] & 1) ? 0 : 1; printf("bit errors: %u / %u\n", num_errors, 144); // clean up allocated objects g2412p_destroy(q); printf("done\n"); return 0; } struct g2412p_s { unsigned char msg_buf[576]; // 24 x 24 message array unsigned char reg0[24]; // 24 value register unsigned int r; unsigned int d; }; g2412p g2412p_create() { g2412p q = (g2412p) malloc( sizeof(struct g2412p_s) ); return q; } void g2412p_destroy(g2412p _q) { // free main object memory free(_q); } void g2412p_print(g2412p _q) { unsigned int i; #if 1 unsigned int j; printf("msg_buf:\n"); for (i=0; i<24; i++) { if (i==12) printf("------\n"); printf("%2u:", i); for (j=0; j<24; j++) printf(" %s%3u", j==12 ? ":" : "", _q->msg_buf[24*i+j]); printf("\n"); } #else for (i=0; i<576; i++) printf(" %3u%s", _q->msg_buf[i], ((i+1)%24)==0 ? "\n" : ""); #endif } void g2412p_encode(g2412p _q, unsigned char * _msg_org, unsigned char * _msg_enc) { unsigned int r; unsigned int c; // encode rows #if DEBUG printf("rows:\n"); #endif for (r=0; r<12; r++) { unsigned int sym_org = 0; for (c=0; c<12; c++) { sym_org <<= 1; sym_org |= _msg_org[12*r+c] ? 1 : 0; } unsigned int sym_enc = fec_golay2412_encode_symbol(sym_org); // make systematic (swap upper and lower 12 bit chunks) sym_enc = ((sym_enc >> 12) & 0xfff) | ((sym_enc << 12) & 0xfff000); #if DEBUG printf(" %2u: 0x%.3x > 0x%.6x\n", r, sym_org, sym_enc); #endif // for (c=0; c<24; c++) { unsigned int bit = (sym_enc >> (24-c-1)) & 1; _msg_enc[24*r+c] = bit; } } // encode columns #if DEBUG printf("cols:\n"); #endif for (c=0; c<24; c++) { unsigned int sym_org = 0; for (r=0; r<12; r++) { sym_org <<= 1; sym_org |= _msg_enc[c+24*r] ? 1 : 0; } unsigned int sym_enc = fec_golay2412_encode_symbol(sym_org); // make systematic (swap upper and lower 12 bit chunks) sym_enc = ((sym_enc >> 12) & 0xfff) | ((sym_enc << 12) & 0xfff000); #if DEBUG printf(" %2u: 0x%.3x > 0x%.6x\n", c, sym_org, sym_enc); #endif // append only parity bits (no need to overwrite original bits) for (r=12; r<24; r++) { unsigned int bit = (sym_enc >> (24-r-1)) & 1; _msg_enc[c+24*r] = bit; } } } void g2412p_decode(g2412p _q, unsigned char * _msg_rec, unsigned char * _msg_dec) { unsigned int i; // copy received message to internal buffer memmove(_q->msg_buf, _msg_rec, 576*sizeof(unsigned char)); // print #if DEBUG g2412p_print(_q); #endif #if 1 // iterate // while... for (i=0; i<30; i++) { int rc = g2412p_iterate(_q); if (rc == 0) break; } printf("steps: %u\n", i); #endif // print #if DEBUG g2412p_print(_q); #endif // copy resulting output #if 0 for (i=0; i<12; i++) memmove(&_msg_dec[24*i], &_q->msg_buf[12*i], 12*sizeof(unsigned char)); #else unsigned int r; unsigned int c; unsigned int n = 0; for (r=0; r<12; r++) { for (c=0; c<12; c++) { _msg_dec[n++] = _q->msg_buf[24*r+c] > LIQUID_SOFTBIT_ERASURE ? 1 : 0; } } #endif } // run single iteration int g2412p_iterate(g2412p _q) { unsigned int i; int rc = 0; // decode columns for (i=0; i<24; i++) { g2412p_load_col (_q, i); rc += g2412p_step (_q ); g2412p_save_col (_q, i); } // decode rows for (i=0; i<12; i++) { g2412p_load_row (_q, i); rc += g2412p_step (_q ); g2412p_save_row (_q, i); } return rc; } // int g2412p_step(g2412p _q) { // TODO: determine if parity check passed // run hard-decision decoding unsigned int sym_rec = 0; unsigned int i; for (i=0; i<24; i++) { sym_rec <<= 1; sym_rec |= _q->reg0[i] > 127 ? 1 : 0; } // flip... //printf(" 0x%.6x > ", sym_rec); sym_rec = ((sym_rec >> 12) & 0xfff) | ((sym_rec << 12) & 0xfff000); // decode to 12-bit symbol unsigned int sym_dec = fec_golay2412_decode_symbol(sym_rec); // re-encode 24-bit symbol unsigned int sym_enc = fec_golay2412_encode_symbol(sym_dec); int rc = (sym_rec == sym_enc) ? 0 : 1; // flip... sym_enc = ((sym_enc >> 12) & 0xfff) | ((sym_enc << 12) & 0xfff000); //printf("0x%.6x\n", sym_enc); // update register // TODO: this is the crux of the algorithm and should be adjusted to // produce maximum performance. float alpha = 0.9f; // percentage of old value to retain float beta = 1.0f - alpha; // percentage of new value to retain for (i=0; i<24; i++) { //int v = (int)(_q->reg0[i]) + ((sym_enc >> i) & 1 ? 16 : -16); int p = (sym_enc >> (24-i-1)) & 1 ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; int v = ((int)(alpha*_q->reg0[i]) + beta*p); if (v < 0) _q->reg0[i] = 0; else if (v > 255) _q->reg0[i] = 255; else _q->reg0[i] = (unsigned char)v; } return rc; } // load 24-bit row into register void g2412p_load_row(g2412p _q, unsigned int _row) { //memmove(_q->reg0, &_q->msg_buf[_row*24], 24*sizeof(unsigned char)); unsigned int c; for (c=0; c<24; c++) _q->reg0[c] = _q->msg_buf[24*_row + c]; } void g2412p_save_row(g2412p _q, unsigned int _row) { //memmove(&_q->msg_buf[_row*24], _q->reg0, 24*sizeof(unsigned char)); unsigned int c; for (c=0; c<24; c++) _q->msg_buf[24*_row + c] = _q->reg0[c]; } void g2412p_load_col(g2412p _q, unsigned int _col) { unsigned int r; for (r=0; r<24; r++) _q->reg0[r] = _q->msg_buf[24*r + _col]; } void g2412p_save_col(g2412p _q, unsigned int _col) { unsigned int r; for (r=0; r<24; r++) _q->msg_buf[24*r + _col] = _q->reg0[r]; } // pack 24-value soft-bit message into integer unsigned int g2412p_pack_symbol(unsigned char * _msg_soft) { unsigned int i; unsigned int sym = 0; for (i=0; i<24; i++) { sym <<= 1; sym |= liquid_hard_decision(_msg_soft[i]); } return sym; } // unpack 24-bit integer into soft array void g2412p_unpack_symbol(unsigned int _msg_hard, unsigned char * _msg_soft) { unsigned int i; for (i=0; i<24; i++) { _msg_soft[i] = _msg_hard & 1 ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; _msg_hard >>= 1; } } unsigned int liquid_hard_decision(unsigned char _soft_bit) { return _soft_bit > LIQUID_SOFTBIT_ERASURE ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; } liquid-dsp-1.7.0/sandbox/fec_golay2412_test.c000066400000000000000000000252141474751757600207270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Golay(24,12) code test // #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_GOLAY 1 // P matrix [12 x 12] unsigned char P[144] = { 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; // generator matrix [12 x 24] unsigned char G[288]; void golay_init_G(); // parity check matrix [12 x 24] unsigned char H[288]; void golay_init_H(); unsigned int fec_golay2412_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<11)) { fprintf(stderr,"error, fec_golay2412_encode(), input symbol too large\n"); exit(1); } return 0; } unsigned int fec_golay2412_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<15)) { fprintf(stderr,"error, fec_golay2412_decode(), input symbol too large\n"); exit(1); } return 0; } void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } void matrix2_print(unsigned char * _x, unsigned int _m, unsigned int _n) { unsigned int i; unsigned int j; for (i=0; i<_m; i++) { printf(" "); for (j=0; j<_n; j++) printf("%c ", _x[i*_n+j] ? '1' : '0'); printf("\n"); } } // multiply two matrices modulo 2 void matrix2_mul(unsigned char * _x, unsigned int _mx, unsigned int _nx, unsigned char * _y, unsigned int _my, unsigned int _ny, unsigned char * _z, unsigned int _mz, unsigned int _nz) { // ensure lengths are valid if (_mz != _mx || _nz != _ny || _nx != _my ) { fprintf(stderr,"error: matrix2_mul(), invalid dimensions\n"); exit(1); } unsigned int r, c, i; for (r=0; r<_mz; r++) { for (c=0; c<_nz; c++) { unsigned int sum = 0; for (i=0; i<_nx; i++) { sum += matrix_access(_x,_mx,_nx,r,i) * matrix_access(_y,_my,_ny,i,c); } matrix_access(_z,_mz,_nz,r,c) = sum % 2; } } } unsigned int vector_weight(unsigned char * _x, unsigned int _n) { unsigned int w = 0; unsigned int i; for (i=0; i<_n; i++) w += _x[i] ? 1 : 0; return w; } int main(int argc, char*argv[]) { // initialize matrices golay_init_G(); golay_init_H(); printf("P:\n"); matrix2_print(P,12,12); printf("G:\n"); matrix2_print(G,12,24); printf("H:\n"); matrix2_print(H,12,24); unsigned int i; // error vector unsigned char err[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}; // arrays unsigned char m[12]; // original message unsigned char v[24]; // encoded/transmitted message unsigned char e[24]; // error vector unsigned char r[24]; // received vector unsigned char s[12]; // syndrome vector unsigned char e_hat[24];// estimated error vector unsigned char v_hat[24];// estimated transmitted message unsigned char m_hat[24];// estimated original message // compute (random) original message for (i=0; i<12; i++) m[i] = rand() % 2; printf("m (original message):\n"); matrix2_print(m,1,12); // compute encoded/transmitted message: v = m*G matrix2_mul(m,1,12, G,12,24, v,1,24); printf("v (encoded/transmitted message):\n"); matrix2_print(v,1,24); #if 0 // generate random error vector unsigned int e0 = rand() % 24; for (i=0; i<24; i++) e[i] = (i==e0) ? 1 : 0; #else // use pre-determined error vector for (i=0; i<24; i++) e[i] = err[i]; #endif printf("e (error vector):\n"); matrix2_print(e,1,24); #if 0 // from Lin & Costello, p. 128, // error locations at indices: 3, 10, 23 r[ 0] = 1; r[ 1] = 0; r[ 2] = 0; r[ 3] = 0; r[ 4] = 0; r[ 5] = 0; r[ 6] = 1; r[ 7] = 1; r[ 8] = 0; r[ 9] = 1; r[10] = 0; r[11] = 0; r[12] = 1; r[13] = 1; r[14] = 0; r[15] = 0; r[16] = 0; r[17] = 0; r[18] = 0; r[19] = 0; r[20] = 0; r[21] = 0; r[22] = 0; r[23] = 1; #else // compute received vector: r = v + e for (i=0; i<24; i++) r[i] = (v[i] + e[i]) % 2; printf("r (received vector):\n"); matrix2_print(r,1,24); #endif // compute syndrome vector, s = r*H^T = ( H*r^T )^T matrix2_mul(H,12,24, r,24,1, s,12,1); printf("s (syndrome vector):\n"); matrix2_print(s,1,12); // compute weight of s unsigned int ws = vector_weight(s,12); printf("w(s) = %u\n", ws); // step 2: if (ws <= 3) { printf(" w(s) <= 3: estimating error vector as [s, 0(12)]\n"); // set e_hat = [s 0(12)] for (i=0; i<24; i++) e_hat[i] = i < 12 ? s[i] : 0; } else { // step 3: search for p[i] s.t. w(s+p[i]) <= 2 printf(" searching for w(s + p_i) <= 2...\n"); unsigned int j; unsigned char spj[12]; int flag3 = 0; unsigned int p3_index = 0; for (j=0; j<12; j++) { for (i=0; i<12; i++) spj[i] = (s[i] + P[12*j+i]) % 2; unsigned int wj = vector_weight(spj,12); printf(" w(s + p[%2u]) = %2u%s\n", j, wj, wj <= 2 ? " *" : ""); if (wj <= 2) { flag3 = 1; p3_index = j; break; } } if (flag3) { // vector found! printf(" w(s + p[%2u]) <= 2: estimating error vector as [s+p[%2u],u[%2u]]\n", p3_index, p3_index, p3_index); for (i=0; i<12; i++) e_hat[i] = (s[i] + P[12*p3_index + i]) % 2; for (i=0; i<12; i++) e_hat[i+12] = (i == p3_index) ? 1 : 0; } else { // step 4: compute s*P unsigned char sP[12]; matrix2_mul(s,1,12, P,12,12, sP,1,12); printf("s*P:\n"); matrix2_print(sP,1,12); unsigned int wsP = vector_weight(sP,12); printf("w(s*P) = %u\n", wsP); if (wsP == 2 || wsP == 3) { // step 5: set e = [0, s*P] printf(" w(s*P) in [2,3]: estimating error vector as [0(12), s*P]\n"); for (i=0; i<24; i++) e_hat[i] = i < 12 ? 0 : sP[i-12]; } else { // step 6: search for p[i] s.t. w(s*P + p[i]) == 2... printf(" searching for w(s*P + p_i) == 2...\n"); unsigned int j; unsigned char sPpj[12]; int flag6 = 0; unsigned int p6_index = 0; for (j=0; j<12; j++) { for (i=0; i<12; i++) sPpj[i] = (sP[i] + P[12*j + i]) % 2; unsigned int wj = vector_weight(sPpj,12); printf(" w(s*P + p[%2u]) = %2u%s\n", j, wj, wj == 2 ? " *" : ""); if (wj == 2) { flag6 = 1; p6_index = j; break; } } if (flag6) { // vector found! printf(" w(s*P + p[%2u]) == 2: estimating error vector as [u[%2u],s*P+p[%2u]]\n", p6_index, p6_index, p6_index); for (i=0; i<12; i++) e_hat[i] = (i == p6_index) ? 1 : 0; for (i=0; i<12; i++) e_hat[i+12] = (sP[i] + P[12*p6_index+i]) % 2; } else { // step 7: decoding error printf(" **** decoding error\n"); } } } } // step 8: compute estimated transmitted message: v_hat = r + e_hat printf("e-hat (estimated error vector):\n"); matrix2_print(e_hat,1,24); for (i=0; i<24; i++) v_hat[i] = (r[i] + e_hat[i]) % 2; printf("v-hat (estimated transmitted vector):\n"); matrix2_print(v_hat,1,24); matrix2_print(v, 1,24); // compute errors between v, v_hat unsigned int num_errors_v = 0; for (i=0; i<24; i++) num_errors_v += v[i] == v_hat[i] ? 0 : 1; printf("\n"); printf("decoding errors (encoded) : %2u / 24\n", num_errors_v); // compute estimated original message: (last 12 bits of encoded message) for (i=0; i<12; i++) m_hat[i] = v_hat[i+12]; // compute errors between m, m_hat unsigned int num_errors_m = 0; for (i=0; i<12; i++) num_errors_m += m[i] == m_hat[i] ? 0 : 1; printf("decoding errors (original) : %2u / 12\n", num_errors_m); return 0; } // initialize generator matrix as G = [P I_12] void golay_init_G() { unsigned int i; unsigned int j; for (i=0; i<12; i++) { for (j=0; j<12; j++) G[i*24 + j] = P[i*12 + j]; for (j=0; j<12; j++) G[i*24 + j + 12] = (i==j) ? 1 : 0; } } // initialize generator matrix as H = [I_12 P] void golay_init_H() { unsigned int i; unsigned int j; for (i=0; i<12; i++) { for (j=0; j<12; j++) H[i*24+j] = (i==j) ? 1 : 0; for (j=0; j<12; j++) H[i*24 + j + 12] = P[i*12 + j]; } } liquid-dsp-1.7.0/sandbox/fec_golay_test.c000066400000000000000000000164441474751757600204230ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Golay(24,12) code test // #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_GOLAY 1 // P matrix [12 x 12] unsigned int P[12] = { 0x08ed, 0x01db, 0x03b5, 0x0769, 0x0ed1, 0x0da3, 0x0b47, 0x068f, 0x0d1d, 0x0a3b, 0x0477, 0x0ffe}; #if 0 // generator matrix [12 x 24] unsigned int G[12] = { 0x008ed800, 0x001db400, 0x003b5200, 0x00769100, 0x00ed1080, 0x00da3040, 0x00b47020, 0x0068f010, 0x00d1d008, 0x00a3b004, 0x00477002, 0x00ffe001}; #endif // generator matrix transposed [24 x 12] unsigned int Gt[24] = { 0x08ed, 0x01db, 0x03b5, 0x0769, 0x0ed1, 0x0da3, 0x0b47, 0x068f, 0x0d1d, 0x0a3b, 0x0477, 0x0ffe, 0x0800, 0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001}; // parity check matrix [12 x 24] unsigned int H[12] = { 0x008008ed, 0x004001db, 0x002003b5, 0x00100769, 0x00080ed1, 0x00040da3, 0x00020b47, 0x0001068f, 0x00008d1d, 0x00004a3b, 0x00002477, 0x00001ffe}; void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; printf(" "); for (i=0; i<_n; i++) printf("%1u ", (_x >> (_n-i-1)) & 1); printf("\n"); } int main(int argc, char*argv[]) { unsigned int i; // error vector // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 unsigned int err = 0x00000d00; // original message // 1 0 1 1 1 1 0 0 1 1 0 1 unsigned int m = 0x0bcd; // derived values unsigned int v; // encoded/transmitted message unsigned int e; // error vector unsigned int r; // received vector unsigned int s; // syndrome vector unsigned int e_hat; // estimated error vector unsigned int v_hat; // estimated transmitted message unsigned int m_hat; // estimated original message // original message printf("m (original message):\n"); print_bitstring(m,12); // compute encoded/transmitted message: v = m*G v = 0; for (i=0; i<24; i++) { v <<= 1; v |= liquid_count_ones_mod2(Gt[i] & m); } printf("v (encoded/transmitted message):\n"); print_bitstring(v,24); // use pre-determined error vector e = err; printf("e (error vector):\n"); print_bitstring(e,24); // compute received vector: r = v + e r = v ^ e; printf("r (received vector):\n"); print_bitstring(r,24); // compute syndrome vector, s = r*H^T = ( H*r^T )^T s = 0; for (i=0; i<12; i++) { s <<= 1; s |= liquid_count_ones_mod2(H[i] & r); } printf("s (syndrome vector):\n"); print_bitstring(s,12); // compute weight of s unsigned int ws = liquid_count_ones(s); printf("w(s) = %u\n", ws); // step 2: e_hat = 0; if (ws <= 3) { printf(" w(s) <= 3: estimating error vector as [s, 0(12)]\n"); // set e_hat = [s 0(12)] e_hat = s << 12; } else { // step 3: search for p[i] s.t. w(s+p[i]) <= 2 printf(" searching for w(s + p_i) <= 2...\n"); unsigned int j; unsigned int spj; int flag3 = 0; unsigned int p3_index = 0; for (j=0; j<12; j++) { spj = s ^ P[j]; unsigned int wj = liquid_count_ones(spj); printf(" w(s + p[%2u]) = %2u%s\n", j, wj, wj <= 2 ? " *" : ""); if (wj <= 2) { flag3 = 1; p3_index = j; break; } } if (flag3) { // vector found! printf(" w(s + p[%2u]) <= 2: estimating error vector as [s+p[%2u],u[%2u]]\n", p3_index, p3_index, p3_index); // NOTE : uj = 1 << (12-j-1) e_hat = ((s ^ P[p3_index]) << 12) | (1 << (11-p3_index)); } else { // step 4: compute s*P unsigned int sP = 0; for (i=0; i<12; i++) { sP <<= 1; sP |= liquid_count_ones_mod2(s & P[i]); } printf("s*P:\n"); print_bitstring(sP,12); unsigned int wsP = liquid_count_ones(sP); printf("w(s*P) = %u\n", wsP); if (wsP == 2 || wsP == 3) { // step 5: set e = [0, s*P] printf(" w(s*P) in [2,3]: estimating error vector as [0(12), s*P]\n"); e_hat = sP; } else { // step 6: search for p[i] s.t. w(s*P + p[i]) == 2... printf(" searching for w(s*P + p_i) == 2...\n"); unsigned int j; unsigned int sPpj; int flag6 = 0; unsigned int p6_index = 0; for (j=0; j<12; j++) { sPpj = sP ^ P[j]; unsigned int wj = liquid_count_ones(sPpj); printf(" w(s*P + p[%2u]) = %2u%s\n", j, wj, wj == 2 ? " *" : ""); if (wj == 2) { flag6 = 1; p6_index = j; break; } } if (flag6) { // vector found! printf(" w(s*P + p[%2u]) == 2: estimating error vector as [u[%2u],s*P+p[%2u]]\n", p6_index, p6_index, p6_index); // NOTE : uj = 1 << (12-j-1) // [ uj << 1 2 ] [ sP + p[j] ] e_hat = (1 << (23-p6_index)) | (sP ^ P[p6_index]); } else { // step 7: decoding error printf(" **** decoding error\n"); } } } } // step 8: compute estimated transmitted message: v_hat = r + e_hat printf("e-hat (estimated error vector):\n"); print_bitstring(e_hat,24); v_hat = r ^ e_hat; printf("v-hat (estimated transmitted vector):\n"); print_bitstring(v_hat,24); print_bitstring(v, 24); // compute errors between v, v_hat printf("decoding errors (encoded) : %2u / 24\n", count_bit_errors(v, v_hat)); // compute estimated original message: (last 12 bits of encoded message) m_hat = v_hat & ((1<<12)-1); // compute errors between m, m_hat printf("decoding errors (original) : %2u / 12\n", count_bit_errors(m, m_hat)); return 0; } liquid-dsp-1.7.0/sandbox/fec_hamming128_example.c000066400000000000000000000021771474751757600216350ustar00rootroot00000000000000// // Hamming(12,8) example // #include #include #include "liquid.internal.h" void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } int main(int argc, char*argv[]) { // original symbol unsigned int sym_org = 139; // encoded symbol unsigned int sym_enc = fec_hamming128_encode_symbol(sym_org); // received symbol unsigned int n=7; // index of bit to corrupt unsigned int sym_rec = sym_enc ^ (1<<(12-n)); // decoded symbol unsigned int sym_dec = fec_hamming128_decode_symbol(sym_rec); // print results printf(" sym org : "); print_bitstring(sym_org, 8); printf("\n"); printf(" sym enc : "); print_bitstring(sym_enc, 12); printf("\n"); printf(" sym rec : "); print_bitstring(sym_rec, 12); printf("\n"); printf(" sym dec : "); print_bitstring(sym_dec, 8); printf("\n"); // print number of bit errors printf(" bit errors : %u\n", count_bit_errors(sym_org, sym_dec)); return 0; } liquid-dsp-1.7.0/sandbox/fec_hamming128_gentab.c000066400000000000000000000033011474751757600214300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 2/3-rate (12,8) Hamming code encoding table generator // #include #include #include "liquid.internal.h" int main() { unsigned int i; unsigned int c; printf("unsigned short int hamming128_enc_gentab[256] = {\n "); for (i=0; i<256; i++) { // encode symbol c = fec_hamming128_encode_symbol(i); // print result printf("0x%.4x", c); if (i != 255) printf(", "); else printf("};"); if ( ((i+1)%8) == 0) printf("\n "); } printf("\n"); return 0; } liquid-dsp-1.7.0/sandbox/fec_hamming128_test.c000066400000000000000000000067521474751757600211640ustar00rootroot00000000000000// // Hamming(12,8) code test // // Tests syndrome decoding // #include #include #include "liquid.internal.h" void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } unsigned char hamming128_P[4] = { 0xda, // 1101 1010 0xb6, // 1011 0110 0x71, // 0111 0001 0x0f}; // 0000 1111 int main(int argc, char*argv[]) { // ... unsigned int sym_org = 0x21; // original symbol unsigned int sym_enc; // encoded symbol unsigned int e = 0x001; // error vector unsigned int sym_rec; // received symbol unsigned int sym_dec; // decoded symbol unsigned int i; // encode symbol unsigned int p0 = liquid_c_ones[sym_org & hamming128_P[0]] & 0x01; unsigned int p1 = liquid_c_ones[sym_org & hamming128_P[1]] & 0x01; unsigned int p2 = liquid_c_ones[sym_org & hamming128_P[2]] & 0x01; unsigned int p3 = liquid_c_ones[sym_org & hamming128_P[3]] & 0x01; unsigned int parity = (p0 << 3) | (p1 << 2) | (p2 << 1) | (p3 << 0); sym_enc = (parity << 8) | sym_org; // received symbol (add error) sym_rec = sym_enc ^ e; // // decode symbol // sym_dec = sym_rec & 0xff; unsigned int e_hat = 0x000; // compute syndrome vector; s = r*H^T = ( H*r^T )^T unsigned int s = 0x0; // 4 bits resolution for (i=0; i<4; i++) { s <<= 1; unsigned int p = ( (sym_rec & (1<<(12-i-1))) ? 1 : 0 ) + liquid_c_ones[sym_rec & hamming128_P[i]]; s |= p & 0x01; } // compute weight of s unsigned int ws = liquid_count_ones(s); printf(" syndrome : "); print_bitstring(s, 4); printf(" (%u)\n", ws); if (ws == 0) { printf("no errors detected\n"); } else { // estimate error location unsigned int e_test = 0x001; int syndrome_match = 0; // TODO : these can be pre-computed unsigned int n; for (n=0; n<12; n++) { // compute syndrome unsigned int s_hat = 0; for (i=0; i<4; i++) { s_hat <<= 1; unsigned int p = ( (e_test & (1<<(12-i-1))) ? 1 : 0 ) + liquid_c_ones[e_test & hamming128_P[i]]; s_hat |= p & 0x01; } // print results //printf("e_test:"); print_bitstring(e_test, 72); printf(" %2u e = ", n); print_bitstring(e_test,12); printf(" s = "); print_bitstring(s_hat,4); if (s == s_hat) printf(" *"); printf("\n"); if (s == s_hat) { e_hat = e_test; syndrome_match = 1; } // shift e_test e_test <<= 1; } // apply error correction and return if (syndrome_match) sym_dec = (sym_rec ^ e_hat) & 0xff; } // print results printf(" sym org : "); print_bitstring(sym_org, 8); printf("\n"); printf(" sym enc : "); print_bitstring(sym_enc, 12); printf("\n"); printf(" sym rec : "); print_bitstring(sym_rec, 12); printf("\n"); printf(" sym dec : "); print_bitstring(sym_dec, 8); printf("\n"); // print number of bit errors printf(" bit errors : %u\n", count_bit_errors(sym_org, sym_dec)); return 0; } liquid-dsp-1.7.0/sandbox/fec_hamming3126_example.c000066400000000000000000000302061474751757600217100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Hamming code parity check matrix // // bit position 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // encoded bits P1 P2 1 P4 2 3 4 P8 5 6 7 8 9 10 11 P16 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 P32 27 28 29 30 31 32 // // parity bit P1 x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . // coverage P2 . x x . . x x . . x x . . x x . . x x . . x x . . x x . . x x . // P4 . . . x x x x . . . . x x x x . . . . x x x x . . . . x x x x . // P8 . . . . . . . x x x x x x x x . . . . . . . . x x x x x x x x . // P16 . . . . . . . . . . . . . . . x x x x x x x x x x x x x x x x . // P32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_HAMMING 1 #if 0 // // (12,8) Hamming code // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:8) // // bit position 3 5 6 7 9 10 11 12 // // parity bit P1 x x . x x . x . = 1101 1010 // coverage P2 x . x x . x x . = 1011 0110 // P4 . x x x . . . x = 0111 0001 // P8 . . . . x x x x = 0000 1111 #define HAMMING_M1 0xda // 1101 1010 #define HAMMING_M2 0xb6 // 1011 0110 #define HAMMING_M4 0x71 // 0111 0001 #define HAMMING_M8 0x0f // 0000 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING_S1 0x0aaa // .... 1010 1010 1010 #define HAMMING_S2 0x0666 // .... 0110 0110 0110 #define HAMMING_S4 0x01e1 // .... 0001 1110 0001 #define HAMMING_S8 0x001f // .... 0000 0001 1111 #endif #if 0 // // (15,11) Hamming code // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:11) // // parity bit P1 x x . x x . x . x . x = .110 1101 0101 // coverage P2 x . x x . x x . . x x = .101 1011 0011 // P4 . x x x . . . x x x x = .011 1000 1111 // P8 . . . . x x x x x x x = .000 0111 1111 #define HAMMING_M1 0x0d65 // .110 1101 0101 #define HAMMING_M2 0x05b3 // .101 1011 0011 #define HAMMING_M4 0x038f // .011 1000 1111 #define HAMMING_M8 0x007f // .000 0111 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING_S1 0x5555 // .101 0101 0101 0101 #define HAMMING_S2 0x3333 // .011 0011 0011 0011 #define HAMMING_S4 0x0f0f // .000 1111 0000 1111 #define HAMMING_S8 0x00ff // .000 0000 1111 1111 #endif // // (31,26) Hamming code // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8, P16 and only including // data bits 1:26) // // bit position 3 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // * * * * * * // parity bit P1 x x . x x . x . x . x x . x . x . x . x . x . x . x = ..11 0110 1010 1101 0101 0101 0101 // coverage P2 x . x x . x x . . x x . x x . . x x . . x x . . x x = ..10 1101 1001 1011 0011 0011 0011 // P4 . x x x . . . x x x x . . . x x x x . . . . x x x x = ..01 1100 0111 1000 1111 0000 1111 // P8 . . . . x x x x x x x . . . . . . . x x x x x x x x = ..00 0011 1111 1000 0000 1111 1111 // P16 . . . . . . . . . . . x x x x x x x x x x x x x x x = ..00 0000 0000 0111 1111 1111 1111 #define HAMMING_M1 0x036AD555 // ..11 0110 1010 1101 0101 0101 0101 #define HAMMING_M2 0x02D9B333 // ..10 1101 1001 1011 0011 0011 0011 #define HAMMING_M4 0x01C78F0F // ..01 1100 0111 1000 1111 0000 1111 #define HAMMING_M8 0x003F80FF // ..00 0011 1111 1000 0000 1111 1111 #define HAMMING_M16 0x00007FFF // ..00 0000 0000 0111 1111 1111 1111 // bit position 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // * * * * * * * // parity bit P1 x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . x = .101 0101 0101 0101 0101 0101 0101 0101 // coverage P2 . x x . . x x . . x x . . x x . . x x . . x x . . x x . . x x = .011 0011 0011 0011 0011 0011 0011 0011 // P4 . . . x x x x . . . . x x x x . . . . x x x x . . . . x x x x = .000 1111 0000 1111 0000 1111 0000 1111 // P8 . . . . . . . x x x x x x x x . . . . . . . . x x x x x x x x = .000 0000 1111 1111 0000 0000 1111 1111 // P16 . . . . . . . . . . . . . . . x x x x x x x x x x x x x x x x = .000 0000 0000 0000 1111 1111 1111 1111 // // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see figure, above). #define HAMMING_S1 0x55555555 // .101 0101 0101 0101 0101 0101 0101 0101 #define HAMMING_S2 0x33333333 // .011 0011 0011 0011 0011 0011 0011 0011 #define HAMMING_S4 0x0f0f0f0f // .000 1111 0000 1111 0000 1111 0000 1111 #define HAMMING_S8 0x00ff00ff // .000 0000 1111 1111 0000 0000 1111 1111 #define HAMMING_S16 0x0000ffff // .000 0000 0000 0000 1111 1111 1111 1111 unsigned int fec_hamming_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<26)) { fprintf(stderr,"error, fec_hamming_encode(), input symbol too large\n"); exit(1); } // compute parity bits unsigned int p1 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M1); unsigned int p2 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M2); unsigned int p4 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M4); unsigned int p8 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M8); unsigned int p16 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M16); #if DEBUG_FEC_HAMMING printf("parity bits (p1,p2,p4,p8,p16) : (%1u,%1u,%1u,%1u,%1u)\n", p1, p2, p4, p8, p16); #endif // encode symbol by inserting parity bits with data bits to // make a 31-bit symbol unsigned int sym_enc = ((_sym_dec & 0x00007fff) << 0) | // ..00 0000 0000 0111 1111 1111 1111 ((_sym_dec & 0x003F8000) << 1) | // ..00 0011 1111 1000 0000 0000 0000 ((_sym_dec & 0x01C00000) << 2) | // ..01 1100 0000 0000 0000 0000 0000 ((_sym_dec & 0x02000000) << 3) | // ..10 0000 0000 0000 0000 0000 0000 ( p1 << 30 ) | // 30 = 31 - 1 (position of P1) ( p2 << 29 ) | // 29 = 31 - 2 (position of P2) ( p4 << 27 ) | // 27 = 31 - 4 (position of P4) ( p8 << 23 ) | // 23 = 31 - 8 (position of P8) ( p16 << 15 ); // 15 = 31 - 16 (position of P16) return sym_enc; } unsigned int fec_hamming_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<31)) { fprintf(stderr,"error, fec_hamming_decode(), input symbol too large\n"); exit(1); } // compute syndrome bits unsigned int s1 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S1); unsigned int s2 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S2); unsigned int s4 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S4); unsigned int s8 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S8); unsigned int s16 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S16); // index unsigned int z = (s16<<4) | (s8<<3) | (s4<<2) | (s2<<1) | s1; #if DEBUG_FEC_HAMMING printf("syndrome bits (s1,s2,s4,s8,16) : (%1u,%1u,%1u,%1u,%1u)\n", s1, s2, s4, s8, s16); printf("syndrome z : %u\n", z); #endif // flip bit at this position if (z) { if (z > 31) { // if this happens there are likely too many errors // to correct; just pass without trying to do anything fprintf(stderr,"warning, fec_hamming_decode_symbol(), syndrome index exceeds maximum\n"); } else { //printf("error detected!\n"); _sym_enc ^= 1 << (31-z); } } // strip data bits from encoded symbol with parity bits unsigned int sym_dec = ((_sym_enc & 0x00007fff) ) | // .000 0000 0000 0000 0111 1111 1111 1111 ((_sym_enc & 0x007f0000) >> 1) | // .000 0000 0111 1111 0000 0000 0000 0000 ((_sym_enc & 0x07000000) >> 2) | // .000 0111 0000 0000 0000 0000 0000 0000 ((_sym_enc & 0x10000000) >> 3); // .001 0000 0000 0000 0000 0000 0000 0000 return sym_dec; } // // Hamming(31,26) example // void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } int main(int argc, char*argv[]) { // original symbol unsigned int sym_org = 28236851; // ..01 1010 1110 1101 1100 0011 0011 // encoded symbol unsigned int sym_enc = fec_hamming_encode_symbol(sym_org); // received symbol unsigned int n=7; // index of bit to corrupt unsigned int sym_rec = sym_enc ^ (1<<(31-n)); // decoded symbol unsigned int sym_dec = fec_hamming_decode_symbol(sym_rec); // print results printf(" sym org : "); print_bitstring(sym_org, 26); printf("\n"); printf(" sym enc : "); print_bitstring(sym_enc, 31); printf("\n"); printf(" sym rec : "); print_bitstring(sym_rec, 31); printf("\n"); printf(" sym dec : "); print_bitstring(sym_dec, 26); printf("\n"); // print number of bit errors printf(" bit errors : %u\n", count_bit_errors(sym_org, sym_dec)); return 0; } liquid-dsp-1.7.0/sandbox/fec_hamming74_gentab.c000066400000000000000000000125221474751757600213550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 1/2-rate (7,4) Hamming code table generator // #include #include // generator matrices // encoding matrix #define HAMMING74_G0 0x0d // 1101 #define HAMMING74_G1 0x0b // 1011 #define HAMMING74_G2 0x08 // 1000 #define HAMMING74_G3 0x07 // 0111 #define HAMMING74_G4 0x04 // 0100 #define HAMMING74_G5 0x02 // 0010 #define HAMMING74_G6 0x01 // 0001 // syndrome matrix #define HAMMING74_H0 0x55 // .101 0101 #define HAMMING74_H1 0x33 // .011 0011 #define HAMMING74_H2 0x0f // .000 1111 // decoding matrix #define HAMMING74_R0 0x10 // .001 0000 #define HAMMING74_R1 0x04 // .000 0100 #define HAMMING74_R2 0x02 // .000 0010 #define HAMMING74_R3 0x01 // .000 0001 unsigned int count_ones(unsigned int _x); unsigned int hamming74_enc_symbol(unsigned int _p); unsigned int hamming74_dec_symbol(unsigned int _x); int main() { unsigned int n = 16; unsigned int k = 128; // generate encoding table unsigned int enc_gentab[n]; unsigned int p; for (p=0; p>= 1; } return num_ones; } unsigned int hamming74_enc_symbol(unsigned int _p) { unsigned int x0 = count_ones(_p & HAMMING74_G0) % 2; unsigned int x1 = count_ones(_p & HAMMING74_G1) % 2; unsigned int x2 = count_ones(_p & HAMMING74_G2) % 2; unsigned int x3 = count_ones(_p & HAMMING74_G3) % 2; unsigned int x4 = count_ones(_p & HAMMING74_G4) % 2; unsigned int x5 = count_ones(_p & HAMMING74_G5) % 2; unsigned int x6 = count_ones(_p & HAMMING74_G6) % 2; unsigned int x = (x0 << 6) | (x1 << 5) | (x2 << 4) | (x3 << 3) | (x4 << 2) | (x5 << 1) | (x6 ); return x; } unsigned int hamming74_dec_symbol(unsigned int _r) { // compute syndromes unsigned int z0 = count_ones(_r & HAMMING74_H0) % 2; unsigned int z1 = count_ones(_r & HAMMING74_H1) % 2; unsigned int z2 = count_ones(_r & HAMMING74_H2) % 2; unsigned int z = (z0 << 0) | (z1 << 1) | (z2 << 2); unsigned int r_hat = _r; if (z) { // error detected: flip appropriate bit of // received symbol r_hat ^= 1 << (7-z); } // decode unsigned int p0 = count_ones(r_hat & HAMMING74_R0) % 2; unsigned int p1 = count_ones(r_hat & HAMMING74_R1) % 2; unsigned int p2 = count_ones(r_hat & HAMMING74_R2) % 2; unsigned int p3 = count_ones(r_hat & HAMMING74_R3) % 2; unsigned int p = (p0 << 3) | (p1 << 2) | (p2 << 1) | (p3 << 0); return p; } liquid-dsp-1.7.0/sandbox/fec_hamming84_gentab.c000066400000000000000000000131751474751757600213630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 1/2-rate (8,4) Hamming code table generator // #include #include // generator matrices // encoding matrix #define HAMMING84_G0 0x0d // 1101 #define HAMMING84_G1 0x0b // 1011 #define HAMMING84_G2 0x08 // 1000 #define HAMMING84_G3 0x07 // 0111 #define HAMMING84_G4 0x04 // 0100 #define HAMMING84_G5 0x02 // 0010 #define HAMMING84_G6 0x01 // 0001 #define HAMMING84_G7 0x0e // 1110 // syndrome matrix #define HAMMING84_H0 0xaa // 1010 1010 #define HAMMING84_H1 0x66 // 0110 0110 #define HAMMING84_H2 0x1e // 0001 1110 #define HAMMING84_H3 0xff // 1111 1111 // decoding matrix #define HAMMING84_R0 0x20 // 0010 0000 #define HAMMING84_R1 0x08 // 0000 1000 #define HAMMING84_R2 0x04 // 0000 0100 #define HAMMING84_R3 0x02 // 0000 0010 unsigned int count_ones(unsigned int _x); unsigned int hamming84_enc_symbol(unsigned int _p); unsigned int hamming84_dec_symbol(unsigned int _x); int main() { unsigned int n = 16; unsigned int k = 256; // generate encoding table unsigned int enc_gentab[n]; unsigned int p; for (p=0; p>= 1; } return num_ones; } unsigned int hamming84_enc_symbol(unsigned int _p) { unsigned int x0 = count_ones(_p & HAMMING84_G0) % 2; unsigned int x1 = count_ones(_p & HAMMING84_G1) % 2; unsigned int x2 = count_ones(_p & HAMMING84_G2) % 2; unsigned int x3 = count_ones(_p & HAMMING84_G3) % 2; unsigned int x4 = count_ones(_p & HAMMING84_G4) % 2; unsigned int x5 = count_ones(_p & HAMMING84_G5) % 2; unsigned int x6 = count_ones(_p & HAMMING84_G6) % 2; unsigned int x7 = count_ones(_p & HAMMING84_G7) % 2; unsigned int x = (x0 << 7) | (x1 << 6) | (x2 << 5) | (x3 << 4) | (x4 << 3) | (x5 << 2) | (x6 << 1) | (x7 ); return x; } unsigned int hamming84_dec_symbol(unsigned int _r) { // compute syndromes unsigned int z0 = count_ones(_r & HAMMING84_H0) % 2; unsigned int z1 = count_ones(_r & HAMMING84_H1) % 2; unsigned int z2 = count_ones(_r & HAMMING84_H2) % 2; unsigned int z = (z0 << 0) | (z1 << 1) | (z2 << 2); unsigned int r_hat = _r; if (z) { // error detected: flip appropriate bit of // received symbol r_hat ^= 1 << (8-z); } #if 0 // check extra parity bit unsigned int z3 = count_ones(r_hat & HAMMING84_H3) % 2; if (z3) printf("decoding error!\n"); #endif // decode unsigned int p0 = count_ones(r_hat & HAMMING84_R0) % 2; unsigned int p1 = count_ones(r_hat & HAMMING84_R1) % 2; unsigned int p2 = count_ones(r_hat & HAMMING84_R2) % 2; unsigned int p3 = count_ones(r_hat & HAMMING84_R3) % 2; unsigned int p = (p0 << 3) | (p1 << 2) | (p2 << 1) | (p3 << 0); return p; } liquid-dsp-1.7.0/sandbox/fec_hamming_test.c000066400000000000000000000205561474751757600207270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Hamming code parity check matrix // // bit position 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 // encoded bits P1 P2 1 P4 2 3 4 P8 5 6 7 8 9 10 11 P16 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 P32 27 28 29 30 31 32 // // parity bit P1 x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . // coverage P2 . x x . . x x . . x x . . x x . . x x . . x x . . x x . . x x . // P4 . . . x x x x . . . . x x x x . . . . x x x x . . . . x x x x . // P8 . . . . . . . x x x x x x x x . . . . . . . . x x x x x x x x . // P16 . . . . . . . . . . . . . . . x x x x x x x x x x x x x x x x . // P32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_HAMMING 1 #if 0 // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:8) // // bit position 3 5 6 7 9 10 11 12 // // parity bit P1 x x . x x . x . = 1101 1010 // coverage P2 x . x x . x x . = 1011 0110 // P4 . x x x . . . x = 0111 0001 // P8 . . . . x x x x = 0000 1111 #define HAMMING_M1 0xda // 1101 1010 #define HAMMING_M2 0xb6 // 1011 0110 #define HAMMING_M4 0x71 // 0111 0001 #define HAMMING_M8 0x0f // 0000 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING_S1 0x0aaa // .... 1010 1010 1010 #define HAMMING_S2 0x0666 // .... 0110 0110 0110 #define HAMMING_S4 0x01e1 // .... 0001 1110 0001 #define HAMMING_S8 0x001f // .... 0000 0001 1111 #endif // // Hamming(15,11) // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:11) // // parity bit P1 x x . x x . x . x . x = .110 1101 0101 // coverage P2 x . x x . x x . . x x = .101 1011 0011 // P4 . x x x . . . x x x x = .011 1000 1111 // P8 . . . . x x x x x x x = .000 0111 1111 #define HAMMING_M1 0x06d5 // .110 1101 0101 #define HAMMING_M2 0x05b3 // .101 1011 0011 #define HAMMING_M4 0x038f // .011 1000 1111 #define HAMMING_M8 0x007f // .000 0111 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING_S1 0x5555 // .101 0101 0101 0101 #define HAMMING_S2 0x3333 // .011 0011 0011 0011 #define HAMMING_S4 0x0f0f // .000 1111 0000 1111 #define HAMMING_S8 0x00ff // .000 0000 1111 1111 unsigned int fec_hamming_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<11)) { fprintf(stderr,"error, fec_hamming_encode(), input symbol too large\n"); exit(1); } // compute parity bits unsigned int p1 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M1); unsigned int p2 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M2); unsigned int p4 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M4); unsigned int p8 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M8); #if DEBUG_FEC_HAMMING printf("parity bits (p1,p2,p4,p8) : (%1u,%1u,%1u,%1u)\n", p1, p2, p4, p8); #endif // encode symbol by inserting parity bits with data bits to // make a 15-bit symbol unsigned int sym_enc = ((_sym_dec & 0x007f) << 0) | ((_sym_dec & 0x0380) << 1) | ((_sym_dec & 0x0400) << 2) | ( p1 << 14 ) | ( p2 << 13 ) | ( p4 << 11 ) | ( p8 << 7 ); return sym_enc; } unsigned int fec_hamming_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<15)) { fprintf(stderr,"error, fec_hamming_decode(), input symbol too large\n"); exit(1); } // compute syndrome bits unsigned int s1 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S1); unsigned int s2 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S2); unsigned int s4 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S4); unsigned int s8 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S8); // index unsigned int z = (s8<<3) | (s4<<2) | (s2<<1) | s1; #if DEBUG_FEC_HAMMING printf("syndrome bits (s1,s2,s4,s8) : (%1u,%1u,%1u,%1u)\n", s1, s2, s4, s8); printf("syndrome z : %u\n", z); #endif // flip bit at this position if (z) { if (z > 15) { // if this happens there are likely too many errors // to correct; just pass without trying to do anything fprintf(stderr,"warning, fec_hamming_decode_symbol(), syndrome index exceeds maximum\n"); } else { //printf("error detected!\n"); _sym_enc ^= 1 << (15-z); } } // strip data bits (x) from encoded symbol with parity bits (.) // symbol: [..x. xxx. xxxx] // 0000 0000 1111 > 0x000f // 0000 1110 0000 > 0x00e0 // 0010 0000 0000 > 0x0200 // // symbol: [ -..x .xxx .xxx xxxx] // -000 0000 0xxx xxxx > 0x007f // -000 0111 0000 0000 > 0x0700 // -001 0000 0000 0000 > 0x1000 unsigned int sym_dec = ((_sym_enc & 0x007f) ) | ((_sym_enc & 0x0700) >> 1) | ((_sym_enc & 0x1000) >> 2); return sym_dec; } // // Hamming(12,8) example // void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } int main(int argc, char*argv[]) { // original symbol unsigned int sym_org = 1377; // 10101100001 // encoded symbol unsigned int sym_enc = fec_hamming_encode_symbol(sym_org); // received symbol unsigned int n=7; // index of bit to corrupt unsigned int sym_rec = sym_enc ^ (1<<(15-n)); // decoded symbol unsigned int sym_dec = fec_hamming_decode_symbol(sym_rec); // print results printf(" sym org : "); print_bitstring(sym_org, 11); printf("\n"); printf(" sym enc : "); print_bitstring(sym_enc, 15); printf("\n"); printf(" sym rec : "); print_bitstring(sym_rec, 15); printf("\n"); printf(" sym dec : "); print_bitstring(sym_dec, 11); printf("\n"); // print number of bit errors printf(" bit errors : %u\n", count_bit_errors(sym_org, sym_dec)); return 0; } liquid-dsp-1.7.0/sandbox/fec_ldpc_test.c000066400000000000000000000111211474751757600202150ustar00rootroot00000000000000// // fec_ldpc_test.c // // Test soft demodulation of LDPC code // #include #include #include #define DEBUG_LDPC_TEST (0) #if DEBUG_LDPC_TEST #include #endif // float phi(float _x) { return -logf(tanhf(_x/2.0f + 1e-12)); } int main(int argc, char*argv[]) { // parity check matrix unsigned char H[32] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1}; // transmitted codeword unsigned char c[8] = { 1, 0, 1, 0, 1, 1, 1, 1}; // received message float y[8] = { 0.2, 0.2, -0.9, 0.6, 0.5, -1.1, -0.4, -1.2}; // noise standard deviation float sigma = sqrtf(0.5f); unsigned int max_iterations = 10; unsigned int n = 8; unsigned int m = 4; // internal variables unsigned int num_iterations = 0; float Lq[m*n]; float Lr[m*n]; float Lc[n]; float LQ[n]; unsigned char c_hat[n]; unsigned char parity[m]; unsigned int i; unsigned int j; unsigned int ip; unsigned int jp; float alpha_prod; float phi_sum; int parity_pass; int continue_running = 1; // initialize Lq with log-likelihood values for (i=0; i 0.0f ? 1.0f : -1.0f; float beta = fabsf(Lq[j*n+ip]); phi_sum += phi(beta); alpha_prod *= alpha; } } Lr[j*n+i] = alpha_prod * phi(phi_sum); } } #if DEBUG_LDPC_TEST // print Lq matrixf_print(Lq,m,n); // print Lr matrixf_print(Lr,m,n); #endif // compute next iteration of Lq for (i=0; i #include "liquid.h" int main() { unsigned char s0, s1, s2, r, r_hat; unsigned int errors = 0; for (s0=0; s0<2; s0++) { for (s1=0; s1<2; s1++) { for (s2=0; s2<2; s2++) { r = (s0 + s1 + s2) < 2 ? 0 : 1; //r_hat = (!s0 & s1 & s2) | (s0 & !(!s1 & !s2)); r_hat = (s1 & s2) | (s0 & s1) | (s0 & s2); int error_found = (s0 ^ s1) | (s0 ^ s2) | (s1 ^ s2); errors += r != r_hat; printf("%2u %2u %2u %2u (%2u) %2u\n", s0, s1, s2, r, r_hat, error_found); } } } printf("errors : %u\n", errors); return 0; } liquid-dsp-1.7.0/sandbox/fec_rep5_test.c000066400000000000000000000022761474751757600201610ustar00rootroot00000000000000// // // #include #include "liquid.h" int main() { unsigned char s0, s1, s2, s3, s4, r, r_hat; unsigned int errors = 0; for (s0=0; s0<2; s0++) { for (s1=0; s1<2; s1++) { for (s2=0; s2<2; s2++) { for (s3=0; s3<2; s3++) { for (s4=0; s4<2; s4++) { r = (s0 + s1 + s2 + s3 + s4) < 3 ? 0 : 1; r_hat = (s0 & s1) | (s0 & s2) | (s0 & s3) | (s0 & s4) | (s1 & s2) | (s1 & s3) | (s1 & s4) | (s2 & s3) | (s2 & s4) | (s3 & s4); r_hat = (s0 & s1 & s2) | (s0 & s1 & s3) | (s0 & s1 & s4) | (s0 & s2 & s3) | (s0 & s2 & s4) | (s0 & s3 & s4) | (s1 & s2 & s3) | (s1 & s2 & s4) | (s1 & s3 & s4) | (s2 & s3 & s4); int error_found = 0; errors += r != r_hat; printf("%2u %2u %2u %2u %2u %2u (%2u) %c %2u\n", s0, s1, s2, s3, s4, r, r_hat, r==r_hat ? ' ' : '*', error_found); } } } } } printf("errors : %u\n", errors); return 0; } liquid-dsp-1.7.0/sandbox/fec_secded2216_test.c000066400000000000000000000166331474751757600210520ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // (22,16) code test (SEC-DED) // #include #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED 1 // P matrix [6 x 16 bits], [6 x 2 bytes] // 1001 1001 0011 1100 : // 0011 1110 1000 1010 : // 1110 1110 0110 0000 : // 1110 0001 1101 0001 : // 0001 0011 1100 0111 : // 0100 0100 0011 1111 : unsigned char P[12] = { 0x99, 0x3c, 0x3e, 0x8a, 0xee, 0x60, 0xe1, 0xd1, 0x13, 0xc7, 0x44, 0x3f}; void print_bitstring_short(unsigned char _x, unsigned char _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } void print_bitstring(unsigned char * _x, unsigned char _n) { unsigned int i; // compute number of elements in _x div_t d = div(_n, 8); unsigned int N = d.quot + (d.rem ? 1 : 0); // print leader printf(" "); if (d.rem == 0) printf(" "); for (i=0; i<8-d.rem-1; i++) printf(" "); // print bitstring for (i=0; i #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED 1 // P matrix [7 x 32 bits], [7 x 4 bytes] // 1000 1010 1000 0010 0000 1111 0001 1011 // 0001 0000 0001 1111 0111 0001 0110 0001 // 0001 0110 1111 0000 1001 0010 1010 0110 // 1111 1111 0000 0001 1010 0100 0100 0100 // 0110 1100 1111 1111 0000 1000 0000 1000 // 0010 0001 0010 0100 1111 1111 1001 0000 // 1100 0001 0100 1000 0100 0000 1111 1111 unsigned char P[28] = { 0x8a, 0x82, 0x0f, 0x1b, 0x10, 0x1f, 0x71, 0x61, 0x16, 0xf0, 0x92, 0xa6, 0xff, 0x01, 0xa4, 0x44, 0x6c, 0xff, 0x08, 0x08, 0x21, 0x24, 0xff, 0x90, 0xc1, 0x48, 0x40, 0xff}; void print_bitstring_short(unsigned char _x, unsigned char _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } void print_bitstring(unsigned char * _x, unsigned char _n) { unsigned int i; // compute number of elements in _x div_t d = div(_n, 8); unsigned int N = d.quot + (d.rem ? 1 : 0); // print leader printf(" "); if (d.rem == 0) printf(" "); for (i=0; i<8-d.rem-1; i++) printf(" "); // print bitstring for (i=0; i #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED 1 // P matrix [8 x 64] // 11111111 00001111 00001111 00001100 01101000 10001000 10001000 10000000 : // 11110000 11111111 00000000 11110011 01100100 01000100 01000100 01000000 : // 00110000 11110000 11111111 00001111 00000010 00100010 00100010 00100110 : // 11001111 00000000 11110000 11111111 00000001 00010001 00010001 00010110 : // 01101000 10001000 10001000 10000000 11111111 00001111 00000000 11110011 : // 01100100 01000100 01000100 01000000 11110000 11111111 00001111 00001100 : // 00000010 00100010 00100010 00100110 11001111 00000000 11111111 00001111 : // 00000001 00010001 00010001 00010110 00110000 11110000 11110000 11111111 : unsigned char P[64] = { 0xFF, 0x0F, 0x0F, 0x0C, 0x68, 0x88, 0x88, 0x80, 0xF0, 0xFF, 0x00, 0xF3, 0x64, 0x44, 0x44, 0x40, 0x30, 0xF0, 0xFF, 0x0F, 0x02, 0x22, 0x22, 0x26, 0xCF, 0x00, 0xF0, 0xFF, 0x01, 0x11, 0x11, 0x16, 0x68, 0x88, 0x88, 0x80, 0xFF, 0x0F, 0x00, 0xF3, 0x64, 0x44, 0x44, 0x40, 0xF0, 0xFF, 0x0F, 0x0C, 0x02, 0x22, 0x22, 0x26, 0xCF, 0x00, 0xFF, 0x0F, 0x01, 0x11, 0x11, 0x16, 0x30, 0xF0, 0xF0, 0xFF}; void print_bitstring_short(unsigned char _x, unsigned char _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } void print_bitstring(unsigned char * _x, unsigned char _n) { unsigned int i; // compute number of elements in _x div_t d = div(_n, 8); unsigned int N = d.quot + (d.rem ? 1 : 0); // print leader printf(" "); if (d.rem == 0) printf(" "); for (i=0; i<8-d.rem-1; i++) printf(" "); // print bitstring for (i=0; i #include #include #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "fec_secded_punctured_test.m" void usage() { printf("Usage: fec_secded_punctured_test\n"); printf(" h : print usage/help\n"); printf(" p : input rate, [1:8], default: 4\n"); printf(" s : SNR start [dB], default: -5\n"); printf(" x : SNR max [dB], default: 5\n"); printf(" n : number of SNR steps, default: 21\n"); printf(" t : number of trials, default: 1000\n"); } // encode symbol void secded7264_encode_symbol_punctured(unsigned char * _sym_dec, unsigned char * _sym_enc, unsigned int _p); // decode symbol void secded7264_decode_symbol_punctured(unsigned char * _sym_enc, unsigned char * _sym_dec, unsigned int _p); int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int p = 4; // input size: p in [1,8] float SNRdB_min = 0.0f; // minimum SNR float SNRdB_max = 10.0f; // maximum SNR unsigned int num_steps = 21; // number of steps unsigned int num_trials = 80000; // get command-line options int dopt; while((dopt = getopt(argc,argv,"hp:s:x:n:t:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'p': p = atoi(optarg); break; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; case 'n': num_steps = atoi(optarg); break; case 't': num_trials = atoi(optarg); break; default: printf("error: %s, unknown option\n", argv[0]); exit(-1); } } // validate input if (p < 1 || p >8) { fprintf(stderr,"error: %s, p must be in [1,8]\n", argv[0]); exit(1); } else if (SNRdB_max <= SNRdB_min) { fprintf(stderr,"error: %s, invalid SNR range\n", argv[0]); exit(1); } else if (num_steps < 1) { fprintf(stderr,"error: %s, must have at least 1 SNR step\n", argv[0]); exit(1); } // derived values unsigned int n = p*8; // decoded message length (bits) unsigned int k = (p+1)*8; // encoded message length (bits) float rate = (float)n / (float)k; float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_steps-1); unsigned int i; // arrays unsigned char m[p]; // original message [64 x 1] unsigned char v[p+1]; // encoded/transmitted message float complex y[k]; // received message with noise unsigned char r[p+1]; // received vector (hard decision) unsigned char m_hat[p]; // estimated original message #if 0 // test it out for (i=0; i 0 ) ? 0x80 : 0x00; r[i] |= ( crealf(y[8*i+1]) > 0 ) ? 0x40 : 0x00; r[i] |= ( crealf(y[8*i+2]) > 0 ) ? 0x20 : 0x00; r[i] |= ( crealf(y[8*i+3]) > 0 ) ? 0x10 : 0x00; r[i] |= ( crealf(y[8*i+4]) > 0 ) ? 0x08 : 0x00; r[i] |= ( crealf(y[8*i+5]) > 0 ) ? 0x04 : 0x00; r[i] |= ( crealf(y[8*i+6]) > 0 ) ? 0x02 : 0x00; r[i] |= ( crealf(y[8*i+7]) > 0 ) ? 0x01 : 0x00; } // decode secded7264_decode_symbol_punctured(r,m_hat,p); // compute errors in decoded message signal num_bit_errors[s] += count_bit_errors_array(m,m_hat,p); } // print results for this SNR step printf(" %8.3f %8.3f [%8u] %8u %12.4e %12.4e\n", SNRdB, SNRdB - 10*log10f(rate), n*num_trials, num_bit_errors[s], (float)(num_bit_errors[s]) / (float)(num_trials*n), 0.5f*erfcf(1.0f/sigma)); } // // export output file // FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"\n\n"); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"k = %u;\n", k); fprintf(fid,"r = n / k;\n"); fprintf(fid,"num_steps = %u;\n", num_steps); fprintf(fid,"num_trials = %u;\n", num_trials); fprintf(fid,"num_bit_trials = num_trials*n;\n"); for (i=0; i #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_SPC2216 0 #define OUTPUT_FILENAME "spc2216_ber_test.m" // encode message // _msg_org : original message [size: 32 bytes] // _msg_enc : encoded message [size: 61 bytes] void spc2216_encode(unsigned char * _msg_org, unsigned char * _msg_enc); // decode message // _msg_rec : received message [size: 61 bytes] // _msg_dec : decoded message [size: 32 bytes] void spc2216_decode(unsigned char * _msg_rec, unsigned char * _msg_dec); // pack message // _m : input message [size: 32 bytes] // _pr : row parities [size: 16 bytes, @ 6 bits] // _pc : col parities [size: 22 bytes, @ 6 bits] // _v : output message [size: 61 bytes] void spc2216_pack(unsigned char * _m, unsigned char * _pr, unsigned char * _pc, unsigned char * _v); // unpack message // _v : input message [size: 61 bytes] // _pr : row parities [size: 16 bytes, @ 6 bits] // _pc : col parities [size: 22 bytes, @ 6 bits] // _m : output message [size: 32 bytes] void spc2216_unpack(unsigned char * _v, unsigned char * _pr, unsigned char * _pc, unsigned char * _m); // transpose square message block (generic) // _m : input message block [size: _n x _n bits, _n*_n/8 bytes] // _n : matrix dimension (must be divisble by 8) void spc2216_transpose_block(unsigned char * _m, unsigned int _n, unsigned char * _mT); // transpose message block and row parities // _m : message block [size: 16 x 16 bits, 32 bytes] // _pr : row parities [size: 16 x 6 bits, 16 bytes] // _w : transposed array [size: 22 x 16 bits, 44 bytes] void spc2216_transpose_row(unsigned char * _m, unsigned char * _pr, unsigned char * _w); // transpose message block and row parities (reverse) // _w : transposed array [size: 22 x 16 bits, 44 bytes] // _m : message block [size: 16 x 16 bits, 32 bytes] // _pr : row parities [size: 16 x 6 bits, 16 bytes] void spc2216_transpose_col(unsigned char * _w, unsigned char * _m, unsigned char * _pr); // print decoded block void spc2216_print_decoded(unsigned char * _m); // print encoded block void spc2216_print_encoded(unsigned char * _v); // print unpacked block void spc2216_print_unpacked(unsigned char * _m, unsigned char * _pr, unsigned char * _pc); // decode message (soft bits) // _msg_rec : received soft message [size: 488 soft bits] // _msg_dec_hard : decoded hard message [size: 32 bytes] void spc2216_decode_soft(unsigned char * _msg_rec, unsigned char * _msg_dec_hard); // decode soft symbol // _msg_rec : received soft bits [size: 22 soft bits] // _msg_dec : decoded soft bits [size: 22 soft bits] // _msg_dec_hard : decoded hard bits [size: 32 bytes] int spc2216_decode_sym_soft(unsigned char * _msg_rec, unsigned char * _msg_dec); void print_bitstring(unsigned char _x, unsigned char _n) { unsigned int i; for (i=0; i<_n; i++) printf("%2s", ((_x >> (_n-i-1)) & 1) ? "1" : "."); } int main(int argc, char*argv[]) { srand(time(NULL)); unsigned int i; // error vector unsigned char e[61]; #if 0 for (i=0; i<61; i++) e[i] = (rand() % 8) == 0 ? 1 << rand() % 7 : 0; #else memset(e, 0x00, 61); e[3] = 0x08; #endif // original message [16 x 16 bits], 32 bytes unsigned char m[32]; // derived values unsigned char v[61]; // encoded/transmitted message unsigned char r[61]; // received vector unsigned char m_hat[32];// estimated original message // generate random transmitted message #if 0 for (i=0; i<32; i++) m[i] = rand() & 0xff; #else for (i=0; i<32; i++) { if (i < 16 && (i%2)==0) m[i] = 0xff >> (i/2); //1 << 7-(i/2); else if (i >= 16 && (i%2)==1) m[i] = 1 << (7-((i-16-1)/2)); else m[i] = 0x00; } #endif printf("m (original message):\n"); spc2216_print_decoded(m); // encode spc2216_encode(m, v); printf("v (encoded message):\n"); spc2216_print_encoded(v); printf("e (error message):\n"); spc2216_print_encoded(e); // add errors for (i=0; i<61; i++) r[i] = v[i] ^ e[i]; printf("r (received message):\n"); spc2216_print_encoded(r); // decode spc2216_decode(r, m_hat); // compute errors between m, m_hat unsigned int num_errors_decoded = count_bit_errors_array(m, m_hat, 32); printf("decoding errors (original) : %2u / 256\n", num_errors_decoded); // // test soft decoding // #if 1 unsigned char msg_rec_soft[8*61]; unsigned char soft0 = 64; unsigned char soft1 = 192; // modulate with BPSK for (i=0; i<61; i++) { msg_rec_soft[8*i+0] = (r[i] & 0x80) ? soft1 : soft0; msg_rec_soft[8*i+1] = (r[i] & 0x40) ? soft1 : soft0; msg_rec_soft[8*i+2] = (r[i] & 0x20) ? soft1 : soft0; msg_rec_soft[8*i+3] = (r[i] & 0x10) ? soft1 : soft0; msg_rec_soft[8*i+4] = (r[i] & 0x08) ? soft1 : soft0; msg_rec_soft[8*i+5] = (r[i] & 0x04) ? soft1 : soft0; msg_rec_soft[8*i+6] = (r[i] & 0x02) ? soft1 : soft0; msg_rec_soft[8*i+7] = (r[i] & 0x01) ? soft1 : soft0; } // add 'noise'... for (i=0; i<6*61; i++) { int LLR = msg_rec_soft[i] + 30*randnf(); if (LLR < 0) LLR = 0; if (LLR > 255) LLR = 255; msg_rec_soft[i] = LLR; } // test soft-decision decoding memset(m_hat, 0x00, 32); spc2216_decode_soft(msg_rec_soft, m_hat); // compute errors between m, m_hat num_errors_decoded = count_bit_errors_array(m, m_hat, 32); printf("soft decoding errors (original) : %2u / 256\n", num_errors_decoded); #else // 1 1 . . 1 1 |. . 1 1 1 1 1 1 . . . . . . . . unsigned char msg_rec_soft[22] = { 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, }; // add noise for (i=0; i<22; i++) { int bit = msg_rec_soft[i] > 128 ? 192 : 64; bit += 30*randnf(); if (bit < 0) bit = 0; if (bit > 255) bit = 255; msg_rec_soft[i] = (unsigned char)bit; } int rc = spc2216_decode_sym_soft(msg_rec_soft, m_hat); #endif // // run SNR trials // float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) float SNRdB_max = 10.0f; // signal-to-noise ratio (maximum) unsigned int num_snr = 31; // number of SNR steps unsigned int num_trials=10000; // number of trials // arrays float complex sym_rec[8*61]; // received BPSK symbols unsigned int bit_errors_hard[num_snr]; unsigned int bit_errors_soft[num_snr]; unsigned int n_enc = 61; unsigned char msg_org[32]; unsigned char msg_enc[61]; unsigned char msg_cor[61]; // corrupted message (hard bits) unsigned char msg_LLR[8*61]; // corrupted message (soft-bit log-likelihood ratio) unsigned char msg_dec_hard[32]; unsigned char msg_dec_soft[32]; // set up parameters float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); printf(" %8s %8s [%8s] %8s %12s %8s %12s %12s\n", "SNR [dB]", "Eb/N0", "trials", "hard", "(hard BER)", "soft", "(soft BER)", "uncoded"); unsigned int s; for (s=0; s 0.0f ? 0x80 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+1]) > 0.0f ? 0x40 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+2]) > 0.0f ? 0x20 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+3]) > 0.0f ? 0x10 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+4]) > 0.0f ? 0x08 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+5]) > 0.0f ? 0x04 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+6]) > 0.0f ? 0x02 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+7]) > 0.0f ? 0x01 : 0x00; } spc2216_decode(msg_cor, msg_dec_hard); // convert to approximate LLR (soft decoding) for (i=0; i<8*n_enc; i++) { int LLR = (int)( 256*(crealf(sym_rec[i])*0.5f + 0.5f) ); if (LLR < 0) LLR = 0; if (LLR > 255) LLR = 255; msg_LLR[i] = (unsigned char) LLR; } spc2216_decode_soft(msg_LLR, msg_dec_soft); // tabulate results bit_errors_hard[s] += count_bit_errors_array(msg_org, msg_dec_hard, 32); bit_errors_soft[s] += count_bit_errors_array(msg_org, msg_dec_soft, 32); } // print results for this SNR step float rate = 32. / 61.; // true rate printf(" %8.3f %8.3f [%8u] %8u %12.4e %8u %12.4e %12.4e\n", SNRdB, SNRdB - 10*log10f(rate), 8*32*num_trials, bit_errors_hard[s], (float)(bit_errors_hard[s]) / (float)(num_trials*32*8), bit_errors_soft[s], (float)(bit_errors_soft[s]) / (float)(num_trials*32*8), 0.5f*erfcf(1.0f/nstd)); } // // export output file // FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"\n\n"); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n = %u; %% frame size [bytes]\n", 32); fprintf(fid,"k = %u; %% encoded frame size [bytes]\n", 61); fprintf(fid,"r = n / k; %% true rate\n"); fprintf(fid,"num_snr = %u;\n", num_snr); fprintf(fid,"num_trials = %u;\n", num_trials); fprintf(fid,"num_bit_trials = num_trials*n*8;\n"); fprintf(fid,"bit_errors_hard = zeros(1,num_snr);\n"); fprintf(fid,"bit_errors_soft = zeros(1,num_snr);\n"); for (i=0; i> (6-j-1)) & 0x01) ? "1" : "."); if (i==15) printf(" "); } printf("\n"); } } // decode message (soft bits) // _msg_rec : received soft message [size: 488 soft bits] // _msg_dec_hard : decoded hard message [size: 32 bytes] void spc2216_decode_soft(unsigned char * _msg_rec, unsigned char * _msg_dec_hard) { unsigned char w[256]; // 256 = 16 x 16 bits unsigned char parity_row[96]; // 96 = 16 rows @ 6 bits unsigned char parity_col[132]; // 132 = 22 cols @ 6 bits // unpack encoded soft bits: memmove(w, _msg_rec, 256); memmove(parity_row, &_msg_rec[256], 96); memmove(parity_col, &_msg_rec[256+96], 132); unsigned int i; unsigned int j; #if 0 // print... for (i=0; i<16; i++) { printf(" "); for (j=0; j<16; j++) printf("%2s", w[16*i+j] > 128 ? "1" : "."); printf(" |"); for (j=0; j<6; j++) printf("%2s", parity_row[6*i+j] > 128 ? "1" : "."); printf("\n"); } printf(" ---------------------------------+-------------\n"); for (i=0; i<6; i++) { printf(" "); for (j=0; j<22; j++) printf("%2s", parity_col[6*j + i] > 128 ? "1" : "."); printf("\n"); } #endif // unsigned char sym_rec[22]; // encoded 22-bit message unsigned char sym_dec[22]; // decoded 22-bit message int syndrome_flag; // TODO : run multiple iterations... unsigned int n; for (n=0; n<6; n++) { #if DEBUG_SPC2216 printf("\n"); // print soft values for (i=0; i<16; i++) { for (j=0; j<16; j++) printf("%3u ", w[16*i+j]); printf("\n"); } #endif // compute syndromes on columns and run soft decoder //printf("columns (w):\n"); for (i=0; i<16; i++) { // extract encoded symbol for (j=0; j<6; j++) sym_rec[j ] = parity_col[j + 6*i]; for (j=0; j<16; j++) sym_rec[j+6] = w[16*j + i]; // run soft decoder syndrome_flag = spc2216_decode_sym_soft(sym_rec, sym_dec); // replace decoded symbol for (j=0; j<6; j++) parity_col[j + 6*i] = sym_dec[j]; for (j=0; j<16; j++) w[16*j + i] = sym_dec[j+6]; } // compute syndromes on row parities and run soft decoder //printf("row parities:\n"); for (i=0; i<6; i++) { // extract encoded symbol for (j=0; j<6; j++) sym_rec[j ] = parity_col[j + 6*(i+16)]; for (j=0; j<16; j++) sym_rec[j+6] = parity_row[6*j + i]; // run soft decoder syndrome_flag = spc2216_decode_sym_soft(sym_rec, sym_dec); // replace decoded symbol for (j=0; j<6; j++) parity_col[j + 6*(i+16)] = sym_rec[j]; for (j=0; j<16; j++) parity_row[6*j + i] = sym_rec[j+6]; } #if DEBUG_SPC2216 printf("...\n"); // print soft values for (i=0; i<16; i++) { for (j=0; j<16; j++) printf("%3u ", w[16*i+j]); printf("\n"); } #endif // compute syndromes on rows and run soft decoder //printf("rows:\n"); unsigned int num_errors = 0; for (i=0; i<16; i++) { // extract encoded symbol for (j=0; j<6; j++) sym_rec[j ] = parity_row[6*i + j]; for (j=0; j<16; j++) sym_rec[j+6] = w[16*i + j]; // run soft decoder syndrome_flag = spc2216_decode_sym_soft(sym_rec, sym_dec); num_errors += syndrome_flag == 0 ? 0 : 1; // replace decoded symbol for (j=0; j<6; j++) parity_row[6*i + j] = sym_rec[j]; for (j=0; j<16; j++) w[16*i + j] = sym_rec[j+6]; } //printf("%3u, detected %u soft decoding errors\n", n, num_errors); if (num_errors == 0) break; } // hard-decision decoding for (i=0; i<16; i++) { _msg_dec_hard[2*i+0] = 0; _msg_dec_hard[2*i+0] |= w[16*i+ 0] > 128 ? 0x80 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 1] > 128 ? 0x40 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 2] > 128 ? 0x20 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 3] > 128 ? 0x10 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 4] > 128 ? 0x08 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 5] > 128 ? 0x04 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 6] > 128 ? 0x02 : 0; _msg_dec_hard[2*i+0] |= w[16*i+ 7] > 128 ? 0x01 : 0; _msg_dec_hard[2*i+1] = 0; _msg_dec_hard[2*i+1] |= w[16*i+ 8] > 128 ? 0x80 : 0; _msg_dec_hard[2*i+1] |= w[16*i+ 9] > 128 ? 0x40 : 0; _msg_dec_hard[2*i+1] |= w[16*i+10] > 128 ? 0x20 : 0; _msg_dec_hard[2*i+1] |= w[16*i+11] > 128 ? 0x10 : 0; _msg_dec_hard[2*i+1] |= w[16*i+12] > 128 ? 0x08 : 0; _msg_dec_hard[2*i+1] |= w[16*i+13] > 128 ? 0x04 : 0; _msg_dec_hard[2*i+1] |= w[16*i+14] > 128 ? 0x02 : 0; _msg_dec_hard[2*i+1] |= w[16*i+15] > 128 ? 0x01 : 0; } // print decoded block //spc2216_print_decoded(_msg_dec_hard); } // decode soft symbol // _msg_rec : received soft bits [size: 22 soft bits] // _msg_dec : decoded soft bits [size: 22 soft bits] // return value: syndrome flag int spc2216_decode_sym_soft(unsigned char * _msg_rec, unsigned char * _msg_dec) { // pack... unsigned char sym_enc[3] = {0, 0, 0}; unsigned char e_hat[3]; unsigned int i; #if DEBUG_SPC2216 printf(" msg_rec:"); for (i=0; i<22; i++) printf("%3u,", _msg_rec[i]); printf("\n"); #endif for (i=0; i<6; i++) { sym_enc[0] <<= 1; sym_enc[0] |= _msg_rec[i] > 128 ? 1 : 0; } for (i=0; i<8; i++) { sym_enc[1] <<= 1; sym_enc[2] <<= 1; sym_enc[1] |= _msg_rec[ 6 + i] > 128 ? 1 : 0; sym_enc[2] |= _msg_rec[14 + i] > 128 ? 1 : 0; } int syndrome_flag = fec_secded2216_estimate_ehat(sym_enc, e_hat); #if DEBUG_SPC2216 if (syndrome_flag == 0) { printf(" (no errors detected)\n"); } else if (syndrome_flag == 1) { printf(" (one error detected and corrected!)\n"); } else { printf(" (multiple errors detected)\n"); } printf(" input : "); print_bitstring(sym_enc[0], 6); printf("|"); print_bitstring(sym_enc[1], 8); print_bitstring(sym_enc[2], 8); printf("\n"); #endif // apply error vector estimate to appropriate arrays sym_enc[0] ^= e_hat[0]; sym_enc[1] ^= e_hat[1]; sym_enc[2] ^= e_hat[2]; #if DEBUG_SPC2216 printf(" output : "); print_bitstring(sym_enc[0], 6); printf("|"); print_bitstring(sym_enc[1], 8); print_bitstring(sym_enc[2], 8); printf("\n"); #endif // unpack... unsigned char sym_dec_soft[22]; for (i=0; i<6; i++) { sym_dec_soft[i] = sym_enc[0] & (1 << (6-i-1)) ? 255 : 0; } for (i=0; i<8; i++) { sym_dec_soft[ 6 + i] = sym_enc[1] & (1 << (8-i-1)) ? 255 : 0; sym_dec_soft[14 + i] = sym_enc[2] & (1 << (8-i-1)) ? 255 : 0; } // combine... for (i=0; i<22; i++) { int delta = (int)sym_dec_soft[i] - 128; //_msg_dec[i] = 0.5*_msg_rec[i] + 0.5*sym_dec_soft[i]; int bit = _msg_rec[i] + 0.2*delta; if (bit < 0) bit = 0; if (bit > 255) bit = 255; _msg_dec[i] = (unsigned char) bit; } #if DEBUG_SPC2216 printf(" msg_dec:"); for (i=0; i<22; i++) printf("%3u,", _msg_dec[i]); printf("\n"); #endif return syndrome_flag; } liquid-dsp-1.7.0/sandbox/fec_sumproduct_test.c000066400000000000000000000031341474751757600215050ustar00rootroot00000000000000// // fec_sumproduct_test.c // // Test soft decoding of LDPC codes using internal sum-product // algorithm. // #include #include #include #include "liquid.internal.h" int main(int argc, char*argv[]) { // parity check matrix unsigned char Hb[32] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1}; // convert H to sparse matrix smatrixb H = smatrixb_create_array(Hb, 4, 8); // transmitted codeword unsigned char c[8] = { 1, 0, 1, 0, 1, 1, 1, 1}; // received message float y[8] = {0.2, 0.2, -0.9, 0.6, 0.5, -1.1, -0.4, -1.2}; unsigned int i; // noise standard deviation float sigma = sqrtf(0.5f); unsigned int m = 4; unsigned int n = 8; // convert received signal to LLR float LLR[n]; for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "fecsoft_ber_test.m" void usage() { printf("fec_ber\n"); printf(" Simulates soft decoding\n"); printf("options:\n"); printf(" u/h : print usage/help\n"); printf(" s : SNR start [dB], default: -2\n"); printf(" x : SNR max [dB], default: 13\n"); printf(" n : number of SNR steps, default: 16\n"); printf(" t : number of trials, default: 800\n"); printf(" f : frame size, default: 64\n"); printf(" c : coding scheme, (h74 default):\n"); liquid_print_fec_schemes(); } int main(int argc, char *argv[]) { // set initial seed to random srand(time(NULL)); // options unsigned int n = 64; // frame size (bytes) float SNRdB_min = -2.0f; // signal-to-noise ratio (minimum) float SNRdB_max = 13.0f; // signal-to-noise ratio (maximum) unsigned int num_snr = 16; // number of SNR steps unsigned int num_trials=800; // number of trials fec_scheme fs = LIQUID_FEC_HAMMING74; // error-correcting scheme // get command-line options int dopt; while((dopt = getopt(argc,argv,"uhs:x:n:t:f:c:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; case 'n': num_snr = atoi(optarg); break; case 't': num_trials = atoi(optarg); break; case 'f': n = atoi(optarg); break; case 'c': fs = liquid_getopt_str2fec(optarg); if (fs == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } unsigned int i; // create arrays unsigned int n_enc = fec_get_enc_msg_length(fs,n); printf("dec msg len : %u\n", n); printf("enc msg len : %u\n", n_enc); float rate = (float)n / (float)n_enc; unsigned char msg_org[n]; // original data message unsigned char msg_enc[n_enc]; // encoded data message float complex sym_rec[8*n_enc]; // received BPSK symbols unsigned char msg_cor_soft[8*n_enc]; // corrupted data message (soft bits) unsigned char msg_cor_hard[n_enc]; // corrupted data message (hard bits) unsigned char msg_dec_soft[n]; // decoded data message (soft bits) unsigned char msg_dec_hard[n]; // decoded data message (soft bits) // create object fec q = fec_create(fs,NULL); fec_print(q); unsigned int bit_errors_soft[num_snr]; unsigned int bit_errors_hard[num_snr]; // // set up parameters // float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); // // start trials // printf(" %8s %8s [%8s] %8s %12s %8s %12s %12s\n", "SNR [dB]", "Eb/N0", "trials", "soft", "(BER)", "hard", "(BER)", "uncoded"); unsigned int s; for (s=0; s 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; msg_cor_soft[i] = (unsigned char)(soft_bit); } // convert to hard bits (hard decoding) for (i=0; i 0.0f ? 0x80 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+1]) > 0.0f ? 0x40 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+2]) > 0.0f ? 0x20 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+3]) > 0.0f ? 0x10 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+4]) > 0.0f ? 0x08 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+5]) > 0.0f ? 0x04 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+6]) > 0.0f ? 0x02 : 0x00; msg_cor_hard[i] |= crealf(sym_rec[8*i+7]) > 0.0f ? 0x01 : 0x00; } // decode fec_decode( q, n, msg_cor_hard, msg_dec_hard); fec_decode_soft(q, n, msg_cor_soft, msg_dec_soft); // tabulate results bit_errors_soft[s] += count_bit_errors_array(msg_org, msg_dec_soft, n); bit_errors_hard[s] += count_bit_errors_array(msg_org, msg_dec_hard, n); } // print results for this SNR step printf(" %8.3f %8.3f [%8u] %8u %12.4e %8u %12.4e %12.4e\n", SNRdB, SNRdB - 10*log10f(rate), 8*n*num_trials, bit_errors_soft[s], (float)(bit_errors_soft[s]) / (float)(num_trials*n*8), bit_errors_hard[s], (float)(bit_errors_hard[s]) / (float)(num_trials*n*8), 0.5f*erfcf(1.0f/nstd)); } // clean up objects fec_destroy(q); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"\n\n"); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n = %u; %% frame size [bytes]\n", n); fprintf(fid,"k = %u; %% encoded frame size [bytes]\n", n_enc); fprintf(fid,"r = n / k; %% true rate\n"); fprintf(fid,"num_snr = %u;\n", num_snr); fprintf(fid,"num_trials = %u;\n", num_trials); fprintf(fid,"num_bit_trials = num_trials*n*8;\n"); for (i=0; i #include #include #include #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "fecsoft_conv_test.m" void usage() { printf("fecsoft_conv_test\n"); printf(" Simulates soft decoding of convoluational codes\n"); printf("options:\n"); printf(" u/h : print usage/help\n"); printf(" s : SNR start [dB], default: -5\n"); printf(" x : SNR max [dB], default: 5\n"); printf(" n : number of SNR steps, default: 21\n"); printf(" t : number of trials, default: 1000\n"); printf(" c : convoluational coding scheme: v27, v29, v39, v615, punctured\n"); } int main(int argc, char *argv[]) { // set initial seed to random srand(time(NULL)); // options fec_scheme fs = LIQUID_FEC_CONV_V27; // convolutional FEC scheme unsigned int n = 64; // original message length float SNRdB_min = -5.0f; // signal-to-noise ratio (minimum) float SNRdB_max = 5.0f; // signal-to-noise ratio (maximum) unsigned int num_snr = 21; // number of SNR steps unsigned int num_trials=100; // number of trials // get command-line options int dopt; while((dopt = getopt(argc,argv,"uhs:x:n:t:c:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; case 'n': num_snr = atoi(optarg); break; case 't': num_trials = atoi(optarg); break; case 'c': fs = liquid_getopt_str2fec(optarg); if (fs == LIQUID_FEC_UNKNOWN ) { fprintf(stderr,"error: %s, unknown/unsupported fec scheme \"%s\"\n\n",argv[0], optarg); exit(1); } else if ( !fec_scheme_is_convolutional(fs) ) { fprintf(stderr,"error: %s, input fec scheme '%s' is not convolutional\n\n",argv[0], optarg); exit(1); } break; default: exit(1); } } unsigned int i; // derived values unsigned int k = fec_get_enc_msg_length(fs, n); // encoded message length // create forward error-correction object fec q = fec_create(fs, NULL); fec_print(q); // // data arrays // #if 0 unsigned int sym_org; // original symbol float complex sym_enc[7]; // encoded symbol float complex sym_rec[7]; // received symbol #endif unsigned char msg_org[n]; // original message unsigned char msg_enc[k]; // encoded message float complex mod_sym[8*k]; // modulated symbols unsigned char msg_rec_soft[8*k]; // received 'soft' bits unsigned char msg_rec_hard[8*k]; // received 'hard' bits unsigned char msg_dec_soft[n]; // soft-decision decoding unsigned char msg_dec_hard[n]; // hard-decision decoding unsigned int bit_errors_soft[num_snr]; unsigned int bit_errors_hard[num_snr]; // // set up parameters // float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); // // start trials // #if 0 // test sym_org = 13; fecsoft_hamming74_encode(sym_org, sym_enc); fecsoft_hamming74_decode(sym_enc, &sym_dec_soft); exit(1); #endif printf(" %8s [%6s] %6s %6s\n", "SNR [dB]", "trials", "soft", "hard"); unsigned int s; for (s=0; s> 7) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+1] = ((msg_enc[i] >> 6) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+2] = ((msg_enc[i] >> 5) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+3] = ((msg_enc[i] >> 4) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+4] = ((msg_enc[i] >> 3) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+5] = ((msg_enc[i] >> 2) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+6] = ((msg_enc[i] >> 1) & 0x01) ? 1.0f : -1.0f; mod_sym[8*i+7] = ((msg_enc[i] ) & 0x01) ? 1.0f : -1.0f; } // add noise for (i=0; i<8*k; i++) mod_sym[i] += nstd*randnf()*cexpf(_Complex_I*2*M_PI*randf()); // 'demodulate' hard/soft for (i=0; i<8*k; i++) { // hard decision msg_rec_hard[i] = ( crealf(mod_sym[i]) > 0.0f ) ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; // soft decision #if 0 float soft_bit = (255*( 0.5f + 0.5f*tanhf(crealf(mod_sym[i])) )); if (soft_bit < 0) msg_rec_soft[i] = 0; else if (soft_bit > 255) msg_rec_soft[i] = 255; else msg_rec_soft[i] = (unsigned char) soft_bit; #else msg_rec_soft[i] = (unsigned char)(255*( 0.5f + 0.5f*tanhf(crealf(mod_sym[i])) )); #endif //printf(" hard : %3u, soft : %3u\n", msg_rec_hard[i], msg_rec_soft[i]); } // decode using 'soft' algorithm if ( fec_scheme_is_punctured(fs) ) { fec_conv_punctured_decode_soft(q, n, msg_rec_hard, msg_dec_hard); fec_conv_punctured_decode_soft(q, n, msg_rec_soft, msg_dec_soft); } else { fec_conv_decode_soft(q, n, msg_rec_hard, msg_dec_hard); fec_conv_decode_soft(q, n, msg_rec_soft, msg_dec_soft); } // count bit errors and tabulate results bit_errors_hard[s] += count_bit_errors_array(msg_org, msg_dec_hard, n); bit_errors_soft[s] += count_bit_errors_array(msg_org, msg_dec_soft, n); } // print results for this SNR step printf(" %8.3f [%6u] %6u %6u\n", SNRdB, 8*n*num_trials, bit_errors_soft[s], bit_errors_hard[s]); } // destroy forward error-correction object fec_destroy(q); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"\n\n"); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n = %u;\n", n); fprintf(fid,"k = %u;\n", k); fprintf(fid,"num_trials = %u;\n", num_trials); fprintf(fid,"total_bits = %u;\n", 8*n*num_trials); fprintf(fid,"num_snr = %u;\n", num_snr); fprintf(fid,"num_trials = %u;\n", num_trials); for (i=0; i #include #include "liquid.internal.h" int main() { // find the 17 symbols with a hamming distance of exactly 3 unsigned int sym_org; // original symbol unsigned int sym_enc; // encoded symbol unsigned int n3; // counter for symbols with a Hamming distance 3 unsigned char sym3[17]; // ... unsigned int i; printf("unsigned char fecsoft_hamming128_neighbors[256][17] = {\n"); for (sym_org=0; sym_org<256; sym_org++) { // printf(" {"); // reset counter n3=0; // encode symbol sym_enc = fec_hamming128_encode_symbol(sym_org); // look at all possible symbols... for (i=0; i<256; i++) { unsigned int sym_test = fec_hamming128_encode_symbol(i); // compute number of bit differences... unsigned int d = count_bit_errors(sym_enc, sym_test); // if (d==3) { if (n3 == 17) { fprintf(stderr,"error: expected no more than 17 symbols of distance 3\n"); exit(1); } sym3[n3++] = i; } // print results... //printf(" %3u : %3u\n", i, d); } //printf(" %3u : n3 =%3u\n", sym_org, n3); if (n3 != 17) { fprintf(stderr,"error: expected exactly 17 symbols of distance 3\n"); exit(1); } // print line for (i=0; i<17; i++) { printf("0x%.2x", sym3[i]); if (i != 16) printf(", "); } printf("}"); if (sym_org != 255) printf(",\n"); else printf("};\n"); } return 0; } liquid-dsp-1.7.0/sandbox/fecsoft_ldpc_test.c000066400000000000000000000134021474751757600211150ustar00rootroot00000000000000// // fecsoft_ldpc_test.c // // Test soft decoding using the sum-product // algorithm (see sandbox/ldpc_test.c) // // The generator and parity check matrices can be generated from // the 16 x 16 matrix P. Each row of P is a circular shift of the // generator polynomial p = [ 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0] // such that P^T = P and // G = [I(16) P ]^T // H = [P^T I(16)] #include #include #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "fecsoft_ldpc_test.m" int main(int argc, char*argv[]) { // initialize random seed srand(time(NULL)); float SNRdB_min = -2.0f; float SNRdB_max = 6.0f; unsigned int num_steps = 19; unsigned int num_trials = 2000; unsigned int max_iterations = 5; unsigned int m = 16; // rows in H unsigned int n = 32; // cols in H // initial generator polynomial // TODO : find 'optimal' generator polynomial unsigned char p[] = {1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,0,0}; // generator matrix [n x m] unsigned char Gs[n*m]; // parity check matrix [m x n] unsigned char Hs[m*n]; unsigned int i; unsigned int j; // init generator and parity check matrices for (i=0; i #include #include #include #include #include #define DEBUG 0 #define DFT_FORWARD (-1) #define DFT_REVERSE ( 1) // print usage/help message void usage() { printf("fft_mixed_radix_test -- test mixed-radix DFTs, compare to slow DFT method\n"); printf("options (default values in []):\n"); printf(" u/h : print usage/help\n"); printf(" p : stride (freq)\n"); printf(" q : stride (time)\n"); } // super slow DFT, but functionally correct void dft_run(unsigned int _nfft, float complex * _x, float complex * _y, int _dir, int _flags); int main(int argc, char*argv[]) { // transform size: p*q unsigned int p = 5; unsigned int q = 3; int dopt; while ((dopt = getopt(argc,argv,"uhp:q:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'p': p = atoi(optarg); break; case 'q': q = atoi(optarg); break; default: exit(1); } } // transform size unsigned int n = p*q; // validate input if ( n == 0 ) { fprintf(stderr,"error: input transform size must be at least 2\n"); exit(1); } unsigned int i; unsigned int k; // create and initialize data arrays float complex x[n]; float complex y[n]; float complex y_test[n]; for (i=0; i %12.6f + j%12.6f\n", crealf(t0[k]), cimagf(t0[k]), crealf(t1[k]), cimagf(t1[k])); #endif } // multiply by twiddle factors // NOTE: this can be combined with previous step printf("multiplying twiddles...\n"); for (i=0; i %12.6f + j%12.6f\n", crealf(t0[k]), cimagf(t0[k]), crealf(t1[k]), cimagf(t1[k])); #endif } // transpose results for (i=0; i #include #include #include #include #include #define DEBUG 0 #define DFT_FORWARD (-1) #define DFT_REVERSE ( 1) #define MAX_FACTORS (40) // print usage/help message void usage() { printf("fft_mixed_radix_test -- test mixed-radix DFTs, compare to slow DFT method\n"); printf("options (default values in []):\n"); printf(" h : print usage/help\n"); printf(" n : fft size\n"); } // super slow DFT, but functionally correct void dft_run(unsigned int _nfft, float complex * _x, float complex * _y, int _dir, int _flags); // FFT mixed-radix butterfly // _x : input/output buffer pointer [size: _nfft x 1] // _twiddle : pre-computed twiddle factors [size: _nfft x 1] // _nfft : original FFT size // _stride : output stride // _m : number of FFTs to compute // _p : generic (small) FFT size // // NOTES : the butterfly decimates in time, storing the output as // contiguous samples in the same buffer. void fftmr_bfly(float complex * _x, float complex * _twiddle, unsigned int _nfft, unsigned int _stride, unsigned int _m, unsigned int _p) { #if DEBUG printf(" bfly: stride=%3u, m=%3u, p=%3u\n", _stride, _m, _p); #endif // create temporary buffer the size of the FFT float complex * x_tmp = (float complex *) malloc(_p*sizeof(float complex)); unsigned int i; unsigned int k; unsigned int n; for (n=0; n<_m; n++) { #if DEBUG printf(" u=%u\n", n); #endif // copy input to temporary buffer for (i=0; i<_p; i++) x_tmp[i] = _x[n + i*_m]; // compute DFT, applying appropriate twiddle factors unsigned int twiddle_base = n; for (i=0; i<_p; i++) { #if DEBUG printf(" ----\n"); #endif float complex y = x_tmp[0]; unsigned int twiddle_index = 0; for (k=1; k<_p; k++) { twiddle_index = (twiddle_index + _stride*twiddle_base) % _nfft; #if DEBUG printf(" twiddle_index = %3u > %12.8f + j%12.8f, %12.8f + j%12.8f\n", twiddle_index, crealf(_twiddle[twiddle_index]), cimagf(_twiddle[twiddle_index]), crealf(x_tmp[k]), cimagf(x_tmp[k])); #endif y += x_tmp[k] * _twiddle[twiddle_index]; } // increment twiddle twiddle base twiddle_base += _m; // store output _x[n + i*_m] = y; #if DEBUG printf(" y = %12.6f + j%12.6f\n", crealf(y), cimagf(y)); #endif } } // free temporary buffer free(x_tmp); } // FFT mixed-radix recursive function... // _x : constant input pointer [size: _nfft x 1] // _y : output pointer // _twiddle : pre-computed twiddle factors [size: _nfft x 1] // _nfft : original FFT size // _xoffset : input buffer offset // _xstride : input buffer stride // _m_vect : array of radix values [size: num_factors x 1] // _p_vect : array of DFT values [size: num_factors x 1] void fftmr_cycle(float complex * _x, float complex * _y, float complex * _twiddle, unsigned int _nfft, unsigned int _xoffset, unsigned int _xstride, unsigned int * _m_vect, unsigned int * _p_vect) { // de-reference factors and pop values off the top unsigned int m = _m_vect[0]; // radix unsigned int p = _p_vect[0]; // DFT size // increment factor pointers _m_vect++; _p_vect++; #if DEBUG printf("fftmr_cycle: offset=%3u, stride=%3u, p=%3u, m=%3u\n", _xoffset, _xstride, p, m); #endif unsigned int i; if ( m == 1 ) { // copy data to output buffer for (i=0; i 1 && num_factors < MAX_FACTORS); // NOTE: this is extremely unlikely as the worst case is // nfft=2^MAX_FACTORS in which case we will probably run out // of memory first if (num_factors == MAX_FACTORS) { fprintf(stderr,"error: could not factor %u with %u factors\n", nfft, MAX_FACTORS); exit(1); } printf("factors of %u:\n", nfft); for (i=0; i #include #include #include #include #include #include "liquid.internal.h" #ifdef HAVE_FFTW3_H # include #endif // print usage/help message void usage() { printf("fft_r2r_test -- test real ffts, compare to fftw3\n"); printf("options (default values in []):\n"); printf(" u/h : print usage/help\n"); printf(" n : number of points\n"); } int main(int argc, char*argv[]) { #ifdef HAVE_FFTW3_H unsigned int n = 32; // transform size unsigned int d = 4; // number of elements to print each line int dopt; while ((dopt = getopt(argc,argv,"uhn:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'n': n = atoi(optarg); break; default: exit(1); } } // validate input if ( n < 2 ) { fprintf(stderr,"error: input transform size must be at least 2\n"); exit(1); } // create and initialize data arrays float x[n]; float y[n]; unsigned int i; for (i=0; i #include #include #include #include #include #define DEBUG 0 #define DFT_FORWARD (-1) #define DFT_REVERSE ( 1) #define MAX_FACTORS (40) // print usage/help message void usage() { printf("fft_rader_prime_radix2_test -- test Rader's alternate prime FFT\n"); printf(" algorithm, compare to slow DFT method\n"); printf("options (default values in []):\n"); printf(" h : print usage/help\n"); printf(" n : fft size (must be prime and greater than 2)\n"); } // super slow DFT, but functionally correct void dft_run(unsigned int _nfft, float complex * _x, float complex * _y, int _dir, int _flags); // determine if number is prime (slow, simple method) int is_prime(unsigned int _n); // find smallest primitive root of _n (assuming _n is prime) unsigned int primitive_root(unsigned int _n); // compute c = base^exp (mod n) unsigned int modpow(unsigned int _base, unsigned int _exp, unsigned int _n); int main(int argc, char*argv[]) { // transform size (must be prime) unsigned int nfft = 17; int dopt; while ((dopt = getopt(argc,argv,"uhn:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': nfft = atoi(optarg); break; default: exit(1); } } // validate input if ( nfft <= 2 || !is_prime(nfft)) { fprintf(stderr,"error: %s, input transform size must be prime and greater than two\n", argv[0]); exit(1); } unsigned int i; // create and initialize data arrays float complex * x = (float complex *) malloc(nfft * sizeof(float complex)); float complex * y = (float complex *) malloc(nfft * sizeof(float complex)); float complex * y_test = (float complex *) malloc(nfft * sizeof(float complex)); if (x == NULL || y == NULL || y_test == NULL) { fprintf(stderr,"error: %s, not enough memory for allocation\n", argv[0]); exit(1); } for (i=0; i 0) { nfft_prime >>= 1; m++; } nfft_prime = 1 << m; printf("nfft_prime = %u\n", nfft_prime); #else // compute larger FFT length greater than 2*nfft-4 // NOTE: while any length greater than 2*nfft-4 will work, use // nfft_prime as smallest 'simple' FFT (mostly small factors) // // score(n) = n / sum(factors(n).^2) float gamma_max = 0.0f; // score unsigned int nfft_prime_opt = 0; for (i=1; i<=10 + nfft/4; i++) { unsigned int n_hat = 2*nfft - 4 + i; // compute factors printf("%3u : ", n_hat); unsigned int k; unsigned int num_factors = 0; unsigned int m = n_hat; float gamma = 0.0f; do { for (k=2; k<=m; k++) { if ( (m % k) == 0) { printf("%-4u", k); m /= k; num_factors++; gamma += k*k; break; } } } while (m > 1); for (k=12; k>num_factors; k--) printf(" "); // compute score: //float gamma = (float)n_hat / (float)num_factors; //float gamma = 1e3f * (float)num_factors / (float)n_hat; gamma = (float)n_hat / gamma; printf(" score : %12.8f%s\n", gamma, gamma > gamma_max ? " *" : ""); if (gamma > gamma_max) { gamma_max = gamma; nfft_prime_opt = n_hat; } } printf("best nfft_prime : %u\n", nfft_prime_opt); unsigned int nfft_prime = nfft_prime_opt; #endif // compute DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft_prime // NOTE: R[0] = -1, |R[k]| = sqrt(nfft) for k != 0 // NOTE: R can be pre-computed float complex * r = (float complex*)malloc((nfft_prime)*sizeof(float complex)); float complex * R = (float complex*)malloc((nfft_prime)*sizeof(float complex)); for (i=0; i 1 && num_unique_factors < MAX_FACTORS); #if 0 // print unique factors printf("found %u unique factors of n-1 = %u\n", num_unique_factors, _n-1); for (k=0; k #include #include #include #include #include #define DEBUG 0 #define DFT_FORWARD (-1) #define DFT_REVERSE ( 1) #define MAX_FACTORS (40) // print usage/help message void usage() { printf("fft_rader_prime_test -- test Rader's prime FFT algorithm, compare to slow DFT method\n"); printf("options (default values in []):\n"); printf(" h : print usage/help\n"); printf(" n : fft size (must be prime and greater than 2)\n"); } // super slow DFT, but functionally correct void dft_run(unsigned int _nfft, float complex * _x, float complex * _y, int _dir, int _flags); // determine if number is prime (slow, simple method) int is_prime(unsigned int _n); // find smallest primitive root of _n (assuming _n is prime) unsigned int primitive_root(unsigned int _n); // compute c = base^exp (mod n) unsigned int modpow(unsigned int _base, unsigned int _exp, unsigned int _n); int main(int argc, char*argv[]) { // transform size (must be prime) unsigned int nfft = 17; int dopt; while ((dopt = getopt(argc,argv,"uhn:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': nfft = atoi(optarg); break; default: exit(1); } } // validate input if ( nfft <= 2 || !is_prime(nfft)) { fprintf(stderr,"error: %s, input transform size must be prime and greater than two\n", argv[0]); exit(1); } unsigned int i; // create and initialize data arrays float complex * x = (float complex *) malloc(nfft * sizeof(float complex)); float complex * y = (float complex *) malloc(nfft * sizeof(float complex)); float complex * y_test = (float complex *) malloc(nfft * sizeof(float complex)); if (x == NULL || y == NULL || y_test == NULL) { fprintf(stderr,"error: %s, not enough memory for allocation\n", argv[0]); exit(1); } for (i=0; i 1 && num_unique_factors < MAX_FACTORS); #if 0 // print unique factors printf("found %u unique factors of n-1 = %u\n", num_unique_factors, _n-1); for (k=0; k #include #include #include #include #include #include "liquid.internal.h" // print usage/help message void usage() { printf("fft_recursive_plan_test -- test planning FFTs\n"); printf("options (default values in []):\n"); printf(" h : print help\n"); printf(" n : input fft size\n"); } // print fft plan // _nfft : input fft size // _level : level void liquid_fft_plan(unsigned int _nfft, unsigned int _level); int main(int argc, char*argv[]) { // options unsigned int nfft = 124; int dopt; while ((dopt = getopt(argc,argv,"hn:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': nfft = atoi(optarg); break; default: exit(1); } } // validate input if ( nfft == 0 ) { fprintf(stderr,"error: input transform size must be at least 2\n"); exit(1); } // print the FFT plan liquid_fft_plan(nfft, 0); printf("done.\n"); return 0; } // print fft plan // _nfft : input fft size // _level : level void liquid_fft_plan(unsigned int _nfft, unsigned int _level) { if (_nfft == 0) { // invalid length fprintf(stderr,"error: liquid_fft_estimate_method(), fft size must be > 0\n"); exit(1); } // print appropriate spacing unsigned int i; for (i=0; i<_level; i++) printf(" "); // print fft size printf("%u, ", _nfft); if (_nfft < 8) { // use simple DFT codelet printf("codelet\n"); return; } else if (fft_is_radix2(_nfft)) { // transform is of the form 2^m printf("radix-2\n"); return; } else if (liquid_is_prime(_nfft)) { // compute prime factors of _nfft-1 unsigned int factors[LIQUID_MAX_FACTORS]; unsigned int num_factors=0; liquid_factor(_nfft-1,factors,&num_factors); if (num_factors > 2) { // use Rader's algorithm (type I) for size _nfft-1 printf("Rader's algorithm, Type I > %u\n", _nfft-1); liquid_fft_plan(_nfft-1, _level+1); return; } else { // use Rader's algorithm (type II) for radix-2 // nfft_prime = 2 ^ nextpow2(2*nfft - 4) unsigned int nfft_prime = 1 << liquid_nextpow2(2*_nfft-4); printf("Rader's algorithm, Type II > %u\n", nfft_prime); liquid_fft_plan(nfft_prime, _level+1); return; } } // use Cooley-Tukey algorithm printf("Cooley-Tukey\n"); // compute prime factors of _nfft unsigned int factors[LIQUID_MAX_FACTORS]; unsigned int num_factors=0; liquid_factor(_nfft,factors,&num_factors); for (i=0; i #include #include #include #include #include #include "liquid.h" #define DEBUG 0 #define DFT_FORWARD (-1) #define DFT_REVERSE ( 1) // print usage/help message void usage() { printf("fft_recursive_test -- test recursive mixed-radix DFTs, compare to slow DFT method\n"); printf("options (default values in []):\n"); printf(" h : print help\n"); printf(" n : fft size, default: 30\n"); } // recursive FFT algorithm void fft_recursion(unsigned int _nfft, float complex * _x, float complex * _y, int _dir); // super slow DFT, but functionally correct void dft_run(unsigned int _nfft, float complex * _x, float complex * _y, int _dir); int main(int argc, char*argv[]) { // transform size unsigned int nfft = 30; int dopt; while ((dopt = getopt(argc,argv,"hn:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'n': nfft = atoi(optarg); break; default: exit(1); } } // validate input if ( nfft < 2 ) { fprintf(stderr,"error: %s, input transform size must be at least 2\n", argv[0]); exit(1); } unsigned int i; // create and initialize data arrays float complex x[nfft]; float complex y[nfft]; float complex y_test[nfft]; for (i=0; i #include #include #include "liquid.h" // print usage/help message void usage() { printf("firdes_energy_test:\n"); printf(" u/h : print usage/help\n"); printf(" f : filter cutoff frequency, 0 < f < 0.5, default: 0.2\n"); printf(" t : filter transition bandwidth, 0 < t < 0.5, default: 0.1\n"); printf(" s : filter stop-band attenuation [dB], 0 < s, default: 60\n"); printf(" m : fractional sample delay, -0.5 < m < 0.5, default: 0\n"); } int main(int argc, char*argv[]) { // options float fc=0.2f; // filter cutoff frequency float ft=0.1f; // filter transition float As=60.0f; // stop-band attenuation [dB] float mu=0.0f; // fractional timing offset int dopt; while ((dopt = getopt(argc,argv,"uhf:t:s:m:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'f': fc = atof(optarg); break; case 't': ft = atof(optarg); break; case 's': As = atof(optarg); break; case 'm': mu = atof(optarg); break; default: exit(1); } } // derived values unsigned int h_len = estimate_req_filter_len(ft,As); printf("h_len : %u\n", h_len); printf("filter design parameters\n"); printf(" cutoff frequency : %8.4f\n", fc); printf(" transition bandwidth : %8.4f\n", ft); printf(" stop-band attenuation [dB] : %8.4f\n", As); printf(" fractional sample offset : %8.4f\n", mu); printf(" filter length : %u\n", h_len); // generate the filter unsigned int i; float h[h_len]; liquid_firdes_kaiser(h_len,fc,As,mu,h); // print coefficients for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdes_fexp_test.m" // print usage/help message void usage() { printf("Usage: sandbox/firdes_fexp_test [OPTION]\n"); printf("Run example fexp receive filter design\n"); printf("\n"); printf(" u/h : print usage/help\n"); printf(" k : filter samples/symbol, k >= 2, default: 4\n"); printf(" m : filter delay (symbols), m >= 1, default: 3\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.3\n"); } float firdes_freqresponse_fexp(float _f, unsigned int _k, float _beta); int main(int argc, char*argv[]) { // options unsigned int k=4; // filter samples/symbol unsigned int m=3; // filter delay [symbols] float beta = 0.3f; // filter excess bandwidth factor // read properties from command line int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int h_len = 2*k*m+1; // filter length // arrays float ht[h_len]; // transmit filter coefficients float hr[h_len]; // receive filter coefficients // // start of filter design procedure // float H_prime[h_len]; // frequency response of Nyquist filter float complex h_tx[h_len]; // impulse response of square-root Nyquist filter float complex H_tx[h_len]; // frequency response of square-root Nyquist filter // compute frequency response of Nyquist filter for (i=0; i 0.5f) f = f - 1.0f; H_prime[i] = firdes_freqresponse_fexp(f,k,beta); } // compute square-root response, copy to fft input for (i=0; i f0 && f < f2) { // transition band float B = 0.5f/(float)_k; float gamma = logf(2.0f)/(_beta*B); if ( f < f1) { return expf(gamma*(B*(1-_beta) - f)); } else { return 1.0f - expf(gamma*(f - (1+_beta)*B)); } } else { return 0.0f; } return 0.0f; } liquid-dsp-1.7.0/sandbox/firdes_gmskrx_test.c000066400000000000000000000210751474751757600213360ustar00rootroot00000000000000// // firdes_gmskrx_test.c : test synthesis of GMSK receive filter // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdes_gmskrx_test.m" // print usage/help message void usage() { printf("Usage: sandbox/firdes_gmskrx_test [OPTION]\n"); printf("Run example GMSK receive filter design\n"); printf("\n"); printf(" u/h : print usage/help\n"); printf(" k : filter samples/symbol, k >= 2, default: 4\n"); printf(" m : filter delay (symbols), m >= 1, default: 3\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.3\n"); } int main(int argc, char*argv[]) { // options unsigned int k=4; // samples/symbol unsigned int m=3; // filter delay [symbols] float BT = 0.3f; // bandwidth-time product // read properties from command line int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': BT = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (BT <= 0.0f || BT >= 1.0f) { fprintf(stderr,"error: %s, BT must be in (0,1)\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int h_len = 2*k*m+1; // filter length // arrays float ht[h_len]; // transmit filter coefficients float hr[h_len]; // receive filter coefficients // design transmit filter liquid_firdes_gmsktx(k,m,BT,0.0f,ht); // print results to screen printf("gmsk transmit filter:\n"); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfb_rrrf_example.m" void apply_delay(float * _h, float * _h_prime, unsigned int _h_len, float _dt) { unsigned int L = _h_len % 2; unsigned int m = (_h_len - L)/2; float complex buf_time[_h_len]; float complex buf_freq[_h_len]; unsigned int i; // copy to buffer, applying appropriate shift for (i=0; i<_h_len; i++) buf_time[i] = _h[(i + m)%_h_len]; fft_run(_h_len, buf_time, buf_freq, LIQUID_FFT_FORWARD, 0); // apply phase shift for (i=0; i<_h_len; i++) { float v = (float)i - (float)m; buf_freq[(i+m+L)%_h_len] *= cexpf(-_Complex_I*_dt*2.*M_PI*v/(float)_h_len);; } #if 0 for (i=0; i<_h_len; i++) printf("H(%3u) = %12.8f + %12.8fi;\n", i+1, crealf(buf_freq[i]), cimagf(buf_freq[i])); printf("\n"); #endif fft_run(_h_len, buf_freq, buf_time, LIQUID_FFT_BACKWARD, 0); #if 0 for (i=0; i<_h_len; i++) printf("g(%3u) = %12.8f + %12.8fi;\n", i+1, crealf(buf_time[i]), cimagf(buf_time[i])); printf("\n"); #endif // copy result, apply shift, retain real component for (i=0; i<_h_len; i++) { _h_prime[(i+m)%_h_len] = crealf( buf_time[i] ); } #if 0 for (i=0; i<_h_len; i++) printf("h(%3u) = %12.8f;\n", i+1, _h_prime[i]); #endif } int main(int argc, char*argv[]) { // options unsigned int m = 12; // filter delay (samples) float fc = 0.25f; // filter cut-off frequency // derived values and buffers unsigned int h_len = 2*m + 1; float h[h_len]; // filter impulse response float g[h_len]; // transformed unsigned int i; for (i=0; i #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "firdes_length_test.m" // print usage/help message void usage() { printf("firdes_length_test:\n"); printf(" u/h : print usage/help\n"); printf(" t : filter transition bandwidth, 0 < t < 0.5, default: 0.1\n"); printf(" a : filter attenuation (minimum) [dB], default: 20\n"); printf(" A : filter attenuation (maximum) [dB], default: 100\n"); printf(" n : number of steps, default: 41\n"); } int main(int argc, char*argv[]) { // options float ft=0.1f; // filter transition float as_min = 20.0f; float as_max = 100.0f; unsigned int num_as = 41; // number of steps int dopt; while ((dopt = getopt(argc,argv,"uht:a:A:n:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': ft = atof(optarg); break; case 'a': as_min = atof(optarg); break; case 'A': as_max = atof(optarg); break; case 'n': num_as = atoi(optarg); break; default: exit(1); } } // validate input if (as_min <= 0.0f || as_max <= 0.0f) { fprintf(stderr,"error: %s, attenuation must be greater than zero\n", argv[0]); exit(1); } else if (as_max <= as_min) { fprintf(stderr,"error: %s, minimum attenuation cannot exceed maximum\n", argv[0]); exit(1); } else if (num_as < 2) { fprintf(stderr,"error: %s, must have at least 2 steps", argv[0]); exit(1); } // derived values float as_step = (as_max - as_min) / (float)(num_as - 1); // output to file FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"num_steps = %u;\n", num_as); fprintf(fid,"as=zeros(1,num_steps);\n"); fprintf(fid,"n_Kaiser=zeros(1,num_steps);\n"); fprintf(fid,"n_Herrmann=zeros(1,num_steps);\n"); unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "firdespm_halfband_test.m" // ideally all even index values up to center is zero float firdespm_halfband_utility(unsigned int _m, float * _h) { float u = 0.0f; unsigned int i; for (i=0; i<_m; i++) u += _h[2*i] * _h[2*i]; return 10*log10f( u / (float)_m ); } // ideally stop-band is zero float firdespm_halfband_utility_as(unsigned int _m, float _ft, float * _h) { unsigned int nfft = 1200; while (nfft < 20*_m) nfft <<= 1; float complex buf_time[nfft]; float complex buf_freq[nfft]; unsigned int i; unsigned int h_len = 4*_m+1; for (i=0; i 0.99f) { float u = firdespm_halfband(m, h, ft, gamma); printf("gamma=%12.8f, u = %12.6f", gamma, u); if (u < u_opt) { u_opt = u; g_opt = gamma; printf(" *\n"); } else { printf("\n"); break; } gamma *= 0.999999f; } //g_opt = 0.92329967f - 3.2e-3f; float u = firdespm_halfband(m, h, ft, g_opt); printf("g_opt : %12.8f, u = %12.8f\n", g_opt, u); // print coefficients unsigned int i; for (i=0; i #include "liquid.h" #define OUTPUT_FILENAME "firfarrow_rrrf_test.m" int main() { // options unsigned int h_len=19; // filter length unsigned int p=5; // polynomial order float fc=0.45f; // filter cutoff float As=60.0f; // stop-band attenuation [dB] unsigned int m=9; // number of delays to evaluate // coefficients array float h[h_len]; float tao = ((float)h_len-1)/2.0f; // nominal filter delay firfarrow_rrrf f = firfarrow_rrrf_create(h_len, p, fc, As); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"m = %u;\n", m); fprintf(fid,"h_len = %u;\n", h_len); fprintf(fid,"h = zeros(%u,%u);\n", m, h_len); fprintf(fid,"mu = zeros(1,%u);\n", m); fprintf(fid,"tao = %12.8f;\n", tao); unsigned int i, j; float mu_vect[m]; for (i=0; i #include #include #include #include #include "liquid.internal.h" #define DEBUG 1 int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels (must be even) unsigned int m=4; // filter delay unsigned int num_symbols=4*m; // number of symbols // validate input if (num_channels%2) { fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence #if 0 unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h); #endif // normalize float hsum = 0.0f; for (i=0; i #include #include #include #include "liquid.h" int main(int argc, char*argv[]) { // options unsigned int M=24; // number of channels (must be even) unsigned int m=2; // filter delay float As = 60.0f; // stop-band suppression unsigned int num_blocks=5000000;// number of symbols unsigned int nfft=1200; // // create filterbank objects from prototype firpfbch2_crcf qa = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, M, m, As); firpfbch2_crcf qs = firpfbch2_crcf_create_kaiser(LIQUID_SYNTHESIZER, M, m, As); spgramcf q = spgramcf_create_default(nfft); //spwaterfallcf psd = spwaterfallcf_create(1200,LIQUID_WINDOW_HAMMING,800,10,1200); // derived values unsigned int M2 = M/2; float complex buf_0[M2]; float complex buf_1[M ]; float complex buf_2[M2]; unsigned int i,j; float phi = 0.0f, dphi = 0.1*2*M_PI; for (i=0; i M_PI) phi -= 2*M_PI; if (phi <-M_PI) phi += 2*M_PI; } // run analysis filterbank firpfbch2_crcf_execute(qa, buf_0, buf_1); // run synthesis filterbank firpfbch2_crcf_execute(qs, buf_1, buf_2); // run result through spectrum estimation spgramcf_write(q, buf_2, M2); //spwaterfallcf_write(psd, buf_2, M2); } // explort to gnuplot spgramcf_export_gnuplot(q,"firpfbch2_flatness_test.gnu"); //spwaterfallcf_set_dims (psd,1200, 800); //spwaterfallcf_set_commands(psd,"set cbrange [-0.5:0.5]; set title 'waterfall'; unset grid;"); //spwaterfallcf_export (psd,"firpfbch2_flatness_test.waterfall"); // destroy filterbank objects firpfbch2_crcf_destroy(qa); // analysis filterbank firpfbch2_crcf_destroy(qs); // synthesis filterbank spgramcf_destroy(q); //spwaterfallcf_destroy(psd); printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/firpfbch2_test.c000066400000000000000000000301001474751757600203210ustar00rootroot00000000000000// // firpfbch2_analysis_equivalence_test.c // // This script tests the equivalence of a finite impulse response (fir) // polyphase filter bank (pfb) channelizer with two outputs per branch // per input symbol. #include #include #include #include #include #include "liquid.internal.h" // print debug status #define DEBUG 0 // use pseudo-random coefficients; this is useful for determining // functional correctness (no symmetry in filter) #define RANDOM_COEFFICIENTS 0 int main(int argc, char*argv[]) { // options unsigned int num_channels=6; // number of channels (must be even) unsigned int m=4; // filter delay unsigned int num_symbols=4*m; // number of symbols // validate input if (num_channels%2) { fprintf(stderr,"error: %s, number of channels must be even\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // // ANALYSIS FILTERBANK // // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = 2*m*num_channels+1; float h[h_len]; #if RANDOM_COEFFICIENTS // testing: set filter coefficients to random values unsigned int s0 = 1; unsigned int p0 = 524287; // large prime number unsigned int g0 = 1031; // another large prime number for (i=0; i beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(h_len, 1.0f/(float)num_channels, 81.29528f, 0.0f, h); #endif // normalize float hsum = 0.0f; for (i=0; i beta = 8.00000 (6 channels, m=4) liquid_firdes_kaiser(f_len, 0.5f/(float)num_channels, 81.29528f, 0.0f, f); #endif // normalize float fsum = 0.0f; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "firpfbch_analysis_sync_test.m" // forward declaration of internal methods void firpfbch_crcf_analyzer_push(firpfbch_crcf _q, float complex _x); void firpfbch_crcf_analyzer_run(firpfbch_crcf _q, unsigned int _k, float complex * _X); int main() { // options unsigned int num_channels=4; // must be even number unsigned int num_symbols=12; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor unsigned int delay = 3; // initial sampling delay int ftype = LIQUID_FIRFILT_ARKAISER; // derived values unsigned int num_frames = num_symbols + 2*m; // compensate for filter delay unsigned int num_samples = num_channels * num_frames; // total number of samples // data arrays float complex x[num_samples]; float complex Y0[num_frames][num_channels]; float complex Y1[num_frames][num_channels]; // create analyzer objects firpfbch_crcf ca0 = firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, num_channels, m, beta, ftype); firpfbch_crcf ca1 = firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, num_channels, m, beta, ftype); unsigned int i; unsigned int j; // generate random input sequence for (i=0; i #include #include #include "liquid.internal.h" #define DEBUG 1 int main() { // options unsigned int num_channels=4; // number of channels unsigned int m=5; // filter delay unsigned int num_symbols=12; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i #include #include "liquid.internal.h" int main() { // options unsigned int num_channels=8; // number of channels unsigned int m=2; // filter delay float As=60; // stop-band attenuation [dB] unsigned int num_symbols=8; // number of symbols // create filterbank objects firpfbch ca0 = firpfbch_create(num_channels, m, As, 0, FIRPFBCH_NYQUIST, 0); firpfbch ca1 = firpfbch_create(num_channels, m, As, 0, FIRPFBCH_NYQUIST, 0); unsigned int i, j; float complex x[num_channels]; // time-domain input float complex y0[num_channels]; // channelized output float complex y1[num_channels]; // channelized output #if 0 // push samples channelizer 1 float complex x_hat; for (i=0; i #include #include #include "liquid.internal.h" #define DEBUG 1 int main() { // options unsigned int num_channels=4; // number of channels unsigned int m=3; // filter delay unsigned int num_symbols=5; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence unsigned int h_len = 2*m*num_channels; float h[h_len]; for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "fskcorr_test.m" int main(int argc, char*argv[]) { unsigned int M = 1024; // samples per symbol unsigned int n = 256; // sequence length (number of symbols) unsigned int p = 4; // over-sampling rate for output float SNRdB = -10.0f; // SNR (so to speak) float noise_floor = -60.0f; // noise floor [dB-Hz] unsigned int timer = 0; // correlator/FFT alignment float fc = 0.2f; // nominal tone frequency unsigned int i; unsigned int j; // derived values float nstd = powf(10.0f, noise_floor/20.0f); float gain = powf(10.0f, (SNRdB + noise_floor)/20.0f); unsigned int i1 = (unsigned int)round(fc*M); unsigned int i0 = M - i1; printf("M = %u, fc = %.3f {%u,%u}\n", M, fc, i0, i1); // generate sequence uint8_t seq[n]; for (i=0; i buf_1 // add noise for (j=0; j #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "fskmodem_test.m" // print usage/help message void usage() { printf("fskmodem_example -- frequency-shift keying test\n"); printf("options:\n"); printf(" h : print help\n"); printf(" m : bits/symbol, default: 1\n"); printf(" k : samples/symbol, default: 2*2^m\n"); printf(" b : signal bandwidth default: 0.2\n"); printf(" n : number of data symbols, default: 80\n"); printf(" s : SNR [dB], default: 40\n"); printf(" F : carrier frequency offset, default: 0\n"); printf(" P : carrier phase offset, default: 0\n"); printf(" T : fractional symbol offset, default: 0\n"); } int main(int argc, char*argv[]) { // options unsigned int m = 3; // number of bits/symbol unsigned int k = 0; // filter samples/symbol unsigned int num_symbols = 200; // number of data symbols float SNRdB = 40.0f; // signal-to-noise ratio [dB] float cfo = 0.0f; // carrier frequency offset float cpo = 0.0f; // carrier phase offset float tau = 0.0f; // fractional symbol timing offset float bandwidth = 0.20; // frequency spacing int dopt; while ((dopt = getopt(argc,argv,"hm:k:b:n:s:F:P:T:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'm': m = atoi(optarg); break; case 'k': k = atoi(optarg); break; case 'b': bandwidth = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'F': cfo = atof(optarg); break; case 'P': cpo = atof(optarg); break; case 'T': tau = atof(optarg); break; default: exit(1); } } printf("channel offsets: tau=%.3f, cfo=%.3f, cpo=%.3f\n", tau, cfo, cpo); unsigned int i; unsigned int j; // derived values if (k == 0) k = 2 << m; // set samples per symbol if not otherwise specified unsigned int num_samples = k*num_symbols; unsigned int M = 1 << m; float nstd = powf(10.0f, -SNRdB/20.0f); float M2 = 0.5f*(float)(M-1); // validate input if (k < M) { fprintf(stderr,"errors: %s, samples/symbol must be at least modulation size (M=%u)\n", __FILE__,M); exit(1); } else if (k > 2048) { fprintf(stderr,"errors: %s, samples/symbol exceeds maximum (2048)\n", __FILE__); exit(1); } else if (M > 1024) { fprintf(stderr,"errors: %s, modulation size (M=%u) exceeds maximum (1024)\n", __FILE__, M); exit(1); } else if (bandwidth <= 0.0f || bandwidth >= 0.5f) { fprintf(stderr,"errors: %s, bandwidth must be in (0,0.5)\n", __FILE__); exit(1); } // compute demodulation FFT size such that FFT output bin frequencies are // as close to modulated frequencies as possible unsigned int K = 0; // demodulation FFT size float df = bandwidth / M2; // frequency spacing float err_min = 1e9f; unsigned int K_min = k; // minimum FFT size unsigned int K_max = k*4 < 16 ? 16 : k*4; // maximum FFT size unsigned int K_hat; for (K_hat=K_min; K_hat<=K_max; K_hat++) { // compute candidate FFT size float v = 0.5f*df * (float)K_hat; // bin spacing float err = fabsf( roundf(v) - v ); // fractional bin spacing // print results printf(" K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : ""); // save best result if (K_hat==K_min || err < err_min) { K = K_hat; err_min = err; } // perfect match; no need to continue searching if (err < 1e-6f) break; } // arrays unsigned int sym_in[num_symbols]; // input symbols float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal unsigned int sym_out[num_symbols]; // output symbols // determine demodulation mapping between tones and frequency bins // TODO: use gray coding unsigned int demod_map[M]; for (i=0; i vmax) { s_opt = s; vmax =v; } } // save best result sym_out[j++] = s_opt; } } // destroy fft object fft_destroy_plan(fft); #endif // count errors unsigned int num_symbol_errors = 0; for (i=0; i 10) num_symbols = 10; num_samples = k*num_symbols; FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"M = %u;\n", M); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskmodem_coherent_test.m" // print usage/help message void usage() { printf("gmskmodem_coherent_test -- coherent GMSK demodulation example\n"); printf("options:\n"); printf(" h : print help\n"); printf(" k : samples/symbol, default: 8\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter roll-off, default: 0.3\n"); printf(" n : number of data symbols, default: 80\n"); printf(" s : SNR [dB], default: 40\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 8; // filter samples/symbol unsigned int m = 3; // filter delay (symbols) float beta = 0.25f; // GMSK bandwidth-time factor unsigned int num_symbols = 80; // number of data symbols float SNRdB = 40.0f; // signal-to-noise ratio [dB] int dopt; while ((dopt = getopt(argc,argv,"hk:m:b:n:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_samples = k*num_symbols; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned int sym_in [num_symbols]; // input symbols float complex x [num_samples]; // transmitted signal float complex y [num_samples]; // received signal float complex z [num_samples]; // received signal // create modem objects gmskmod mod = gmskmod_create(k, m, beta); // generate message signal for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskmodem_equalizer_test.m" int main(int argc, char*argv[]) { // options unsigned int k = 4; // filter samples/symbol float beta = 0.3f; // bandwidth-time product unsigned int p = 3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.50f; // learning rate unsigned int num_symbols = 240000;// number of symbols to simulate unsigned int nfft = 1200;// number of symbols to simulate // create modulator gmskmod mod = gmskmod_create(k, 3, beta); // add half-sample delay filter unsigned int i; float fc = 0.4f; #if 0 unsigned int m=12; float h[2*m]; for (i=0; i<2*m; i++) { float t = (float)i - (float)m + 0.5f; h[i] = sincf(2*fc*t); printf("h(%2u) = %12.8f;\n", i+1, h[i]); } firfilt_crcf filt = firfilt_crcf_create(h,2*m); #else firfilt_crcf filt = firfilt_crcf_create_kaiser(17, fc, 60.0f, 0.5f); #endif firfilt_crcf_set_scale(filt, 2*fc); // create equalizer eqlms_cccf eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, k, p, beta, 0.0f); eqlms_cccf_set_bw(eq, mu); // window for saving last few symbols unsigned int buf_len = 800; // buffer size windowcf sym_buf = windowcf_create(buf_len); // create spectral periodogram spgramcf q = spgramcf_create_default(nfft); // write results to output file FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"psd = zeros(1,nfft);\n"); float complex buf[k]; for (i=0; i 0 ? 1 : -1) * M_SQRT1_2 + (cimagf(d_hat) > 0 ? 1 : -1) * M_SQRT1_2 * _Complex_I; eqlms_cccf_step(eq, d_prime, d_hat); // reduce learning rate //mu *= 1.0f - 1e-5f; } printf("mu = %12.4e\n", mu); // get equalizer weights unsigned int hp_len = 2*k*p+1; // equalizer filter length float complex hp[hp_len]; // equalizer filter coefficients eqlms_cccf_copy_coefficients(eq, hp); fprintf(fid,"hp = zeros(1,%u);\n", hp_len); for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskmodem_psd_filter_compare_test.m" int main(int argc, char*argv[]) { // options unsigned int k = 2; // filter samples/symbol unsigned int m = 3; // filter delay [symbols] float beta = 0.3f; // bandwidth-time product unsigned int num_symbols = 5000000;// number of symbols to simulate unsigned int nfft = 1200;// fft size // create modulator gmskmod mod = gmskmod_create(k, m, beta); // create spectral periodogram spgramcf q = spgramcf_create_default(nfft); float complex buf[k]; unsigned int i; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "gmskmodem_test.m" // print usage/help message void usage() { printf("gmskmodem_test -- Gaussian minimum-shift keying modem example\n"); printf("options (default values in <>):\n"); printf(" u/h : print usage/help\n"); printf(" k : samples/symbol <4>\n"); printf(" m : filter delay [symbols], <3>\n"); printf(" n : number of data symbols <32>\n"); printf(" b : bandwidth-time product, 0 <= b <= 1, <0.3>\n"); printf(" s : SNR [dB] <30>\n"); } int main(int argc, char*argv[]) { // options unsigned int k=4; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.5f; // bandwidth-time product unsigned int num_data_symbols = 32; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:s:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 'b': BT = atof(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (BT <= 0.0f || BT >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_data_symbols + 2*m; unsigned int num_samples = k*num_symbols; unsigned int h_len = 2*k*m+1; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned char sym_in[num_symbols]; // input symbols float phi[num_samples]; // transmitted phase float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float phi_hat[num_samples]; // received phase float phi_prime[num_samples]; // matched-filter output unsigned char sym_out[num_symbols]; // output symbols // create transmit/receive interpolator/decimator #if 0 float ht[h_len]; // transmit filter coefficients liquid_firdes_gmsktx(k,m,BT,0.0f,ht); firfilt_rrrf ft = firfilt_rrrf_create(ht,h_len); #else firinterp_rrrf interp_tx = firinterp_rrrf_create_prototype(LIQUID_FIRFILT_GMSKTX,k,m,BT,0); #endif float hr[h_len]; // receive filter coefficients liquid_firdes_gmskrx(k,m,BT,0.0f,hr); firfilt_rrrf decim_rx = firfilt_rrrf_create(hr,h_len); // generate symbols and interpolate float theta = 0.0f; float k_inv = 1.0f / (float)k; for (i=0; i 0.0f ? 1 : 0; printf("%3u : %12.8f (%1u)", n, phi_prime[i], sym_out[n]); if (n >= 2*m) printf(" (%1u)\n", sym_in[n-2*m]); else printf("\n"); n++; } } // compute number of errors unsigned int num_errors = 0; for (i=0; i #include #include #include #include "liquid.h" #define DEBUG 1 int main() { unsigned int i; unsigned int j; unsigned int k; #if 0 // problem definition float A[40] = { 22, 10, 2, 3, 7, 14, 7, 10, 0, 8, -1, 13, -1, -11, 3, -3, -2, 13, -2, 4, 9, 8, 1, -2, 4, 9, 1, -7, 5, -1, 2, -6, 6, 5, 1, 4, 5, 0, -2, 2}; unsigned int m = 8; unsigned int n = 5; #else unsigned int m=8; unsigned int n=5; float A[m*n]; // make random matrix unsigned int t; for (t=0; tk float ck = 1.0 / (2*sk*a0_kk/fabs(a0_kk)*xk); // TODO : use copysign for (i=k+1; i m] float a1_kk1 = matrix_access(A1,m,n,k,k+1); betak = -tk * a1_kk1 / fabs(a1_kk1); // TODO : use copysign #if DEBUG printf(" tk : %12.8f\n", tk); printf(" betak : %12.8f\n", betak); printf(" A1[k,k+1] : %12.8f\n", a1_kk1); #endif // TODO : check dimension size if ( (k+1)==n ) { fprintf(stderr,"warning: maximum dimension exceeded\n"); // copy and exit memmove(A0, A1, m*n*sizeof(float)); break; } if (tk == 0) { for (j=0; j m] float yk1 = (tk == 0) ? 0.0 : sqrt( 0.5*(1 + fabs(a1_kk1)/tk) ); yj[k+1] = yk1; // compute y_j(k) for j > k+1 float dk = 1.0 / (2*tk*a1_kk1/fabs(a1_kk1)*yk1); #if DEBUG printf("dk : %12.8f\n", dk); #endif for (j=k+2; j #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdes_gradsearch_test.m" #define DEBUG 0 // highly compressed linear activation function (like tanh but // hugs lower bound between y=x and y=1 much more closely) float activation(float _x) { float p=4.0f; return copysign(powf(tanhf(powf(fabsf(_x),p)),1./p),_x); } typedef struct gs_s * gs; struct gs_s { unsigned int n, L, r, nsos; // filter order, etc. unsigned int vlen; // search vector length float complex * zd, * pd; // digital zeros/poles [size: L x 1] float kd, z0, p0; // gain, additional zero/pole for odd-length order float * A, * B; // second-order sections, [size: L+r x 3] // fft object, buffers // design parameters unsigned int nfft; // float * H; // frequency response float fp, fs; // pass and stop bands float utility; // utility value }; gs gs_create (unsigned int _order); void gs_destroy (gs _q); void gs_unpack (gs _q, float * _v, int _debug); void gs_expand (gs _q, int _debug); float gs_evaluate(gs _q, int _debug); void gs_print (gs _q, int _debug); float gs_callback(void * _q, float * _v, unsigned int _n); int main() { srand(time(NULL)); gs q = gs_create(2); unsigned int n = q->vlen; float v[n]; // search vector unsigned int i; for (i=0; infft); fprintf(fid,"f = 0.5*[0:(nfft-1)]/nfft;\n"); for (i=0; infft; i++) fprintf(fid,"H(%4u) = %16.8e;\n", i+1, q->H[i]); // plot utility over time fprintf(fid,"figure;\n"); fprintf(fid,"semilogy(u,'-x');\n"); fprintf(fid,"xlabel('iteration');\n"); fprintf(fid,"ylabel('utility');\n"); fprintf(fid,"title('gradient search results');\n"); fprintf(fid,"grid on;\n"); // plot frequency response fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,20*log10(H));\n"); fprintf(fid,"xlabel('Normalized Frequency');\n"); fprintf(fid,"ylabel('PSD [dB[');\n"); fprintf(fid,"grid on;\n"); fclose(fid); printf("results written to %s.\n", OUTPUT_FILENAME); gs_print(q,1); gradsearch_destroy(gs); gs_destroy(q); return 0; } gs gs_create(unsigned int _order) { gs q = (gs) malloc(sizeof(struct gs_s)); q->n = _order; q->r = (q->n) % 2; q->L = (q->n - q->r)/2; q->vlen = 4*q->L + 2*q->r + 1; // optimum vector length q->nsos = q->L + q->r; q->nfft = 1024; q->zd = (float complex*)malloc(q->n*sizeof(float complex)); q->pd = (float complex*)malloc(q->n*sizeof(float complex)); q->B = (float *)malloc(3*q->nsos*sizeof(float)); q->A = (float *)malloc(3*q->nsos*sizeof(float)); q->H = (float *)malloc(q->nfft*sizeof(float)); q->fp = 0.2f; q->fs = 0.3f; return q; } void gs_destroy(gs _q) { // free allocated memory free(_q->zd); free(_q->pd); free(_q->B); free(_q->A); free(_q->H); free(_q); } // unpack poles, zeros, and gain // format: [{z-mag, z-phase, p-mag, p-phase}*L, k, {z-real, p-real}*r] void gs_unpack(gs _q, float * _v, int _debug) { unsigned int i; float x, y, r, t; for (i=0; i<_q->L; i++) { x = _v[4*i+0]; y = _v[4*i+1]; r = activation(sqrtf(x*x+y*y)); t = atan2f(y,x); _q->zd[2*i+0] = r * cexpf(-_Complex_I*t); _q->zd[2*i+1] = r * cexpf(+_Complex_I*t); x = _v[4*i+2]; y = _v[4*i+3]; r = activation(sqrtf(x*x+y*y)); t = atan2f(y,x); _q->pd[2*i+0] = r * cexpf(-_Complex_I*t); _q->pd[2*i+1] = r * cexpf(+_Complex_I*t); } // unpack real-valued zero/pole if (_q->r) { _q->zd[2*_q->L] = tanhf(_v[4*_q->L ]); _q->pd[2*_q->L] = tanhf(_v[4*_q->L+1]); } _q->kd = _v[4*_q->L + 2*_q->r]; // unpack gain // debug: print values if (_debug) { printf("gs_unpack:\n"); printf("v : ["); for (i=0; i<_q->vlen; i++) printf("%8.5f,", _v[i]); printf("]\n"); gs_print(_q, _debug); } } // expand second-order sections void gs_expand(gs _q, int _debug) { // convert complex digital poles/zeros/gain into second- // order sections form iirdes_dzpk2sosf(_q->zd,_q->pd,_q->n,_q->kd,_q->B,_q->A); // print coefficients if (_debug) { unsigned int i; printf("B [%u x 3] :\n", _q->L+_q->r); for (i=0; i<_q->L+_q->r; i++) printf(" %12.8f %12.8f %12.8f\n", _q->B[3*i+0], _q->B[3*i+1], _q->B[3*i+2]); printf("A [%u x 3] :\n", _q->L+_q->r); for (i=0; i<_q->L+_q->r; i++) printf(" %12.8f %12.8f %12.8f\n", _q->A[3*i+0], _q->A[3*i+1], _q->A[3*i+2]); } } float gs_evaluate(gs _q, int _debug) { float u = 0.0f; unsigned int n; for (n=0; n<_q->nfft; n++) { float f = 0.5f * (float)n / (float)_q->nfft; float D = 0.0f; float W = 1.0f; if (f < _q->fp) { // pass band D = 1.0f; W = 1.0f; } else if (f > _q->fs) { // stop band D = 0.0f; W = 1.0f; } else { // transition band (don't care) D = 0.0f; W = 0.0f; } // compute 3-point DFT for each second-order section float complex H = 1.0f; unsigned int i; for (i=0; i<_q->nsos; i++) { float complex Hb = _q->B[3*i+0] * cexpf(_Complex_I*2*M_PI*f*0) + _q->B[3*i+1] * cexpf(_Complex_I*2*M_PI*f*1) + _q->B[3*i+2] * cexpf(_Complex_I*2*M_PI*f*2); float complex Ha = _q->A[3*i+0] * cexpf(_Complex_I*2*M_PI*f*0) + _q->A[3*i+1] * cexpf(_Complex_I*2*M_PI*f*1) + _q->A[3*i+2] * cexpf(_Complex_I*2*M_PI*f*2); // consolidate H *= Hb / Ha; } // compare to ideal float H_abs = crealf(H)*crealf(H) + cimagf(H)*cimagf(H); float e = W * (D-H_abs)*(D-H_abs); if (_debug) printf(" %5u %8.6f %5.3f %16.13f %16.13f\n", n, f, D, H_abs, e); u += e*e; _q->H[n] = H_abs; // save response } //u /= (float)(_q->nfft); if (_debug) printf("u = %12.8f\n", u); _q->utility = u; return _q->utility; } void gs_print(gs _q, int _debug) { // print digital z/p/k unsigned int i; printf("zeros (digital):\n"); for (i=0; i<_q->n; i++) printf(" zd[%3u] = %12.4e + j*%12.4e;\n", i, crealf(_q->zd[i]), cimagf(_q->zd[i])); printf("poles (digital):\n"); for (i=0; i<_q->n; i++) printf(" pd[%3u] = %12.4e + j*%12.4e;\n", i, crealf(_q->pd[i]), cimagf(_q->pd[i])); printf("gain (digital):\n"); printf(" kd : %12.8f + j*%12.8f\n", crealf(_q->kd), cimagf(_q->kd)); // print response... printf(" u : %12.8f\n", _q->utility); gs_evaluate(_q, 1); } // gradient search error float gs_callback(void * _context, float * _v, unsigned int _n) { gs _q = (gs)_context; if (_n != _q->vlen) { fprintf(stderr,"search vector length mismatch\n"); exit(1); } gs_unpack(_q, _v, DEBUG); gs_expand(_q, DEBUG); return gs_evaluate(_q, DEBUG); } #if 0 make examples/iirdes_example && ./examples/iirdes_example -t ellip -n 2 -o sos -f 0.25 B [1 x 3] : 0.30749798 0.61379653 0.30749798 A [1 x 3] : 1.00000000 0.06440119 0.31432679 results written to iirdes_example.m. done. make examples/iirdes_example && ./examples/iirdes_example -t ellip -n 2 -o tf -f 0.25 a[ 0] = 1.00000000; a[ 1] = 0.06440119; a[ 2] = 0.31432679; b[ 0] = 0.30749798; b[ 1] = 0.61379653; b[ 2] = 0.30749798; results written to iirdes_example.m. done. a = [1.00000000 0.06440119 0.31432679]; b = [0.30749798 0.61379653 0.30749798]; roots(a) - poles -0.03220 + 0.55972i -0.03220 - 0.55972i roots(b) - zeros -0.99805 + 0.06242i -0.99805 - 0.06242i #endif liquid-dsp-1.7.0/sandbox/iirdes_test.c000066400000000000000000000345471474751757600177560ustar00rootroot00000000000000// iirdes_example.c // // Tests infinite impulse response (IIR) filter design. // #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirdes_test.m" // print usage/help message void usage() { printf("iirdes_example -- infinite impulse response filter design\n"); printf("options (default values in []):\n"); printf(" -h : print usage/help\n"); printf(" -t : filter type: [butter], cheby1, cheby2, ellip, bessel\n"); printf(" -b : filter transformation: [LP], HP, BP, BS\n"); printf(" -n : filter order, n > 0 [5]\n"); printf(" -r : passband ripple in dB (cheby1, ellip), r > 0 [1.0]\n"); printf(" -s : stopband attenuation in dB (cheby2, ellip), s > 0 [60.0]\n"); printf(" -f : passband cut-off, 0 < f < 0.5 [0.2]\n"); printf(" -c : center frequency (BP, BS cases), 0 < c < 0.5 [0.25]\n"); printf(" -o : format [sos], tf\n"); printf(" sos - second-order sections form\n"); printf(" tf - regular transfer function form (potentially\n"); printf(" unstable for large orders\n"); } int main(int argc, char*argv[]) { // options unsigned int n=5; // filter order float fc = 0.20f; // cutoff frequency (low-pass prototype) float f0 = 0.25f; // center frequency (band-pass, band-stop) float As = 60.0f; // stopband attenuation [dB] float ripple = 1.0f; // passband ripple [dB] // filter type liquid_iirdes_filtertype ftype = LIQUID_IIRDES_BUTTER; // band type liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; // output format: second-order sections or transfer function liquid_iirdes_format format = LIQUID_IIRDES_SOS; int dopt; while ((dopt = getopt(argc,argv,"uht:b:n:r:s:f:c:o:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"butter")==0) { ftype = LIQUID_IIRDES_BUTTER; } else if (strcmp(optarg,"cheby1")==0) { ftype = LIQUID_IIRDES_CHEBY1; } else if (strcmp(optarg,"cheby2")==0) { ftype = LIQUID_IIRDES_CHEBY2; } else if (strcmp(optarg,"ellip")==0) { ftype = LIQUID_IIRDES_ELLIP; } else if (strcmp(optarg,"bessel")==0) { ftype = LIQUID_IIRDES_BESSEL; } else { fprintf(stderr,"error: iirdes_example, unknown filter type \"%s\"\n", optarg); usage(); exit(1); } break; case 'b': if (strcmp(optarg,"LP")==0) { btype = LIQUID_IIRDES_LOWPASS; } else if (strcmp(optarg,"HP")==0) { btype = LIQUID_IIRDES_HIGHPASS; } else if (strcmp(optarg,"BP")==0) { btype = LIQUID_IIRDES_BANDPASS; } else if (strcmp(optarg,"BS")==0) { btype = LIQUID_IIRDES_BANDSTOP; } else { fprintf(stderr,"error: iirdes_example, unknown band type \"%s\"\n", optarg); usage(); exit(1); } break; case 'n': n = atoi(optarg); break; case 'r': ripple = atof(optarg); break; case 's': As = atof(optarg); break; case 'f': fc = atof(optarg); break; case 'c': f0 = atof(optarg); break; case 'o': if (strcmp(optarg,"sos")==0) { format = LIQUID_IIRDES_SOS; } else if (strcmp(optarg,"tf")==0) { format = LIQUID_IIRDES_TF; } else { fprintf(stderr,"error: iirdes_example, unknown output format \"%s\"\n", optarg); usage(); exit(1); } break; default: exit(1); } } // validate input if (fc <= 0 || fc >= 0.5) { fprintf(stderr,"error: %s, cutoff frequency out of range\n", argv[0]); usage(); exit(1); } else if (f0 < 0 || f0 > 0.5) { fprintf(stderr,"error: %s, center frequency out of range\n", argv[0]); usage(); exit(1); } else if (ripple <= 0) { fprintf(stderr,"error: %s, pass-band ripple out of range\n", argv[0]); usage(); exit(1); } else if (As <= 0) { fprintf(stderr,"error: %s, stop-band ripple out of range\n", argv[0]); usage(); exit(1); } // number of analog poles/zeros unsigned int npa = n; unsigned int nza; // analog poles/zeros/gain float complex pa[n]; float complex za[n]; float complex ka; float complex k0; unsigned int r = n%2; unsigned int L = (n-r)/2; unsigned int i; // specific filter variables float epsilon, Gp, Gs, ep, es; switch (ftype) { case LIQUID_IIRDES_BUTTER: printf("Butterworth filter design:\n"); nza = 0; k0 = 1.0f; butter_azpkf(n,za,pa,&ka); break; case LIQUID_IIRDES_CHEBY1: printf("Cheby-I filter design:\n"); nza = 0; epsilon = sqrtf( powf(10.0f, ripple / 10.0f) - 1.0f ); k0 = r ? 1.0f : 1.0f / sqrtf(1.0f + epsilon*epsilon); cheby1_azpkf(n,epsilon,za,pa,&ka); break; case LIQUID_IIRDES_CHEBY2: printf("Cheby-II filter design:\n"); nza = 2*L; epsilon = powf(10.0f, -As/20.0f); k0 = 1.0f; cheby2_azpkf(n,epsilon,za,pa,&ka); break; case LIQUID_IIRDES_ELLIP: printf("elliptic filter design:\n"); nza = 2*L; Gp = powf(10.0f, -ripple / 20.0f); Gs = powf(10.0f, -As / 20.0f); printf(" Gp = %12.8f\n", Gp); printf(" Gs = %12.8f\n", Gs); // epsilon values ep = sqrtf(1.0f/(Gp*Gp) - 1.0f); es = sqrtf(1.0f/(Gs*Gs) - 1.0f); k0 = r ? 1.0f : 1.0f / sqrtf(1.0f + ep*ep); ellip_azpkf(n,ep,es,za,pa,&ka); break; case LIQUID_IIRDES_BESSEL: printf("Bessel filter design:\n"); bessel_azpkf(n,za,pa,&ka); k0 = 1.0f; nza = 0; break; default: fprintf(stderr,"error: iirdes_example: unknown filter type\n"); exit(1); } printf("poles (analog):\n"); for (i=0; i 2*n r = 0; L = n; n = 2*n; } fprintf(fid,"n=%u;\n", n); fprintf(fid,"r=%u;\n", r); fprintf(fid,"L=%u;\n", L); fprintf(fid,"nfft=1024;\n"); // print digital z/p/k fprintf(fid,"zd = zeros(1,n);\n"); fprintf(fid,"pd = zeros(1,n);\n"); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "iirfilt_intdiff_test.m" int main(int argc, char*argv[]) { // options unsigned int num_samples = 801; // // integrator digital zeros/poles/gain, [Pintelon:1990] Table II // // zeros, digital, integrator float complex zdi[8] = { 1.175839 * -1.0f, 3.371020 * cexpf(_Complex_I * M_PI / 180.0f * -125.1125f), 3.371020 * cexpf(_Complex_I * M_PI / 180.0f * 125.1125f), 4.549710 * cexpf(_Complex_I * M_PI / 180.0f * -80.96404f), 4.549710 * cexpf(_Complex_I * M_PI / 180.0f * 80.96404f), 5.223966 * cexpf(_Complex_I * M_PI / 180.0f * -40.09347f), 5.223966 * cexpf(_Complex_I * M_PI / 180.0f * 40.09347f), 5.443743,}; // poles, digital, integrator float complex pdi[8] = { 0.5805235f * -1.0f, 0.2332021f * cexpf(_Complex_I * M_PI / 180.0f * -114.0968f), 0.2332021f * cexpf(_Complex_I * M_PI / 180.0f * 114.0968f), 0.1814755f * cexpf(_Complex_I * M_PI / 180.0f * -66.33969f), 0.1814755f * cexpf(_Complex_I * M_PI / 180.0f * 66.33969f), 0.1641457f * cexpf(_Complex_I * M_PI / 180.0f * -21.89539f), 0.1641457f * cexpf(_Complex_I * M_PI / 180.0f * 21.89539f), 1.0f,}; // gain, digital, integrator float complex kdi = -1.89213380759321e-05f; #if 1 // second-order sections // allocate 12 values for 4 second-order sections each with // 2 roots (order 8), e.g. (1 + r0 z^-1)(1 + r1 z^-1) float Bi[12]; float Ai[12]; iirdes_dzpk2sosf(zdi, pdi, 8, kdi, Bi, Ai); // create integrator iirfilt_crcf integrator = iirfilt_crcf_create_sos(Bi,Ai,4); #else // regular transfer function form // 9 = order + 1 float bi[9]; float ai[9]; iirdes_dzpk2tff(zdi, pdi, 8, kdi, bi, ai); iirfilt_crcf integrator = iirfilt_crcf_create(bi,9,ai,9); #endif // // differentiator digital zeros/poles/gain, [Pintelon:1990] Table IV // // zeros, digital, differentiator float complex zdd[8] = { 1.702575f * -1.0f, 5.877385f * cexpf(_Complex_I * M_PI / 180.0f * -221.4063f), 5.877385f * cexpf(_Complex_I * M_PI / 180.0f * 221.4063f), 4.197421f * cexpf(_Complex_I * M_PI / 180.0f * -144.5972f), 4.197421f * cexpf(_Complex_I * M_PI / 180.0f * 144.5972f), 5.350284f * cexpf(_Complex_I * M_PI / 180.0f * -66.88802f), 5.350284f * cexpf(_Complex_I * M_PI / 180.0f * 66.88802f), 1.0f,}; // poles, digital, differentiator float complex pdd[8] = { 0.8476936f * -1.0f, 0.2990781f * cexpf(_Complex_I * M_PI / 180.0f * -125.5188f), 0.2990781f * cexpf(_Complex_I * M_PI / 180.0f * 125.5188f), 0.2232427f * cexpf(_Complex_I * M_PI / 180.0f * -81.52326f), 0.2232427f * cexpf(_Complex_I * M_PI / 180.0f * 81.52326f), 0.1958670f * cexpf(_Complex_I * M_PI / 180.0f * -40.51510f), 0.1958670f * cexpf(_Complex_I * M_PI / 180.0f * 40.51510f), 0.1886088f,}; // gain, digital, differentiator float complex kdd = 2.09049284907492e-05f; #if 1 // second-order sections // allocate 12 values for 4 second-order sections each with // 2 roots (order 8), e.g. (1 + r0 z^-1)(1 + r1 z^-1) float Bd[12]; float Ad[12]; iirdes_dzpk2sosf(zdd, pdd, 8, kdd, Bd, Ad); // create differentiator iirfilt_crcf differentiator = iirfilt_crcf_create_sos(Bd,Ad,4); #else // regular transfer function form // 9 = order + 1 float bd[9]; float ad[9]; iirdes_dzpk2tff(zdd, pdd, 8, kdd, bd, ad); iirfilt_crcf differentiator = iirfilt_crcf_create(bd,9,ad,9); #endif // allocate arrays float complex x[num_samples]; float complex y[num_samples]; float complex z[num_samples]; float tmin = 0.0f; float tmax = 1.0f; float dt = (tmax-tmin)/(float)(num_samples-1); unsigned int i; for (i=0; i #include #include #include #include "liquid.internal.h" int main() { unsigned int p=10; // derived values float r[p+1]; float a_matrixinv[p+1]; float a_levinson[p+1]; unsigned int i; unsigned int j; for (i=0; ij) ? (i-j) : (j-i)]; // abs(i-j) } // invert matrix (using Gauss-Jordan elimination) matrixf_inv(R,p,p); float rt[p]; float a_hat[p]; for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "matched_filter_cfo_test.m" // print usage/help message void usage() { printf("matched_filter_cfo_test options:\n"); printf(" u/h : print usage/help\n"); printf(" t : filter type: [rrcos], rkaiser, arkaiser, hM3\n"); printf(" k : filter samples/symbol, k >= 2, default: 2\n"); printf(" m : filter delay (symbols), m >= 1, default: 3\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.5\n"); printf(" n : number of symbols, default: 16\n"); printf(" P : carrier phase offset, default: 0\n"); printf(" F : carrier frequency offset, default: 0.8\n"); printf(" c : compensate for carrier frequency offset in matched filter? default: no\n"); } int main(int argc, char*argv[]) { // options unsigned int k=2; // samples/symbol unsigned int m=4; // symbol delay float beta=0.3f; // excess bandwidth factor float phi = 0.0f; // carrier phase offset float dphi = 0.8f; // carrier frequency offset unsigned int num_symbols=128; int cfo_compensation=0; // compensate for carrier offset in matched filter? enum { FILTER_RRCOS=0, FILTER_RKAISER, FILTER_ARKAISER, FILTER_hM3 } ftype = 0; // filter prototype int dopt; while ((dopt = getopt(argc,argv,"uht:k:m:b:n:P:F:c")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 't': if (strcmp(optarg,"rrcos")==0) { ftype = FILTER_RRCOS; } else if (strcmp(optarg,"rkaiser")==0) { ftype = FILTER_RKAISER; } else if (strcmp(optarg,"arkaiser")==0) { ftype = FILTER_ARKAISER; } else if (strcmp(optarg,"hM3")==0) { ftype = FILTER_hM3; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 'P': phi = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'c': cfo_compensation=1; break; default: exit(1); } } if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } // initialize objects unsigned int h_len = 2*k*m+1; float h[h_len]; switch (ftype) { case FILTER_RRCOS: liquid_firdes_rrcos(k,m,beta,0,h); break; case FILTER_RKAISER: liquid_firdes_rkaiser(k,m,beta,0,h); break; case FILTER_ARKAISER: liquid_firdes_arkaiser(k,m,beta,0,h); break; case FILTER_hM3: liquid_firdes_hM3(k,m,beta,0,h); break; default: // should never get to this point fprintf(stderr,"error: %s, invalid filter type\n", argv[0]); exit(1); } // derived values unsigned int num_samples = num_symbols*k; // generate receive filter coefficients (reverse of transmit) float complex gc[h_len]; unsigned int i; for (i=0; i=2*m) printf(" *\n"); else printf("\n"); #endif } // clean up objects firinterp_crcf_destroy(interp); firdecim_cccf_destroy(decim); FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %12.8f;\n", beta); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = k*num_symbols;\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "matched_filter_test.m" // print usage/help message void usage() { printf("matched_filter_test options:\n"); printf(" u/h : print usage/help\n"); printf(" k : filter samples/symbol, k >= 2, default: 4\n"); printf(" m : filter delay (symbols), m >= 1, default: 2\n"); printf(" b : filter excess bandwidth factor, 0 < b < 1, default: 0.9\n"); } int main(int argc, char*argv[]) { // options unsigned int k=4; // samples/symbol unsigned int m=2; // symbol delay float beta=0.9f; // excess bandwidth factor int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; default: exit(1); } } if (k < 2) { fprintf(stderr,"error: %s, k must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s, m must be at least 1\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, beta must be in (0,1)\n", argv[0]); exit(1); } // design filter unsigned int h_len = 2*k*m+1; float h[h_len]; liquid_firdes_rrcos(k,m,beta,0,h); // truncate filter to be of length 2*k*m unsigned int g_len = 2*k*m; // generate receive filter coefficients (reverse of transmit) float g[g_len]; unsigned int i; for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_cacosf(float complex _z) { // return based on quadrant int sign_i = crealf(_z) > 0; int sign_q = cimagf(_z) > 0; if (sign_i == sign_q) { return - _Complex_I*clogf(_z + csqrtf(_z*_z - 1.0f)); } else { return - _Complex_I*clogf(_z - csqrtf(_z*_z - 1.0f)); } // should never get to this state return 0.0f; } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number items per line // data arrays float complex z[n]; float complex test[n]; float complex err_max = 0.0f; unsigned int i; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_cacosf(float complex _z) { // return based on quadrant int sign_i = crealf(_z) > 0; int sign_q = cimagf(_z) > 0; if (sign_i == sign_q) { return - _Complex_I*clogf(_z + csqrtf(_z*_z - 1.0f)); } else { return - _Complex_I*clogf(_z - csqrtf(_z*_z - 1.0f)); } // should never get to this state return 0.0f; } float complex sandbox_casinf(float complex _z) { return 0.5f*M_PI - sandbox_cacosf(_z); } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number items per line // data arrays float complex z[n]; float complex test[n]; float complex err_max = 0.0f; unsigned int i; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_catanf(float complex _z) { return 0.5f*_Complex_I*clogf( (1.0f-_Complex_I*_z)/(1.0f+_Complex_I*_z) ); } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number items per line // data arrays float complex z[n]; float complex test[n]; float complex err_max = 0.0f; unsigned int i; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_cexpf(float complex _z) { float r = expf( crealf(_z) ); float complex re = cosf( cimagf(_z) ); float complex im = sinf( cimagf(_z) ); return r*(re + _Complex_I*im); } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number items per line // data arrays float complex z[n]; float complex test[n]; unsigned int i; float complex err_max = 0.0f; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_clogf(float complex _z) { return logf(cabsf(_z)) + _Complex_I*cargf(_z); } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number items per line // data arrays float complex z[n]; float complex test[n]; unsigned int i; float complex err_max = 0.0f; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include #define sandbox_randf() ((float) rand() / (float) RAND_MAX) float complex sandbox_csqrtf(float complex _z) { float r = cabsf(_z); // magnitude of _z float a = crealf(_z); // real component of _z float re = sqrtf(0.5f*(r+a)); // real component of return value float im = sqrtf(0.5f*(r-a)); // imag component of return value // return value, retaining sign of imaginary component return cimagf(_z) > 0 ? re + _Complex_I*im : re - _Complex_I*im; } int main() { unsigned int n=32; // number of tests unsigned int d=2; // number of items per line // data arrays float complex z[n]; float complex test[n]; float complex err_max = 0.0f; unsigned int i; for (i=0; i cabsf(err_max) ) err_max = err; } printf("maximum error: %12.4e;\n", cabsf(err_max)); // // print autotest lines // printf("\n"); printf(" float complex z[%u] = {\n ", n); for (i=0; i #include #include #include "liquid.h" float z[41] = { 0.00100000, 0.00125890, 0.00158490, 0.00199530, 0.00251190, 0.00316230, 0.00398110, 0.00501190, 0.00630960, 0.00794330, 0.01000000, 0.01258900, 0.01584900, 0.01995300, 0.02511900, 0.03162300, 0.03981100, 0.05011900, 0.06309600, 0.07943300, 0.10000000, 0.12589000, 0.15849000, 0.19953000, 0.25119000, 0.31623000, 0.39811000, 0.50119000, 0.63096000, 0.79433000, 1.00000000, 1.25890000, 1.58490000, 1.99530000, 2.51190000, 3.16230000, 3.98110000, 5.01190000, 6.30960000, 7.94330000, 10.00000000}; float lngamma_test[41] = { 6.90720000, 6.67680000, 6.44630000, 6.21580000, 5.98530000, 5.75460000, 5.52390000, 5.29310000, 5.06210000, 4.83090000, 4.59950000, 4.36780000, 4.13570000, 3.90320000, 3.67010000, 3.43640000, 3.20190000, 2.96640000, 2.72990000, 2.49200000, 2.25270000, 2.01200000, 1.76980000, 1.52660000, 1.28300000, 1.04050000, 0.80154000, 0.57004000, 0.35224000, 0.15757000, 0.00000000, -0.10025000, -0.11440000, -0.00199580, 0.29308000, 0.84799000, 1.76800000, 3.19600000, 5.32420000, 8.41110000, 12.80200000}; float sandbox_lngammaf(float _z, float * _v) { float v0 = _v[0]; float v1 = _v[1]; // z = 10.^[-3:0.1:1]; // t0 = log(gamma(z)); // t1 = (1+z-0.5).*log(1+z) - (1+z) + 0.5*log(2*pi) - log(z) + 0.0405*(1-tanh(0.5*log(z))); // float g_hat = (0.5f+_z)*logf(1.0f+_z) - (1.0f+_z) + 0.5f*logf(2*M_PI) - logf(_z) + v0*(1.0f - tanhf(v1*logf(_z))); return g_hat; } // gradient search curve-fit error float gserror(void * _userdata, float * _v, unsigned int _n) { // compute error float rmse = 0.0f; unsigned int i; for (i=0; i<41; i++) { float g = sandbox_lngammaf(z[i], _v); float e = g - lngamma_test[i]; rmse += e*e; } return sqrtf(rmse / 41.0f); } int main() { unsigned int num_iterations = 1000; // number of iterations to run float v[2] = {0.0405f, 0.5f}; // gradsearch gs = gradsearch_create(NULL,v,2,gserror,LIQUID_OPTIM_MINIMIZE); // execute search one iteration at a time unsigned int i; float rmse; for (i=0; i #include #include "liquid.h" int main() { unsigned int num_iterations=8; #if 0 unsigned int n=4; float A[16] = { 1,2,3,4, 5,5,7,8, 6,4,8,7, 1,0,3,1}; #else unsigned int n=3; float A[9] = { 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 1.0f, 2.0f}; #endif float eig[n]; float A0[n*n]; float Q[n*n], R[n*n]; memmove(A0, A, n*n*sizeof(float)); printf("\n"); printf("testing Q/R decomposition [Gram-Schmidt]\n"); matrixf_qrdecomp_gramschmidt(A,n,n,Q,R); //matrixf_print(Q,n,n); //matrixf_print(R,n,n); unsigned int k; for (k=0; k #include #include #include "liquid.h" int main() { float x[6] = { 1, 2, 3, 4, 5, 6}; float y[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9}; float z[6]; // compute z = x * y printf("z = x * y :\n"); matrixf_mul(x,2,3,y,3,3,z,2,3); matrixf_print(z,2,3); /* // compute z = y * x' matrixf_transpose(x); printf("x' : \n"); matrixf_print(x); matrixf_transpose(z); matrixf_multiply(y,x,z); printf("z = y * x' :\n"); matrixf_print(z); matrixf_destroy(x); matrixf_destroy(y); matrixf_destroy(z); */ float s[16] = { 1,2,3,4, 5,5,7,8, 6,4,8,7, 1,0,3,1}; float s_inv[16]; memmove(s_inv,s,16*sizeof(float)); matrixf_inv(s_inv,4,4); float i4[16]; matrixf_mul(s,4,4,s_inv,4,4,i4,4,4); printf("\ns:\n"); matrixf_print(s,4,4); printf("\ninv(s):\n"); matrixf_print(s_inv,4,4); printf("\ns*inv(s):\n"); matrixf_print(i4,4,4); printf("\n"); float det = matrixf_det(s,4,4); printf("det(s) = %12.8f\n", det); #if 0 // pivot test (matrix inversion) float t[32] = { 1,2,3,4, 1,0,0,0, 5,5,7,8, 0,1,0,0, 6,4,8,7, 0,0,1,0, 1,0,3,1, 0,0,0,1}; unsigned int i; for (i=0; i<4; i++) { matrixf_pivot(t,4,8,i,i); matrixf_print(t,4,8); } unsigned int j; for (i=0; i<4; i++) { float v = matrix_access(t,4,8,i,i); for (j=0; j<8; j++) matrix_access(t,4,8,i,j) /= v; } matrixf_print(t,4,8); #endif printf("\n"); printf("testing L/U decomposition [Crout's method]\n"); float L[16], U[16], P[16]; matrixf_ludecomp_crout(s,4,4,L,U,P); matrixf_print(L,4,4); matrixf_print(U,4,4); printf("\n"); printf("testing L/U decomposition [Doolittle's method]\n"); matrixf_ludecomp_doolittle(s,4,4,L,U,P); matrixf_print(L,4,4); matrixf_print(U,4,4); printf("\n\n"); float X[16] = { 0.84382, -2.38304, 1.43061, -1.66604, 3.99475, 0.88066, 4.69373, 0.44563, 7.28072, -2.06608, 0.67074, 9.80657, 6.07741, -3.93099, 1.22826, -0.42142}; float Y[16]; printf("\nX:\n"); matrixf_print(X,4,4); // swaprows memmove(Y,X,16*sizeof(float)); matrixf_swaprows(Y,4,4,0,2); printf("\nmatrixf_swaprows(X,4,4,0,2):\n"); matrixf_print(Y,4,4); // pivot test memmove(Y,X,16*sizeof(float)); matrixf_pivot(Y,4,4,1,2); printf("\nmatrixf_pivot(X,4,4,1,2):\n"); matrixf_print(Y,4,4); // inverse test memmove(Y,X,16*sizeof(float)); matrixf_inv(Y,4,4); printf("\nmatrixf_inv(X,4,4):\n"); matrixf_print(Y,4,4); // determinant test float D = matrixf_det(X,4,4); printf("\nmatrixf_det(X,4) = %12.8f\n", D); // L/U decomp (Crout's method) matrixf_ludecomp_crout(X,4,4,L,U,P); printf("\nmatrixf_ludecomp_crout(X,4,4,L,U,P)\n"); printf("L:\n"); matrixf_print(L,4,4); printf("U:\n"); matrixf_print(U,4,4); // L/U decomp (Doolittle's method) matrixf_ludecomp_doolittle(X,4,4,L,U,P); printf("\nmatrixf_ludecomp_doolittle(X,4,4,L,U,P)\n"); printf("L:\n"); matrixf_print(L,4,4); printf("U:\n"); matrixf_print(U,4,4); printf("\n"); printf("testing Q/R decomposition [Gram-Schmidt]\n"); float Q[16], R[16]; matrixf_qrdecomp_gramschmidt(X,4,4,Q,R); matrixf_print(Q,4,4); matrixf_print(R,4,4); /* float b[4] = { 0.91489, 0.71789, 1.06553, -0.81707}; */ float Xb[20] = { 0.84382, -2.38304, 1.43061, -1.66604, 0.91489, 3.99475, 0.88066, 4.69373, 0.44563, 0.71789, 7.28072, -2.06608, 0.67074, 9.80657, 1.06553, 6.07741, -3.93099, 1.22826, -0.42142, -0.81707}; printf("\n[X b] =\n"); matrixf_print(Xb,4,5); matrixf_gjelim(Xb,4,5); printf("\nmatrixf_gjelim(Xb,4,5)\n"); matrixf_print(Xb,4,5); // compute a*a' float a[20] = { -0.24655, -1.78843, 0.39477, 0.43735, -1.08998, -0.42751, 0.62496, 1.43802, 0.19814, 0.78155, -0.35658, -0.81875, -1.09984, 1.87006, -0.94191, 0.39553, -2.02036, 1.17393, 1.54591, 1.29663}; printf("\na =\n"); matrixf_print(a,4,5); printf("\n\n"); printf("computing a*a'\n"); float aaT[16]; matrixf_mul_transpose(a,4,5,aaT); matrixf_print(aaT,4,4); printf("\n\n"); printf("computing a'*a\n"); float aTa[25]; matrixf_transpose_mul(a,4,5,aTa); matrixf_print(aTa,5,5); printf("\n"); printf("testing Gram-Schmidt\n"); float Xgs[12] = { 1., 2., 1., 0., 2., 0., 2., 3., 1., 1., 1., 0.}; float Ugs[12]; float Ugs_test[12] = { sqrtf(6.)/6., sqrtf(2.)/6., 2./3., 0., 2.*sqrtf(2.)/3.,-1./3., sqrtf(6.)/3., 0., 0., sqrtf(6.)/6., -sqrtf(2.)/6., -2./3.}; matrixf_gramschmidt(Xgs,4,3,Ugs); printf("X:\n"); matrixf_print(Xgs,4,3); printf("normalized X:\n"); matrixf_print(Ugs,4,3); printf("expected:\n"); matrixf_print(Ugs_test,4,3); // // test Cholesky decomposition // printf("\n"); printf("testing Cholesky decomposition\n"); // generate input matrix float complex Lp[9] = { 1.0, 0.0, 0.0, -3.1 + 0.2*_Complex_I, 0.3, 0.0, 1.7 + 0.5*_Complex_I, -0.6 - 0.3*_Complex_I, 2.9}; float complex Ap[9]; matrixcf_mul_transpose(Lp, 3, 3, Ap); float complex Lc[9]; matrixcf_chol(Ap, 3, Lc); printf("Lp:\n"); matrixcf_print(Lp, 3, 3); printf("Ap:\n"); matrixcf_print(Ap, 3, 3); printf("Lc:\n"); matrixcf_print(Lc, 3, 3); printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/mdct_test.c000066400000000000000000000106241474751757600174140ustar00rootroot00000000000000// // mdct_example.c // // Modified discrete cosine transform (MDCT) example. Demonstrates // the functionality and interface for the mdct and imdct routines. // #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "mdct_example.m" int main() { // MDCT options unsigned int num_channels=64; // MDCT size unsigned int num_symbols=16; // filter options unsigned int h_len=21; // filter length float fc=0.01f; // filter cutoff float As=60.0f; // stop-band attenuation [dB] float mu=0.0f; // timing offset // derived values unsigned int i,j; unsigned int num_samples = num_channels*num_symbols; float x[num_samples]; float X[num_samples]; float y[num_samples]; for (i=0; i #include #include #include double function(double _x) { #if 0 // -sin(x) minimum at x = pi/2 double y = 1.0f-sin(_x); #else // exp(-(x-pi/2)^2) double t = _x - M_PI/2; double y = 1-exp(-t*t); #endif return y; } int main() { // options unsigned int num_iterations = 10; double x0; // lower value double x1 = 1.2f; // middle value (initial guess) double x2; // upper value double dx = 2.0f; // step size double gamma = 0.7f;// step size reduction double tol = 1e-6f; // error tolerance // choose x0, x2 x0 = x1 - dx; x2 = x1 + dx; // double y0, y1, y2; double x_hat; double del = 0.0f; unsigned int i; for (i=0; i x1); assert(x1 > x0); // compute minimum // TODO : exploit uniform spacing... double t0 = y0*(x1*x1 - x2*x2) + y1*(x2*x2 - x0*x0) + y2*(x0*x0 - x1*x1); double t1 = y0*(x1 - x2) + y1*(x2 - x0) + y2*(x0 - x1); x_hat = 0.5f * t0 / t1; del = x_hat - x1; // print printf("%4u : %12.8f, e=%12.4e, del: %12.4e\n", i, x_hat, x_hat-M_PI/2, del); // reduce step size dx *= gamma; // x0 = x_hat - dx; x2 = x_hat + dx; if (fabs(del) < tol) break; } printf("estimated minimum : %f (%f)\n", x_hat, M_PI/2); return 0; } liquid-dsp-1.7.0/sandbox/minsearch_test.c000066400000000000000000000035471474751757600204440ustar00rootroot00000000000000// // minsearch.c // // search to find minimum of a function using parabolic // interpolation // #include #include #include #include double function(double _x) { #if 0 // -sin(x) minimum at x = pi/2 double y = 1.0f-sin(_x); #else // exp(-(x-pi/2)^2) double t = _x - M_PI/2; double y = -exp(-t*t); #endif return y; } int main() { // options unsigned int num_iterations = 10; double x0 = 0.3f; // lower value double x1; // middle value (ignored) double x2 = 3.1f; // upper value double tol = 1e-6f; // error tolerance // double y0 = function(x0); double y1; double y2 = function(x2); double x_hat; double del = 0.0f; unsigned int i; for (i=0; i x1); assert(x1 > x0); // compute minimum double t0 = y0*(x1*x1 - x2*x2) + y1*(x2*x2 - x0*x0) + y2*(x0*x0 - x1*x1); double t1 = y0*(x1 - x2) + y1*(x2 - x0) + y2*(x0 - x1); x_hat = 0.5f * t0 / t1; del = x_hat - x1; // print printf("%4u : %12.8f, e=%12.4e\n", i, x_hat, x_hat-M_PI/2); if (x_hat > x1) { // new minimum x0 = x1; y0 = y1; } else { // new maximum x2 = x1; y2 = y1; } if (fabs(del) < tol) break; } printf("estimated minimum : %f (%f)\n", x_hat, M_PI/2); return 0; } liquid-dsp-1.7.0/sandbox/modem_demodulate_arb_gentab.c000066400000000000000000000242201474751757600230730ustar00rootroot00000000000000// Generate fast demodulation tables for arbitrary modems; use existing // modulation scheme with fast decoding (e.g. 16-QAM) and associate // these constellation points with the arbitrary constellation points. // The goal is to allow the demodulator to first demodulate the // received point using the fast demodulator and then perform a search // over only the set of nearby points. This script computes the look-up // table for these nearby points and stores them as an array of // indices. #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_demodulate_arb_gentab.m" #define DEBUG 0 // print usage/help message void usage() { printf("sandbox/modem_demodulate_arb_gentab [options]\n"); printf(" u/h : print usage\n"); printf(" m : input modulation scheme (arb64vt default)\n"); printf(" r : reference modulation scheme (qam16 default)\n"); liquid_print_modulation_schemes(); printf(" a : alpha (reference scheme gain), default: 1.0\n"); } // search for nearest constellation points to reference points void modemcf_arbref_search(float complex * _c, unsigned int _M, float complex * _cref, unsigned int _p, unsigned char * _index, unsigned int _s); // search for nearest constellation points to single reference point void modemcf_arbref_search_point(float complex * _c, unsigned int _M, float complex _cref, unsigned char * _index, unsigned int _s); // find unassigned constellation points unsigned int modemcf_arbref_search_unassigned(unsigned char * _index, unsigned int _M, unsigned int _p, unsigned int _s, unsigned char * _assigned); int main(int argc, char*argv[]) { // create mod/demod objects modulation_scheme ms = LIQUID_MODEM_ARB64VT; modulation_scheme mref = LIQUID_MODEM_QAM64; float alpha = 1.0f; int dopt; while ((dopt = getopt(argc,argv,"uhp:m:r:a:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; case 'r': mref = liquid_getopt_str2mod(optarg); if (mref == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported modulation scheme '%s'\n", argv[0], optarg); return 1; } break; case 'a': alpha = atof(optarg); break; default: exit(1); } } // validate input unsigned int i; unsigned int j; // initialize reference points modemcf qref = modemcf_create(mref); unsigned int kref = modemcf_get_bps(qref); unsigned int p = 1 << kref; float complex cref[p]; for (i=0; i 0); // print table printf("\n"); printf("unsigned char modemcf_demodulate_gentab[%u][%u] = {\n", p, s); for (i=0; i _M) { fprintf(stderr,"error: modemcf_arbref_search(), index size exceeds constellation size\n"); exit(1); } // unsigned int i; for (i=0; i<_p; i++) modemcf_arbref_search_point(_c, _M, _cref[i], &_index[_s*i], _s); } // search for nearest constellation points to single reference point void modemcf_arbref_search_point(float complex * _c, unsigned int _M, float complex _cref, unsigned char * _index, unsigned int _s) { #if DEBUG printf("searching neighbors to (%8.3f,%8.3f)\n", crealf(_cref), cimagf(_cref)); #endif // initialize array of selected element flags unsigned char selected[_M]; memset(selected, 0x00, _M); unsigned int i; unsigned int n; for (n=0; n<_s; n++) { int min_found = 0; float d; float dmin = 0.0f; unsigned int index_min = 0; for (i=0; i<_M; i++) { // ignore constellation point if it has already been // selected if (selected[i]==1) continue; // compute distance d = crealf( (_c[i]-_cref)*conjf(_c[i]-_cref) ); if ( d < dmin || !min_found ) { dmin = d; index_min = i; min_found = 1; } } // save minimum index _index[n] = index_min; // flag point as 'selected' selected[index_min] = 1; #if DEBUG printf("%6u (%8.3f,%8.3f)\n", index_min, crealf(_c[index_min]), cimagf(_c[index_min])); #endif } } // find unassigned constellation points unsigned int modemcf_arbref_search_unassigned(unsigned char * _index, unsigned int _M, unsigned int _p, unsigned int _s, unsigned char * _assigned) { unsigned int num_unassigned = 0; // unsigned int i; for (i=0; i<_M; i++) { // initialized 'assigned' flag to false _assigned[i] = 0; unsigned int j; for (j=0; j<_p; j++) { // see if this constellation point has been assigned // to this reference unsigned int k; for (k=0; k<_s; k++) { if (_index[j*_s+k] == i) _assigned[i] = 1; } } if (!_assigned[i]) num_unassigned++; } return num_unassigned; } liquid-dsp-1.7.0/sandbox/modem_demodulate_soft_gentab.c000066400000000000000000000271451474751757600233130ustar00rootroot00000000000000// Generate table of nearest symbols and tests soft demodulation #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_demodulate_soft_gentab.m" #define DEBUG 0 // print a string of bits to the standard output void print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } // soft demodulation // _q : demodulator object // _c : constellation table // _cp : nearest neighbor table [size: _p x 1] // _p : size of table // _r : received sample // _s : hard demodulator output // _soft_bits : soft bit output (approximate log-likelihood ratio) void modemcf_demodulate_soft_tab(modemcf _q, float complex * _c, unsigned int * _cp, unsigned int _p, float complex _r, unsigned int * _s, float * _soft_bits); int main(int argc, char*argv[]) { srand(time(NULL)); // options modulation_scheme ms = LIQUID_MODEM_QAM16; // modulation scheme unsigned int p = 4; // number of 'nearest symbols' float complex e = 0.1f + _Complex_I*0.15f; // error // validate input if (ms == LIQUID_MODEM_UNKNOWN || ms >= LIQUID_MODEM_NUM_SCHEMES) { fprintf(stderr,"error: %s, invalid modulation scheme\n", argv[0]); exit(1); } unsigned int i; unsigned int j; unsigned int k; // derived values unsigned int bps = modulation_types[ms].bps; unsigned int M = 1 << bps; // constellation size // ensure number of nearest symbols is not too large if (p > (M-1)) { fprintf(stderr,"error: requesting too many neighbors\n"); exit(1); } float sig = 0.2f; // noise standard deviation // generate constellation modemcf q = modemcf_create(ms); float complex c[M]; // constellation for (i=0; i> (bps-k-1)) & 0x01; //printf("%c", bit ? '1' : '0'); if (bit) bit_1 += t; else bit_0 += t; #if DEBUG printf(" symbol : "); print_bitstring(i,bps); printf(" [%c]", bit ? '1' : '0'); printf(" { %7.4f %7.4f}, d=%7.4f, t=%12.8f\n", crealf(c[i]), cimagf(c[i]), d, t); #endif } soft_bits[k] = logf(bit_1) - logf(bit_0); #if DEBUG printf(" {0 : %12.8f, 1 : %12.8f}\n", bit_0, bit_1); #endif } // // demodulate using internal method // q = modemcf_create(ms); unsigned int sym_out_tab; float soft_bits_tab[bps]; modemcf_demodulate_soft_tab(q,c,cp,p,r,&sym_out_tab,soft_bits_tab); modemcf_destroy(q); // print results printf("\n"); printf(" input symbol : "); print_bitstring(sym_in,bps); printf(" {%12.8f, %12.8f}\n", crealf(c[sym_in]), cimagf(c[sym_in])); printf(" soft bits :\n"); printf(" /----------- LLR -----------\\ /------- min dist --------\\\n"); for (k=0; k> (bps-k-1)) & 0x01); printf("%12.8f > ", soft_bits[k]); int soft_bit = (soft_bits[k]*16 + 127); if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; printf("%5d > %1u", soft_bit, soft_bit & 0x80 ? 1 : 0); // // print tabular method // printf(" "); printf("%12.8f > ", soft_bits_tab[k]); soft_bit = (soft_bits_tab[k]*16 + 127); if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; printf("%5d > %1u", soft_bit, soft_bit & 0x80 ? 1 : 0); printf("\n"); } // // export results to file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"m = %u;\n", bps); fprintf(fid,"M = %u;\n", 1<> (bps-k-1)) & 0x01; if (bit) dmin_1 = d; else dmin_0 = d; // check symbols in table #if DEBUG printf(" index %2u : ", k); #endif for (i=0; i<_p; i++) { bit = (_cp[(*_s)*_p+i] >> (bps-k-1)) & 0x01; #if DEBUG print_bitstring(_cp[(*_s)*_p+i],bps); printf("[%1u]", bit); #endif // compute distance float complex x_hat = _c[ _cp[(*_s)*_p + i] ]; d = crealf( (_r-x_hat)*conjf(_r-x_hat) ); #if DEBUG printf("(%8.6f) ", d); #endif if (bit) { if (d < dmin_1) dmin_1 = d; } else { if (d < dmin_0) dmin_0 = d; } } #if DEBUG printf("\n"); printf(" dmin_0 : %12.8f\n", dmin_0); printf(" dmin_1 : %12.8f\n", dmin_1); #endif // make assignments #if 0 _soft_bits[k] = logf(expf(-dmin_1/(2.0f*sig*sig))) - logf(expf(-dmin_0/(2.0f*sig*sig))); #else _soft_bits[k] = (-dmin_1/(2.0f*sig*sig)) - (-dmin_0/(2.0f*sig*sig)); #endif } } liquid-dsp-1.7.0/sandbox/modem_demodulate_soft_test.c000066400000000000000000000102211474751757600230150ustar00rootroot00000000000000// Test soft demoulation using log-likelihood ratio #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "modem_demodulate_soft_test.m" int main() { srand(time(NULL)); // options modulation_scheme ms = LIQUID_MODEM_QAM16; // modulation scheme float complex e = 0.1f + _Complex_I*0.2f; // error unsigned int i; // derived values float sig = 0.2f; // noise standard deviation // generate constellation modemcf q = modemcf_create(ms); unsigned int bps = modemcf_get_bps(q); unsigned int M = 1 << bps; // constellation size float complex c[M]; // constellation for (i=0; i> (bps-k-1)) & 0x01; //printf("%c", bit ? '1' : '0'); if (bit) bit_1 += t; else bit_0 += t; printf(" symbol : "); unsigned int j; for (j=0; j> (bps-j-1)) & 0x01 ? '1' : '0'); printf(" [%c]", bit ? '1' : '0'); printf(" { %7.4f %7.4f}, d=%7.4f, t=%12.8f\n", crealf(c[i]), cimagf(c[i]), d, t); } soft_bits[k] = logf(bit_1) - logf(bit_0); printf(" {0 : %12.8f, 1 : %12.8f}\n", bit_0, bit_1); } // print results printf("\n"); printf(" input symbol : "); for (k=0; k> (bps-k-1)) & 0x01 ? '1' : '0'); printf(" {%12.8f, %12.8f}\n", crealf(c[sym_in]), cimagf(c[sym_in])); printf(" soft bits :\n"); for (k=0; k> (bps-k-1)) & 0x01); printf("%12.8f > ", soft_bits[k]); int soft_bit = (soft_bits[k]*16 + 127); if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; printf("%5d > %1u\n", soft_bit, soft_bit & 0x80 ? 1 : 0); } // // export results to file // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"m = %u;\n", bps); fprintf(fid,"M = %u;\n", 1< #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "mskmodem_test.m" // print usage/help message void usage() { printf("mskmodem_test -- minimum-shift keying modem example\n"); printf("options:\n"); printf(" -h : print help\n"); printf(" -t : filter type: [square], rcos-full, rcos-half, gmsk\n"); printf(" -k : samples/symbol, default: 8\n"); printf(" -b : bits/symbol, default: 1\n"); printf(" -H : modulation index, default: 0.5\n"); printf(" -B : filter roll-off, default: 0.35\n"); printf(" -n : number of data symbols, default: 20\n"); printf(" -s : SNR [dB], default: 80\n"); printf(" -F : carrier freq. offset, default: 0.0\n"); printf(" -P : carrier phase offset, default: 0.0\n"); } int main(int argc, char*argv[]) { // options unsigned int k = 8; // filter samples/symbol unsigned int bps= 1; // number of bits/symbol float h = 0.5f; // modulation index (h=1/2 for MSK) unsigned int num_data_symbols = 20; // number of data symbols float SNRdB = 80.0f; // signal-to-noise ratio [dB] float cfo = 0.0f; // carrier frequency offset float cpo = 0.0f; // carrier phase offset enum { TXFILT_SQUARE=0, TXFILT_RCOS_FULL, TXFILT_RCOS_HALF, TXFILT_GMSK, } tx_filter_type = TXFILT_SQUARE; float gmsk_bt = 0.35f; // GMSK bandwidth-time factor int dopt; while ((dopt = getopt(argc,argv,"ht:k:b:H:B:n:s:F:P:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 't': if (strcmp(optarg,"square")==0) { tx_filter_type = TXFILT_SQUARE; } else if (strcmp(optarg,"rcos-full")==0) { tx_filter_type = TXFILT_RCOS_FULL; } else if (strcmp(optarg,"rcos-half")==0) { tx_filter_type = TXFILT_RCOS_HALF; } else if (strcmp(optarg,"gmsk")==0) { tx_filter_type = TXFILT_GMSK; } else { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'k': k = atoi(optarg); break; case 'b': bps = atoi(optarg); break; case 'H': h = atof(optarg); break; case 'B': gmsk_bt = atof(optarg); break; case 'n': num_data_symbols = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'F': cfo = atof(optarg); break; case 'P': cpo = atof(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_symbols = num_data_symbols; unsigned int num_samples = k*num_symbols; unsigned int M = 1 << bps; // constellation size float nstd = powf(10.0f, -SNRdB/20.0f); // arrays unsigned char sym_in[num_symbols]; // input symbols float phi[num_samples]; // transmitted phase float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float complex z[num_samples]; // output... //unsigned char sym_out[num_symbols]; // output symbols unsigned int ht_len = 0; unsigned int tx_delay = 0; float * ht = NULL; switch (tx_filter_type) { case TXFILT_SQUARE: // regular MSK ht_len = k; tx_delay = 1; ht = (float*) malloc(ht_len *sizeof(float)); for (i=0; i (%1u)", n, crealf(z[i]), cimagf(z[i]), phi_hat, v, sym_out); if (n >= m+tx_delay) { num_errors += (sym_out == sym_in[n-m-tx_delay]) ? 0 : 1; num_symbols_checked++; printf(" (%1u)\n", sym_in[n-m-tx_delay]); } else { printf("\n"); } n++; } } // print number of errors printf("errors : %3u / %3u\n", num_errors, num_symbols_checked); // destroy objects firinterp_rrrf_destroy(interp_tx); firfilt_crcf_destroy(decim_rx); // compute power spectral density of transmitted signal unsigned int nfft = 1024; float psd[nfft]; spgramcf_estimate_psd(nfft, y, num_samples, psd); // // export results // FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"h = %f;\n", h); fprintf(fid,"num_symbols = %u;\n", num_symbols); fprintf(fid,"num_samples = %u;\n", num_samples); fprintf(fid,"nfft = %u;\n", nfft); fprintf(fid,"delay = %u; %% receive filter delay\n", tx_delay); fprintf(fid,"x = zeros(1,num_samples);\n"); fprintf(fid,"y = zeros(1,num_samples);\n"); fprintf(fid,"z = zeros(1,num_samples);\n"); fprintf(fid,"phi = zeros(1,num_samples);\n"); for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "msresamp_crcf_test.m" // print usage/help message void usage() { printf("Usage: msresamp_crcf_test [OPTION]\n"); printf(" h : print help\n"); printf(" r : resampling rate (output/input), default: 0.117\n"); printf(" s : stop-band attenuation [dB], default: 60\n"); printf(" n : number of input samples, default: 500\n"); } int main(int argc, char*argv[]) { // options float r=1.2f; // resampling rate (output/input) float As=80.0f; // resampling filter stop-band attenuation [dB] unsigned int nx=400; // number of input samples float fc=0.40f; // complex sinusoid frequency int dopt; while ((dopt = getopt(argc,argv,"hr:s:n:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'r': r = atof(optarg); break; case 's': As = atof(optarg); break; case 'n': nx = atoi(optarg); break; default: exit(1); } } // validate input if (nx == 0) { fprintf(stderr,"error: %s, number of input samples must be greater than zero\n", argv[0]); exit(1); } else if (r <= 0.0f) { fprintf(stderr,"error: %s, resampling rate must be greater than zero\n", argv[0]); exit(1); } else if ( fabsf(log2f(r)) > 10 ) { fprintf(stderr,"error: %s, resampling rate unreasonable\n", argv[0]); exit(1); } unsigned int i; // derived values unsigned int ny_alloc = (unsigned int) (2*(float)nx * r); // allocation for output // allocate memory for arrays float complex x[nx]; float complex y[ny_alloc]; // generate input unsigned int window_len = (3*nx)/4; for (i=0; i1, fx = f/r; fy = f; %% interpolated\n"); fprintf(fid,"else, fx = f; fy = f*r; %% decimated\n"); fprintf(fid,"end;\n"); fprintf(fid,"plot(fx,X,'Color',[0.5 0.5 0.5],fy,Y,'LineWidth',2);\n"); fprintf(fid,"grid on;\n\n"); fprintf(fid,"xlabel('normalized frequency');\n"); fprintf(fid,"ylabel('PSD [dB]');\n"); fprintf(fid,"legend('original','resampled','location','northeast');"); fprintf(fid,"axis([-0.5 0.5 -120 10]);\n"); fprintf(fid,"\n\n"); fprintf(fid,"%% plot time-domain result\n"); fprintf(fid,"tx=[0:(length(x)-1)];\n"); fprintf(fid,"ty=[0:(length(y)-1)]/r-delay;\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(tx,real(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,real(y),'-s','Color',[0.5 0 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('real');\n"); fprintf(fid," grid on;\n\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(tx,imag(x),'-s','Color',[0.5 0.5 0.5],'MarkerSize',1,...\n"); fprintf(fid," ty,imag(y),'-s','Color',[0 0.5 0], 'MarkerSize',1);\n"); fprintf(fid," legend('original','resampled','location','northeast');"); fprintf(fid," xlabel('time');\n"); fprintf(fid," ylabel('imag');\n"); fprintf(fid," grid on;\n\n"); fclose(fid); printf("results written to %s\n",OUTPUT_FILENAME); printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/newbench_example.c000066400000000000000000000071031474751757600207300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Example of a benchmark header // // compile and run: // $ gcc -Wall -I. -I./include -c newbench_example.c -o newbench_example.o // $ gcc newbench_example.o libliquid.a -lm -lfec -lpthread -lc -lfftw3f -o newbench_example // $ ./newbench_example #include #include #include #include #include #include #include "include/liquid.h" double calculate_execution_time(struct rusage _start, struct rusage _finish) { return _finish.ru_utime.tv_sec - _start.ru_utime.tv_sec + 1e-6*(_finish.ru_utime.tv_usec - _start.ru_utime.tv_usec) + _finish.ru_stime.tv_sec - _start.ru_stime.tv_sec + 1e-6*(_finish.ru_stime.tv_usec - _start.ru_stime.tv_usec); } struct decim_crcf_opts { unsigned int n; // filter length unsigned int D; // decimation factor }; void benchmark_decim_crcf( void * _opts, struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // retrieve options struct decim_crcf_opts * opts = (struct decim_crcf_opts*) _opts; unsigned long int i; // DSP initiazation goes here float h[opts->n]; for (i=0; in; i++) h[i] = 0.0f; decim_crcf decim = decim_crcf_create(opts->D,h,opts->n); float complex x[opts->D]; float complex y; for (i=0; iD; i++) x[i] = 1.0f; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // DSP execution goes here decim_crcf_execute(decim,x,&y,opts->D-1); } getrusage(RUSAGE_SELF, _finish); // DSP cleanup goes here decim_crcf_destroy(decim); } void precision_decim_crcf( unsigned int argc, char *argv[], float * _error) { // blah... *_error = 0.0f; } int main() { struct rusage start,finish; unsigned long int num_trials = 1000000; unsigned int n; unsigned int D; double extime; double cpuclock=2.4e9; double cycles_per_trial; struct decim_crcf_opts opts; for (D=2; D<=8; D*=2) { printf("***** D = %u\n",D); for (n=5; n<31; n+=4) { opts.D = D; opts.n = n; benchmark_decim_crcf((void*)(&opts),&start,&finish,&num_trials); extime = calculate_execution_time(start,finish); cycles_per_trial = cpuclock * extime / (double)(num_trials); printf("n : %3u, D : %3u, cycles/trial : %6.2f\n", n,D,cycles_per_trial); } } printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/ofdm_ber_test.c000066400000000000000000000113731474751757600202440ustar00rootroot00000000000000// test OFDM bit error rate #include #include #include #include #include #include #include "liquid.h" void usage() { printf("ofdm_ber_test [options]\n"); printf(" h : print usage\n"); printf(" s : signal-to-noise ratio [dB], default: 6.5\n"); printf(" M : number of subcarriers (must be even), default: 64\n"); printf(" C : cyclic prefix length, default: 16\n"); printf(" m : modulation scheme (bpsk default)\n"); liquid_print_modulation_schemes(); printf(" n : number of OFDM symbols, default: 40\n"); printf(" c : number of channel taps, default: 1\n"); } int main(int argc, char*argv[]) { // set random number generator seed srand(time(NULL)); // options unsigned int M = 64; // number of subcarriers unsigned int cp_len = 16; // cyclic prefix length modulation_scheme ms = LIQUID_MODEM_BPSK; float SNRdB = 6.5f; // signal-to-noise ratio [dB] unsigned int hc_len = 1; // channel impulse response length unsigned int num_symbols = 40; // number of OFDM symbols // get options int dopt; while((dopt = getopt(argc,argv,"hs:M:C:m:n:c:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 's': SNRdB = atof(optarg); break; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'm': ms = liquid_getopt_str2mod(optarg); if (ms == LIQUID_MODEM_UNKNOWN) { fprintf(stderr,"error: %s, unknown/unsupported mod. scheme: %s\n", argv[0], optarg); exit(-1); } break; case 'n': num_symbols = atoi(optarg); break; case 'c': hc_len = atoi(optarg); break; default: exit(-1); } } unsigned int i; // validate options if (M < 4) { fprintf(stderr,"error: %s, must have at least 4 subcarriers\n", argv[0]); exit(1); } else if (hc_len == 0) { fprintf(stderr,"error: %s, must have at least 1 channel tap\n", argv[0]); exit(1); } // derived values unsigned int symbol_len = M + cp_len; float nstd = powf(10.0f, -SNRdB/20.0f); float fft_gain = 1.0f / sqrtf(M); // 'gain' due to taking FFT // buffers unsigned int sym_in[M]; // input data symbols unsigned int sym_out[M]; // output data symbols float complex x[M]; // time-domain buffer float complex X[M]; // freq-domain buffer float complex buffer[symbol_len]; // // create modulator/demodulator objects modemcf mod = modemcf_create(ms); modemcf demod = modemcf_create(ms); unsigned int bps = modemcf_get_bps(mod); // modem bits/symbol // create channel filter (random taps) float complex hc[hc_len]; hc[0] = 1.0f; for (i=1; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmframe_papr_test.m" void usage() { printf("Usage: ofdmframe_papr_test [OPTION]\n"); printf(" h : print help\n"); printf(" M : number of subcarriers (must be even), default: 64\n"); printf(" C : cyclic prefix length, default: 16\n"); printf(" T : taper length, default: 0\n"); printf(" N : number of data symbols, default: 1000\n"); } // compute peak-to-average power ratio // _x : input time series // _n : number of samples float ofdmframe_PAPR(float complex * _x, unsigned int _n); int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int M = 64; // number of subcarriers unsigned int cp_len = 16; // cyclic prefix length unsigned int taper_len = 0; // taper length unsigned int num_symbols = 1000; // number of data symbols modulation_scheme ms = LIQUID_MODEM_QPSK; // get options int dopt; while((dopt = getopt(argc,argv,"hM:C:T:N:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'T': taper_len = atoi(optarg); break; case 'N': num_symbols = atoi(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int frame_len = M + cp_len; // initialize subcarrier allocation unsigned char p[M]; ofdmframe_init_default_sctype(M, p); // create frame generator ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, p); ofdmframegen_print(fg); modemcf mod = modemcf_create(ms); float complex X[M]; // channelized symbols float complex buffer[frame_len];// output time series float * PAPR = (float*) malloc(num_symbols*sizeof(float)); // histogram display float xmin = -1.29f + 0.70f*log2f(M); float xmax = 8.97f + 0.34f*log2f(M); unsigned int num_bins = 30; float bin_width = (xmax - xmin) / (num_bins); unsigned int hist[num_bins]; for (i=0; i= num_bins) index = num_bins-1; hist[index]++; // save min/max PAPR values if (i==0 || PAPR[i] < PAPR_min) PAPR_min = PAPR[i]; if (i==0 || PAPR[i] > PAPR_max) PAPR_max = PAPR[i]; PAPR_mean += PAPR[i]; } PAPR_mean /= (float)num_symbols; // destroy objects ofdmframegen_destroy(fg); modemcf_destroy(mod); // print results to screen // find max(hist) unsigned int hist_max = 0; for (i=0; i hist_max ? hist[i] : hist_max; printf("%8s : %6s [%6s]\n", "PAPR[dB]", "count", "prob."); for (i=0; i e_max) ? e : e_max; } e_mean = e_mean / (float)_n; return 10*log10f(e_max / e_mean); } liquid-dsp-1.7.0/sandbox/ofdmframesync_cfo_test.c000066400000000000000000000154701474751757600221550ustar00rootroot00000000000000// // ofdmframesync_cfo_test : test carrier frequency offset estimation // #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmframesync_cfo_test.dat" void usage() { printf("Usage: ofdmframesync_cfo_test [OPTION]\n"); printf(" h : print help\n"); printf(" M : number of subcarriers (must be even), default: 64\n"); printf(" C : cyclic prefix length, default: 16\n"); printf(" T : taper length, default: 4\n"); printf(" S : signal-to-noise ratio [dB], default: 20\n"); printf(" t : number of trials, default: 500\n"); printf(" s : number of steps, default: 21\n"); } static int callback(float complex * _X, unsigned char * _p, unsigned int _M, void * _userdata); int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int M = 64; // number of subcarriers unsigned int cp_len = 16; // cyclic prefix length unsigned int taper_len = 4; // taper length float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 20.0f; // signal-to-noise ratio [dB] unsigned int num_trials = 500; // number of trials to simulate unsigned int num_steps = 21; // number of steps // get options int dopt; while((dopt = getopt(argc,argv,"hM:C:T:S:t:s:")) != EOF){ switch (dopt) { case 'h': usage(); return 0; case 'M': M = atoi(optarg); break; case 'C': cp_len = atoi(optarg); break; case 'T': taper_len = atoi(optarg); break; case 'S': SNRdB = atof(optarg); break; case 't': num_trials= atoi(optarg); break; case 's': num_steps = atoi(optarg); break; default: exit(1); } } unsigned int i; // derived values unsigned int num_symbols = 1; // number of data symbols unsigned int symbol_len = M + cp_len; unsigned int num_samples = (3+num_symbols)*symbol_len; // data symbols float nstd = powf(10.0f, noise_floor/20.0f); float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f); printf("gamma : %f\n", gamma); // initialize subcarrier allocation unsigned char p[M]; ofdmframe_init_default_sctype(M, p); // create frame generator ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, p); ofdmframegen_print(fg); // create frame synchronizer int frame_detected; ofdmframesync fs = ofdmframesync_create(M, cp_len, taper_len, p, callback, (int*)&frame_detected); ofdmframesync_print(fs); float complex X[M]; // channelized symbols float complex frame[num_samples]; // initial frame float complex y[num_samples]; // output time series unsigned int n=0; // generate frame ofdmframegen_write_S0a(fg, &frame[n]); n += symbol_len; ofdmframegen_write_S0b(fg, &frame[n]); n += symbol_len; ofdmframegen_write_S1( fg, &frame[n]); n += symbol_len; // generate single data symbol (random BPSK) for (i=0; i #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmoqam_firpfbch_cfo_test.m" #define DEBUG 1 int main() { // options unsigned int num_channels=64; // must be even number unsigned int num_symbols=16; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor float phi = 0.0f; // carrier phase offset; float dphi = 0.04f; // carrier frequency offset // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; unsigned int i; unsigned int j; // create filter prototype unsigned int h_len = 2*num_channels*m + 1; float h[h_len]; float complex hc[h_len]; float complex gc[h_len]; liquid_firdes_rkaiser(num_channels, m, beta, 0.0f, h); unsigned int g_len = 2*num_channels*m; for (i=0; i #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "ofdmoqam_firpfbch_test.m" int main() { // options unsigned int num_channels=6; // must be even number unsigned int num_symbols=32; // number of symbols unsigned int m=3; // filter delay (symbols) float beta = 0.9f; // filter excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; // number of frames (compensate for filter delay) unsigned int num_frames = num_symbols + 2*m; unsigned int num_samples = num_channels * num_frames; // create synthesizer/analyzer objects firpfbch_crcf cs0 = firpfbch_crcf_create_rnyquist(LIQUID_SYNTHESIZER, num_channels, m, beta, ftype); firpfbch_crcf cs1 = firpfbch_crcf_create_rnyquist(LIQUID_SYNTHESIZER, num_channels, m, beta, ftype); firpfbch_crcf ca0 = firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, num_channels, m, beta, ftype); firpfbch_crcf ca1 = firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, num_channels, m, beta, ftype); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"num_channels=%u;\n", num_channels); fprintf(fid,"num_symbols=%u;\n", num_symbols); fprintf(fid,"num_samples=%u;\n", num_samples); fprintf(fid,"X = zeros(%u,%u);\n", num_channels, num_frames); fprintf(fid,"y = zeros(1,%u);\n", num_samples); fprintf(fid,"Y = zeros(%u,%u);\n", num_channels, num_frames); unsigned int i, j, n=0; unsigned int k2 = num_channels/2; float complex X[num_channels]; // channelized symbols float complex y[num_channels]; // interpolated time-domain samples float complex Y[num_channels]; // received symbols // temporary buffers float complex X0[num_channels]; float complex X1[num_channels]; float complex y0[num_channels]; float complex y1[num_channels]; float complex y1_prime[num_channels]; for (i=0; i #include #include #include #include #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "packetizer_persistent_ber_test.m" void usage() { printf("Usage: packetizer_persistent_ber_test\n"); printf(" Simulates persistent decoding (best for small packets, large CRC)\n"); printf("options:\n"); printf(" u/h : print usage/help\n"); printf(" s : SNR min [dB], default: 0\n"); printf(" x : SNR max [dB], default: 8\n"); printf(" n : number of SNR steps, default: 33\n"); printf(" t : number of trials, default: 2000\n"); printf(" f : frame size, default: 20\n"); printf(" v : data integrity check: crc32 default\n"); liquid_print_crc_schemes(); printf(" c : coding scheme (inner), default: h128\n"); printf(" k : coding scheme (outer), default: none\n"); liquid_print_fec_schemes(); } // persistent decoding methods int packetizer_decode_persistent(packetizer _p, unsigned char * _pkt, unsigned char * _msg); int packetizer_decode_persistent2(packetizer _p, unsigned char * _pkt, unsigned char * _msg); int main(int argc, char *argv[]) { // set initial seed to random srand(time(NULL)); // options unsigned int n = 20; // frame size (bytes) float SNRdB_min = 0.0f; // signal-to-noise ratio (minimum) float SNRdB_max = 8.0f; // signal-to-noise ratio (maximum) unsigned int num_snr = 33; // number of SNR steps unsigned int num_trials=2000; // number of trials crc_scheme check = LIQUID_CRC_32; // error-detection scheme fec_scheme fec0 = LIQUID_FEC_HAMMING128;// error-correcting scheme (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // error-correcting scheme (outer) // get command-line options int dopt; while((dopt = getopt(argc,argv,"uhs:x:n:t:f:v:c:k:")) != EOF){ switch (dopt) { case 'h': case 'u': usage(); return 0; case 's': SNRdB_min = atof(optarg); break; case 'x': SNRdB_max = atof(optarg); break; case 'n': num_snr = atoi(optarg); break; case 't': num_trials = atoi(optarg); break; case 'f': n = atoi(optarg); break; case 'v': // data integrity check check = liquid_getopt_str2crc(optarg); if (check == LIQUID_CRC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg); exit(1); } break; case 'c': fec0 = liquid_getopt_str2fec(optarg); if (fec0 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg); exit(1); } break; case 'k': fec1 = liquid_getopt_str2fec(optarg); if (fec1 == LIQUID_FEC_UNKNOWN) { fprintf(stderr,"error: unknown/unsupported fec scheme \"%s\"\n\n",optarg); exit(1); } break; default: exit(1); } } unsigned int i; // create arrays unsigned int k = packetizer_compute_enc_msg_len(n,check,fec0,fec1); printf("dec msg len : %u\n", n); printf("enc msg len : %u\n", k); float rate = (float)n / (float)k; unsigned char msg_org[n]; // original data message unsigned char msg_enc[k]; // encoded data message float complex sym_rec[8*k]; // received BPSK symbols unsigned char msg_cor[k]; // corrupted data message unsigned char msg_dec_per0[n]; // decoded data message (regular decoding) unsigned char msg_dec_per2[n]; // decoded data message (persistent decoding) // create object packetizer q = packetizer_create(n,check,fec0,fec1); packetizer_print(q); unsigned int packet_errors_per0[num_snr]; unsigned int packet_errors_per2[num_snr]; // // set up parameters // float SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr-1); // // start trials // printf(" %8s %8s [%6s] %8s %8s %8s %8s\n", "SNR [dB]", "Eb/N0", "trials", "per", "(PER)", "reg", "(PER)"); unsigned int s; for (s=0; s 0.0f ? 0x80 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+1]) > 0.0f ? 0x40 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+2]) > 0.0f ? 0x20 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+3]) > 0.0f ? 0x10 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+4]) > 0.0f ? 0x08 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+5]) > 0.0f ? 0x04 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+6]) > 0.0f ? 0x02 : 0x00; msg_cor[i] |= crealf(sym_rec[8*i+7]) > 0.0f ? 0x01 : 0x00; } // decode packetizer_decode( q, msg_cor, msg_dec_per0); packetizer_decode_persistent2(q, msg_cor, msg_dec_per2); // tabulate results packet_errors_per0[s] += count_bit_errors_array(msg_org, msg_dec_per0, n) ? 1 : 0; packet_errors_per2[s] += count_bit_errors_array(msg_org, msg_dec_per2, n) ? 1 : 0; } // print results for this SNR step printf(" %8.3f %8.3f [%6u] %8u %8.2f %8u %8.2f\n", SNRdB, SNRdB - 10*log10f(rate), num_trials, packet_errors_per2[s], 100.0f * (float)(packet_errors_per2[s]) / (float)(num_trials), packet_errors_per0[s], 100.0f * (float)(packet_errors_per0[s]) / (float)(num_trials) ); } // clean up objects packetizer_destroy(q); // // export output file // FILE * fid = fopen(OUTPUT_FILENAME, "w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"\n\n"); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"n = %u; %% frame size [bytes]\n", n); fprintf(fid,"k = %u; %% encoded frame size [bytes]\n", k); fprintf(fid,"r = n / k; %% true rate\n"); fprintf(fid,"num_snr = %u;\n", num_snr); fprintf(fid,"num_trials = %u;\n", num_trials); for (i=0; ibuffer_0; flip bits to try to get // CRC to pass for (i=0; i<_p->msg_len + _p->crc_length; i++) { unsigned int j; for (j=0; j<8; j++) { // flip bit unsigned char mask = 1 << (8-j-1); _p->buffer_0[i] ^= mask; // strip crc, validate message key = 0; unsigned int k; for (k=0; k<_p->crc_length; k++) { key <<= 8; key |= _p->buffer_0[_p->msg_len+k]; } // compute crc validity crc_pass = crc_validate_message(_p->check, _p->buffer_0, _p->msg_len, key); // check validity if (crc_pass) { // copy result to output and return memmove(_msg, _p->buffer_0, _p->msg_len); //printf("persistent decoding worked!\n"); return crc_pass; } else { // flip bit back _p->buffer_0[i] ^= mask; } } } // copy result to output and return memmove(_msg, _p->buffer_0, _p->msg_len); return crc_pass; } // double bit errors in a single byte // nchoosek(8,2) = 28 unsigned char packetizer_persistent_mask2[28] = { 0x03, // 00000011 0x06, // 00000110 0x0C, // 00001100 0x18, // 00011000 0x30, // 00110000 0x60, // 01100000 0xC0, // 11000000 0x05, // 00000101 0x0A, // 00001010 0x14, // 00010100 0x28, // 00101000 0x50, // 01010000 0xA0, // 10100000 0x09, // 00001001 0x12, // 00010010 0x24, // 00100100 0x48, // 01001000 0x90, // 10010000 0x11, // 00010001 0x22, // 00100010 0x44, // 01000100 0x88, // 10001000 0x21, // 00100001 0x42, // 01000010 0x84, // 10000100 0x41, // 01000001 0x82, // 10000010 0x81, // 10000001 }; // Execute the packetizer to decode an input message, return validity // check of resulting data; persistent attempts to find error(s) // // _p : packetizer object // _pkt : input message (coded bytes) // _msg : decoded output message int packetizer_decode_persistent2(packetizer _p, unsigned char * _pkt, unsigned char * _msg) { // try first-order persistent decoding int crc_pass = packetizer_decode_persistent(_p, _pkt, _msg); // return if decoding was successful if (crc_pass) return crc_pass; unsigned int i; unsigned int key=0; // result is stored in _p->buffer_0; flip bits to try to get // CRC to pass for (i=0; i<_p->msg_len + _p->crc_length; i++) { unsigned int j; for (j=0; j<28; j++) { // apply mask _p->buffer_0[i] ^= packetizer_persistent_mask2[j]; // strip crc, validate message key = 0; unsigned int k; for (k=0; k<_p->crc_length; k++) { key <<= 8; key |= _p->buffer_0[_p->msg_len+k]; } // compute crc validity crc_pass = crc_validate_message(_p->check, _p->buffer_0, _p->msg_len, key); // check validity if (crc_pass) { // copy result to output and return memmove(_msg, _p->buffer_0, _p->msg_len); //printf("persistent decoding worked! (2)\n"); return crc_pass; } else { // flip bit back _p->buffer_0[i] ^= packetizer_persistent_mask2[j]; } } } // copy result to output and return memmove(_msg, _p->buffer_0, _p->msg_len); return crc_pass; } liquid-dsp-1.7.0/sandbox/pll_3rd_order_test.c000066400000000000000000000100431474751757600212120ustar00rootroot00000000000000// Demonstrates a 3rd-order PLL design to track to drifting carrier offset. #include #include #include #include void export_octave(); int main() { // options float phase_in = 3.0f; // carrier phase offset float frequency_in = -0.20; // carrier frequency offset float alpha = 0.08f; // phase adjustment factor unsigned int n = 1200; // number of samples float df_in = 0.30 /(float)n; // initialize states float beta = 0.5*alpha*alpha; // frequency adjustment factor float gamma = 2*powf(alpha,4.0f); // frequency drift adjustment factor float phase_out = 0.0f; // output signal phase float frequency_out = 0.0f; // output signal frequency float df_out = 0.0f; // output signal frequency drift // run basic simulation int i; FILE * fid= fopen("pll_3rd_order_test.dat","w"); fprintf(fid,"# %6s %6s %6s %6s %9s %9s %12s %12s %12s %12s %12s\n", "x-real","x-imag","y-real","y-imag","x-phase","y-phase", "x-freq","y-freq","x-dfreq","y-dfreq","phase err"); for (i=0; i #include #include #include #include #include "liquid.h" // output to octave-friendly format #define OUTPUT_FILENAME "pll_design_test.m" int main() { // parameters float phase_offset = 0.8f; float frequency_offset = 0.01f; float pll_bandwidth = 0.05f; float pll_damping_factor = 0.707f; unsigned int n=256; // number of iterations unsigned int d=n/32; // print every "d" lines // float theta[n]; // input phase float complex x[n]; // input sinusoid float phi[n]; // output phase float complex y[n]; // output sinusoid // generate iir loop filter(s) float a[3]; float b[3]; float wn = pll_bandwidth; float zeta = pll_damping_factor; float K = 10; // loop gain #if 0 // loop filter (active lag) float t1 = K/(wn*wn); float t2 = 2*zeta/wn - 1/K; b[0] = 2*K*(1.+t2/2.0f); b[1] = 2*K*2.; b[2] = 2*K*(1.-t2/2.0f); a[0] = 1 + t1/2.0f; a[1] = -t1; a[2] = -1 + t1/2.0f; #else // loop filter (active PI) float t1 = K/(wn*wn); float t2 = 2*zeta/wn; b[0] = 2*K*(1.+t2/2.0f); b[1] = 2*K*2.; b[2] = 2*K*(1.-t2/2.0f); a[0] = t1/2.0f; a[1] = -t1; a[2] = t1/2.0f; #endif iirfilt_rrrf H = iirfilt_rrrf_create(b,3,a,3); iirfilt_rrrf_print(H); unsigned int i; // generate input float t=phase_offset; float dt = frequency_offset; for (i=0; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "predemod_sync_test.m" // print usage/help message void usage() { printf("predemod_sync_test -- test pre-demodulation synchronization\n"); printf("options:\n"); printf(" h : print usage/help\n"); printf(" k : samples/symbol, default: 2\n"); printf(" m : filter delay [symbols], default: 4\n"); printf(" n : number of data symbols, default: 64\n"); printf(" b : bandwidth-time product, (0,1), default: 0.3\n"); printf(" t : fractional sample offset, (-0.5,0.5), default: 0\n"); printf(" F : frequency offset, default: 0\n"); printf(" P : phase offset, default: 0\n"); printf(" s : SNR [dB], default: 30\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // filter samples/symbol unsigned int m=4; // filter delay (symbols) float beta=0.3f; // bandwidth-time product float dt = 0.0f; // fractional sample timing offset unsigned int num_sync_symbols = 64; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio [dB] float dphi = 0.0f; // carrier frequency offset float phi = 0.0f; // carrier phase offset unsigned int num_delay_symbols = 12; unsigned int num_dphi_hat = 21; // number of frequency offset estimates float dphi_hat_step = 0.01f; // frequency offset step size int dopt; while ((dopt = getopt(argc,argv,"uhk:m:n:b:t:F:P:s:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'n': num_sync_symbols = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 't': dt = atof(optarg); break; case 'F': dphi = atof(optarg); break; case 'P': phi = atof(optarg); break; case 's': SNRdB = atof(optarg); break; default: exit(1); } } unsigned int i; // validate input if (beta <= 0.0f || beta >= 1.0f) { fprintf(stderr,"error: %s, bandwidth-time product must be in (0,1)\n", argv[0]); exit(1); } else if (dt < -0.5 || dt > 0.5) { fprintf(stderr,"error: %s, fractional sample offset must be in (0,1)\n", argv[0]); exit(1); } // derived values unsigned int num_symbols = num_delay_symbols + num_sync_symbols + 2*m; unsigned int num_samples = k*num_symbols; unsigned int num_sync_samples = k*num_sync_symbols; float nstd = powf(10.0f, -SNRdB/20.0f); // arrays float complex seq[num_sync_symbols]; // data sequence (symbols) float complex s0[num_sync_samples]; // data sequence (interpolated samples) float complex x[num_samples]; // transmitted signal float complex y[num_samples]; // received signal float rxy[num_dphi_hat][num_samples]; // pre-demod output matrix // generate sequence for (i=0; i #include #include #include #include "liquid.h" #define DEBUG_BFGS 0 // utility function pointer typedef float (*utility)(float * _x, unsigned int _n); // utility function float myutility(float * _x, unsigned int _n); // useful function to print vector to screen void print_vector(const char * _str, float * _v, unsigned int _n); // estimate gradient at point _x // _x : input point, [size: _n x 1] // _n : dimension // _u : utility function pointer // _gradient : resulting gradient (normalized?) void estimate_gradient(float * _x, unsigned int _n, utility _u, float * _gradient); // update BFGS estimate of Hessian matrix inverse // _n : dimension // _dx : step size (previous), [size: _n x 1] // _y : gradient difference // _H0 : Hessian matrix inverse estimate (previous), [size: _n x _n] // _H1 : Hessian matrix inverse estimate [size: _n x _n] void bfgs_update(unsigned int _n, float * _dx, float * _y, float * _H0, float * _H1); // check the strong Wolfe conditions (c1=0.0001, c2=0.9) // _alpha : step length // _u0 : f(x) // _u1 : f(x + alpha*p) // _gamma0 : p'*grad(x) (NOTE: should be less than zero) // _gamma1 : p'*grad(x + alpha*p) int check_wolfe_conditions(float _alpha, float _u0, float _u1, float _gamma0, float _gamma1); // check Wolfe conditions // _x : input vector [size: _n x 1] // _p : step direction vector [size: _n x 1] // _n : dimension // _alpha : test step length // _u : utility function pointer int check_wolfe_conditions2(float * _x, float * _p, unsigned int _n, float _alpha, utility _u); int main() { // options unsigned int n = 4; // search dimension unsigned int num_iterations = 10; // number of steps // allocate memory for arrays float x[n]; // search vector float p[n]; // direction float dx[n]; // search vector step float gradient0[n]; float gradient1[n]; float y[n]; float H0[n*n]; float H1[n*n]; float alpha = 0.2f; unsigned int i; for (i=0; i 0 // _gamma < 0 // float c1 = 1e-4f; float c2 = 0.9f; // check first condition int cond1 = (_u1 <= _u0 + c1*_alpha*_gamma0) ? 1 : 0; // check second condition int cond2 = ( fabsf(_gamma1) <= c2*fabsf(_gamma0) ) ? 1 : 0; #if 0 printf("(g0: %12.8f g1: %12.8f) [%c %c]", _gamma0, _gamma1, cond1 ? '1' : '0', cond2 ? '1' : '0'); #endif // return cond1 && cond2; } // check Wolfe conditions // _x : input vector [size: _n x 1] // _p : step direction vector [size: _n x 1] // _n : dimension // _alpha : test step length // _u : utility function pointer int check_wolfe_conditions2(float * _x, float * _p, unsigned int _n, float _alpha, utility _u) { // allocate temporary arrays float grad0[_n]; float grad1[_n]; float x_prime[_n]; // compute f(x) float u0 = _u(_x,_n); // compute gradient(f(x)) estimate_gradient(_x,_n,_u,grad0); // compute f(x + alpha*p) unsigned int i; for (i=0; i<_n; i++) x_prime[i] = _x[i] + _alpha*_p[i]; float u1 = _u(x_prime, _n); // compute gradient(f(x + alpha*p)) estimate_gradient(x_prime, _n, _u, grad1); // compute p'*grad0 float gamma0 = 0.0f; for (i=0; i<_n; i++) gamma0 += _p[i] * grad0[i]; // compute p'*grad1 float gamma1 = 0.0f; for (i=0; i<_n; i++) gamma1 += _p[i] * grad1[i]; // test Wolfe conditions return check_wolfe_conditions(_alpha, u0, u1, gamma0, gamma1); } liquid-dsp-1.7.0/sandbox/recursive_qpsk_test.c000066400000000000000000000110111474751757600215210ustar00rootroot00000000000000// Run recursive QPSK modulation/demodulation test. #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "recursive_qpsk_test.m" // print usage/help message void usage() { printf("%s [options]\n", __FILE__); printf(" -h : print usage\n"); printf(" -b : beta value for constellation, beta in (0,1)\n"); } int main(int argc, char*argv[]) { // create mod/demod objects float beta = 0.25f; float SNRdB_min = 0.0f; float SNRdB_max = 30.0f; unsigned int num_snr = 31; unsigned int num_trials = 1e6; int dopt; while ((dopt = getopt(argc,argv,"hb:")) != EOF) { switch (dopt) { case 'h': usage(); return 0; case 'b': beta = atof(optarg); break; default: exit(1); } } unsigned int i; float complex map_qpsk[4] = { M_SQRT1_2 + _Complex_I*M_SQRT1_2, // 00 -M_SQRT1_2 + _Complex_I*M_SQRT1_2, // 01 M_SQRT1_2 - _Complex_I*M_SQRT1_2, // 10 -M_SQRT1_2 - _Complex_I*M_SQRT1_2, // 11 }; // generate composite constellation float complex map[16]; for (i=0; i<4; i++) { map[4*i+0] = map_qpsk[i] + beta*map_qpsk[0]; map[4*i+1] = map_qpsk[i] + beta*map_qpsk[1]; map[4*i+2] = map_qpsk[i] + beta*map_qpsk[2]; map[4*i+3] = map_qpsk[i] + beta*map_qpsk[3]; } // create arbitrary modem modemcf mod = modemcf_create_arbitrary(map, 16); // open file for writing FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); unsigned int sym_tx_0; unsigned int sym_tx_1; unsigned int sym_tx; float complex s; unsigned int sym_rx; unsigned int sym_rx_0; unsigned int sym_rx_1; unsigned int num_bit_errors_0 = 0; unsigned int num_bit_errors_1 = 0; // print constellation fprintf(fid,"map = zeros(1,16);\n"); for (i=0; i<16; i++) { modemcf_modulate(mod, i, &s); fprintf(fid,"map(%2u) = %12.4e + %12.4ei;\n", i+1, crealf(s), cimagf(s)); } unsigned int n; float complex SNRdB_step = (SNRdB_max - SNRdB_min) / (num_snr - 1); for (n=0; n> 2) & 0x3; sym_rx_1 = (sym_rx ) & 0x3; // accumulate errors num_bit_errors_0 += count_bit_errors(sym_tx_0, sym_rx_0); num_bit_errors_1 += count_bit_errors(sym_tx_1, sym_rx_1); } float BER_QPSK = 0.5f*erfcf(powf(10.0f,SNRdB/20.0f)*M_SQRT1_2); float BER_0 = num_bit_errors_0 / (float)(2*num_trials); float BER_1 = num_bit_errors_1 / (float)(2*num_trials); // print results to screen printf("%3u : SNR = %6.3f dB, {%8u %8u} / %8u, QPSK: %12.4e, BER : {%12.4e %12.4e}\n", n, SNRdB, num_bit_errors_0, num_bit_errors_1, 2*num_trials, BER_QPSK, BER_0, BER_1); // print results to file fprintf(fid,"SNRdB(%3u)=%6.3f; BER_QPSK(%3u)=%12.4e; BER_0(%3u)=%12.4e; BER_1(%3u)=%12.4e;\n", n+1, SNRdB, n+1, BER_QPSK, n+1, BER_0, n+1, BER_1); } fprintf(fid,"figure;\n"); fprintf(fid,"semilogy(SNRdB,BER_QPSK+1e-12,SNRdB,BER_0+1e-12,SNRdB,BER_1+1e-12);\n"); fprintf(fid,"axis([%.3f %.3f 1e-5 1]);\n", SNRdB_min, SNRdB_max); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('SNR [dB]');\n"); fprintf(fid,"ylabel('BER');\n"); fprintf(fid,"legend('qpsk ', 'stream 0 ', 'stream 1 ', 'location', 'northeast');\n"); fclose(fid); printf("results written to '%s'\n", OUTPUT_FILENAME); // destroy modem object modemcf_destroy(mod); printf("done.\n"); return 0; } liquid-dsp-1.7.0/sandbox/resamp2_crcf_filterbank_test.c000066400000000000000000000117371474751757600232420ustar00rootroot00000000000000// // resamp2_crcf_filterbank_test.c // // Halfband (two-channel) filterbank example. This example demonstrates // the analyzer/synthesizer execute() methods for the resamp2_xxxt // family of objects. // // NOTE: The filterbank is not a perfect reconstruction filter; a // significant amount of distortion occurs in the transition band // of the half-band filters. // // SEE ALSO: resamp2_crcf_decim_example.c // resamp2_crcf_interp_example.c // #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_filterbank_example.m" int main() { unsigned int m=9; // filter semi-length unsigned int num_samples=128; // number of input samples float As=60.0f; // stop-band attenuation [dB] // derived values unsigned int h_len = 4*m+1; // half-band filter length unsigned int N = num_samples + h_len; // ensure N is even N += (N%2); unsigned int n = N/2; // arrays float complex x[N]; // input time series float complex y[n][2]; // output time series (channelized) float complex z[N]; // output time series // generate input sequence unsigned int i; for (i=0; i #include #include #include "liquid.h" #define OUTPUT_FILENAME "resamp2_crcf_interp_recreate_test.m" int main() { unsigned int m0=5; unsigned int m1=4; unsigned int h0_len = 4*m0+1; // initial filter length unsigned int h1_len = 4*m1+1; // filter length (after recreate) float fc=0.10f; unsigned int N=32; float As=60.0f; resamp2_cccf f = resamp2_cccf_create(h0_len,0.0f,As); resamp2_cccf_print(f); FILE*fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s: auto-generated file\n",OUTPUT_FILENAME); fprintf(fid,"clear all;\nclose all;\n\n"); fprintf(fid,"h0_len = %u;\n", h0_len); fprintf(fid,"h1_len = %u;\n", h1_len); fprintf(fid,"N = %u;\n", N); unsigned int i; float theta=0.0f, dtheta=2*M_PI*fc; unsigned int ix=0, iy=0; float complex x, y[2]; for (i=0; i #include // slow implementation of byte reversal unsigned char reverse_byte(unsigned char _x) { unsigned char y = 0x00; unsigned int i; for (i=0; i<8; i++) { y <<= 1; y |= _x & 1; _x >>= 1; } return y; } int main() { printf("// auto-generated file (do not edit)\n"); printf("\n"); printf("// reverse byte table\n"); printf("unsigned const char liquid_reverse_byte[256] = {\n "); unsigned int i; for (i=0; i<256; i++) { // reverse byte unsigned char byte_rev = reverse_byte((unsigned char)i); // print results printf("0x%.2x", byte_rev); if ( i != 255 ) { printf(","); if ( ((i+1)%8)==0 ) printf("\n "); else printf(" "); } } printf("};\n\n"); return 0; } liquid-dsp-1.7.0/sandbox/rhamming_test.c000066400000000000000000000063161474751757600202720ustar00rootroot00000000000000// Design (approximate) square-root Nyquist Hamming filter #include #include #include #include "liquid.internal.h" #define OUTPUT_FILENAME "rhamming_test.m" float bisect_search(int _wtype, unsigned int _k, unsigned int _m, float _arg, float * _h, int _verbose); float bisect_eval (int _wtype, unsigned int _k, unsigned int _m, float _arg, float * _h, float _gamma); int main() { // options unsigned int k = 2; unsigned int m = 12; int wtype = LIQUID_WINDOW_HAMMING; float arg = 0; int verbose = 1; // derived values unsigned int h_len = 2*k*m+1; float h[h_len]; float gamma_opt = bisect_search(wtype, k, m, arg, h, verbose); printf(" k:%2u, m:%2u, gamma:%12.8f\n", k, m, gamma_opt); // re-design with optimum and save to file //printf("optimum RMS ISI of %.2f dB with gamma=%.6f\n", 20*log10(isi_opt), gamma_opt); liquid_firdes_windowf(wtype,h_len,gamma_opt*0.5f/(float)k,arg,h); FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"k = %u; m = %u; h = zeros(2*k*m+1,1);\n", k, m); fprintf(fid,"h = ["); unsigned int i; for (i=0; i #include #include #include "liquid.internal.h" #define DEBUG 0 #define OUTPUT_FILENAME "rkaiser2_test.m" struct gsuserdata_s { unsigned int k; // samples/symbol unsigned int m; // filter delay (symbols) float beta; // excess bandwidth factor float dt; // fractional delay float w0; // weighting for ISI float w1; // weighting for stop-band attenuation }; // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] void liquid_firdes_rkaiser_filter2(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h); // gradient search utility float gs_utility(void * _userdata, float * _h, unsigned int _n); int main() { // options unsigned int k=2; unsigned int m=5; float beta = 0.3; float dt = 0.0; // derived values unsigned int h_len = 2*k*m+1; float h1[h_len]; float h2[h_len]; liquid_firdes_rkaiser(k,m,beta,dt,h1); liquid_firdes_rkaiser_filter2(k,m,beta,dt,h2); // print filters // export results FILE * fid = fopen(OUTPUT_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); fprintf(fid,"\n"); fprintf(fid,"k = %u;\n", k); fprintf(fid,"m = %u;\n", m); fprintf(fid,"beta = %12.8f;\n", beta); fprintf(fid,"n = 2*k*m+1;\n"); fprintf(fid,"h1 = zeros(1,n);\n"); fprintf(fid,"h2 = zeros(1,n);\n"); unsigned int i; for (i=0; i= 1.0f) { fprintf(stderr,"error: liquid_firdes_rkaiser(), beta must be in (0,1)\n"); exit(1); } else if (_dt < -1.0f || _dt > 1.0f) { fprintf(stderr,"error: liquid_firdes_rkaiser(), dt must be in [-1,1]\n"); exit(1); } unsigned int h_len = 2*_k*_m + 1; // #if 0 float fc = 0.5*(1.0 + _beta)/(float)(_k); float as = 40.0f; #else float rho_hat = rkaiser_approximate_rho(_m,_beta); float fc = 0.5f*(1 + _beta*(1.0f-rho_hat))/(float)_k; // filter cutoff float del = _beta*rho_hat / (float)_k; // transition bandwidth float as = estimate_req_filter_As(del, h_len); // stop-band suppression // reduce slightly to help ensure solution isn't stuck // (not really necessary) fc *= 0.995f; as -= 1.0f; #endif float v[2] = {fc, as/1000}; struct gsuserdata_s q = { .k = _k, .m = _m, .beta = _beta, .dt = _dt, .w0 = 0.5f, .w1 = 0.5f}; // create gradsearch object gradsearch gs = gradsearch_create((void*)&q, v, 2, // vector optimizer gs_utility, LIQUID_OPTIM_MINIMIZE); // run search unsigned int i; unsigned int num_iterations = 100; for (i=0; iw0; float w1 = q->w1; unsigned int k = q->k; unsigned int m = q->m; float beta = q->beta; float dt = q->dt; unsigned int nfft=512; // parameters float fc = _v[0]; float as = _v[1]*1000; // derived values unsigned int h_len = 2*k*m+1; // utilities float u0 = 0.0; float u1 = 0.0; // compute filter float h[h_len]; liquid_firdes_kaiser(h_len,fc,as,dt,h); // normalize coefficients float e2 = 0.0f; unsigned int i; for (i=0; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "shadowing_test.m" int main(int argc, char*argv[]) { srand(time(NULL)); // properties unsigned int num_samples = 80e3; float sigma = 1.0f; float fd = 0.02f; unsigned int nfft = 2400; // spectral periodogram FFT size // generate Doppler filter #if 1 float alpha = fd; float a[2] = {1.0f, alpha-1.0f}; float b[2] = {alpha, 0}; iirfilt_rrrf filter = iirfilt_rrrf_create(b,2,a,2); #else iirfilt_rrrf filter = iirfilt_rrrf_create_lowpass(11,fd); #endif unsigned int i; // output channel gain float G[num_samples]; // generate samples for (i=0; i #include #include "liquid.h" void matrixf_pivot2(float * _x, unsigned int _m, unsigned int _n, unsigned int _i, unsigned int _j) { float v = 1.0f / matrix_access(_x,_m,_n,_i,_j); float g; // multiplier unsigned int r,c; for (r=0; r<_m; r++) { // skip over pivot row if (r == _i) continue; // compute multiplier g = matrix_access(_x,_m,_n,r,_j) * v; // back-substitution for (c=0; c<_n; c++) { matrix_access(_x,_m,_n,r,c) -= matrix_access(_x,_m,_n,_i,c)*g; } } // normalize row by multiplier for (c=0; c<_n; c++) matrix_access(_x,_m,_n,_i,c) *= v; } int main() { // problem definition float x[18] = { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 4.0f, 0.0f, 1.0f, 2.0f, 0.0f, 1.0f, 3.0f }; unsigned int r = 3; unsigned int c = 6; matrixf_print(x,r,c); // pivot around x(1,1) = 2 matrixf_pivot2(x,r,c, 1,1); matrixf_print(x,r,c); // pivot around x(2,2) = 1.5 matrixf_pivot2(x,r,c, 2,2); matrixf_print(x,r,c); // print solution printf("solution:\n"); printf("z : %12.8f\n", matrixf_access(x,r,c,0,c-1)); unsigned int i; for (i=1; i #include #include #include //#include #include "liquid.h" #define DEBUG 1 int main() { // problem definition // sig1 = sqrt(1248) // sig2 = 20 // sig3 = sqrt(384) // sig4 = 0 // sig5 = 0 float a[40] = { 22, 10, 2, 3, 7, 14, 7, 10, 0, 8, -1, 13, -1, -11, 3, -3, -2, 13, -2, 4, 9, 8, 1, -2, 4, 9, 1, -7, 5, -1, 2, -6, 6, 5, 1, 4, 5, 0, -2, 2}; // NOTE: m >= n unsigned int m = 8; unsigned int n = 5; #if 0 // initialize as random matrix unsigned int ii; for (ii=0; ii x) x = y; } // accumulation of right-hand transformations for (i=n-1; i>=0; i--) { //if (g != 0) { if ( fabs(g) > 1e-3 ) { h = matrix_access(u,m,n,i,i+1)*g; for (j=l; j=0; i--) { l = i+1; g = q[i]; for (j=l; j 1e-3 ) { h = matrix_access(u,m,n,i,i) * g; for (j=l; j=0; k--) { if (k==(n-2)) { printf("...\n"); break; } test_f_splitting: printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"); printf("test f splitting\n"); printf(" k = %u\n", k); t--; if (t==0) { fprintf(stderr,"***********************************************\n"); fprintf(stderr," bailing\n"); fprintf(stderr,"***********************************************\n"); t=10; continue; } for (l=k; l>0; l--) { printf(" e[%3u] = %12.4e, q[%3u] = %12.4e (eps: %12.4e)\n", l, e[l], l-1, q[l-1], eps); if ( fabs(e[l]) <= eps ) goto test_f_convergence; if ( fabs(q[l-1]) <= eps ) goto cancellation; } // for l // FIXME: figure out logic here (need to set l > 0) l = 1; // cancellation of e[l] if l>0 cancellation: printf("cancellation\n"); c = 0; s = 1; l1 = l-1; for (i=l; i %f, f -> %f\n", g, f); // next QR transformation c = 1; s = 1; for (i=l+1; i #include #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symsync_crcf_test.m" // print usage/help message void usage() { printf("symsync_crcf_test [options]\n"); printf(" u/h : print usage\n"); printf(" T : filter type: rrcos, rkaiser, [arkaiser], hM3, gmsk\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" B : filter polyphase banks, default: 32\n"); printf(" s : signal-to-noise ratio, default: 30dB\n"); printf(" w : timing pll bandwidth, default: 0.02\n"); printf(" n : number of symbols, default: 200\n"); printf(" t : timing phase offset [%% symbol], t in [-0.5,0.5], default: -0.2\n"); } // filter coefficients // alpha zeta settling time (symbols) // 0.90 1.5 70 // 0.92 1.4 100 // 0.94 1.2 110 // 0.96 0.5 140 // 0.98 0.2 210 // 0.985 0.08 410 // 0.990 0.05 500 // 0.995 0.01 1100 // 0.998 0.002 2500 // // Let bandwidth = 1/settling time, int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // samples/symbol (input) unsigned int m=3; // filter delay (symbols) float beta=0.5f; // filter excess bandwidth factor unsigned int npfb=32; // number of filters in the bank unsigned int num_symbols=512; // number of data symbols float SNRdB = 30.0f; // signal-to-noise ratio liquid_firfilt_type ftype_tx = LIQUID_FIRFILT_ARKAISER; liquid_firfilt_type ftype_rx = LIQUID_FIRFILT_ARKAISER; float bt=0.02f; // loop filter bandwidth float tau=-0.2f; // fractional symbol offset int dopt; while ((dopt = getopt(argc,argv,"uhT:m:b:B:s:w:n:t:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; case 'T': if (strcmp(optarg,"gmsk")==0) { ftype_tx = LIQUID_FIRFILT_GMSKTX; ftype_rx = LIQUID_FIRFILT_GMSKRX; } else { ftype_tx = liquid_getopt_str2firfilt(optarg); ftype_rx = liquid_getopt_str2firfilt(optarg); } if (ftype_tx == LIQUID_FIRFILT_UNKNOWN) { fprintf(stderr,"error: %s, unknown filter type '%s'\n", argv[0], optarg); exit(1); } break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'B': npfb = atoi(optarg); break; case 's': SNRdB = atof(optarg); break; case 'w': bt = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; case 't': tau = atof(optarg); break; default: exit(1); } } // validate input if (m < 1) { fprintf(stderr,"error: m (filter delay) must be greater than 0\n"); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: beta (excess bandwidth factor) must be in (0,1]\n"); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: number of polyphase filters must be greater than 0\n"); exit(1); } else if (bt <= 0.0f) { fprintf(stderr,"error: timing PLL bandwidth must be greater than 0\n"); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: number of symbols must be greater than 0\n"); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: timing phase offset must be in [-1,1]\n"); exit(1); } unsigned int i; unsigned int num_samples = k*num_symbols; float complex sym_in[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // noisy samples float complex sym_out[num_symbols + 64]; // synchronized symbols // generate random QPSK symbols for (i=0; i npfb-1) { pfb_index -= npfb; pfb_soft -= npfb; pfb_timer++; } // save debugging outputs debug_pfb_error[n] = pfb_error; debug_pfb_q[n] = pfb_q; debug_pfb_soft[n] = pfb_soft; // increment output counter n++; } // decrement timer pfb_timer--; } // destroy filterbanks firpfb_crcf_destroy(mf); firpfb_crcf_destroy(dmf); // print last several symbols to screen printf("output symbols:\n"); for (i=n-10; i #include #include #include #include #include #include "liquid.h" #define OUTPUT_FILENAME "symsync_eqlms_test.m" // print usage/help message void usage() { printf("symsync_eqlms_test [options]\n"); printf(" u/h : print usage\n"); // transmit filter properties printf(" k : filter samples/symbol, default: 2\n"); printf(" m : filter delay (symbols), default: 3\n"); printf(" b : filter excess bandwidth, default: 0.5\n"); printf(" n : number of symbols, default: 400\n"); // symsync properties printf(" B : filter polyphase banks, default: 32\n"); printf(" w : timing pll bandwidth, default: 0.02\n"); // equalizer properties printf(" p : equalizer order [symbols], default: 3\n"); printf(" W : equalizer bandwidth, default: 0.05\n"); // channel printf(" s : signal-to-noise ratio, default: 30dB\n"); printf(" c : channel impulse response length, default: 5\n"); printf(" t : timing phase offset [%% symbol], -0.5 < t <= 0.5, default: 0\n"); } int main(int argc, char*argv[]) { srand(time(NULL)); // options unsigned int k=2; // samples/symbol (input) unsigned int m=3; // filter delay (symbols) float beta=0.5f; // filter excess bandwidth factor unsigned int npfb=32; // number of filters in the bank unsigned int p=3; // equalizer length (symbols, hp_len = 2*k*p+1) float mu = 0.05f; // equalizer learning rate unsigned int num_symbols=500; // number of data symbols unsigned int hc_len=5; // channel filter length float SNRdB = 30.0f; // signal-to-noise ratio liquid_firfilt_type ftype = LIQUID_FIRFILT_ARKAISER; float bt=0.05f; // symbol synchronizer loop filter bandwidth float tau=-0.1f; // fractional symbol offset int dopt; while ((dopt = getopt(argc,argv,"uhk:m:b:n:B:w:p:W:s:c:t:")) != EOF) { switch (dopt) { case 'u': case 'h': usage(); return 0; // transmit filter properties case 'k': k = atoi(optarg); break; case 'm': m = atoi(optarg); break; case 'b': beta = atof(optarg); break; case 'n': num_symbols = atoi(optarg); break; // symsync properties case 'B': npfb = atoi(optarg); break; case 'w': bt = atof(optarg); break; // equalizer properties case 'p': p = atoi(optarg); break; case 'W': mu = atof(optarg); break; // equalizer properties case 's': SNRdB = atof(optarg); break; case 'c': hc_len = atoi(optarg); break; case 't': tau = atof(optarg); break; default: exit(1); } } // validate input if (k < 2) { fprintf(stderr,"error: %s,k (samples/symbol) must be at least 2\n", argv[0]); exit(1); } else if (m < 1) { fprintf(stderr,"error: %s,m (filter delay) must be greater than 0\n", argv[0]); exit(1); } else if (beta <= 0.0f || beta > 1.0f) { fprintf(stderr,"error: %s,beta (excess bandwidth factor) must be in (0,1]\n", argv[0]); exit(1); } else if (num_symbols == 0) { fprintf(stderr,"error: %s,number of symbols must be greater than 0\n", argv[0]); exit(1); } else if (npfb == 0) { fprintf(stderr,"error: %s,number of polyphase filters must be greater than 0\n", argv[0]); exit(1); } else if (bt < 0.0f) { fprintf(stderr,"error: %s,timing PLL bandwidth cannot be negative\n", argv[0]); exit(1); } else if (p == 0) { fprintf(stderr,"error: %s, equalizer order must be at least 1\n", argv[0]); exit(1); } else if (mu < 0.0f || mu > 1.0f) { fprintf(stderr,"error: %s, equalizer learning rate must be in [0,1]\n", argv[0]); exit(1); } else if (hc_len < 1) { fprintf(stderr,"error: %s, channel response must have at least 1 tap\n", argv[0]); exit(1); } else if (tau < -1.0f || tau > 1.0f) { fprintf(stderr,"error: %s,timing phase offset must be in [-1,1]\n", argv[0]); exit(1); } // derived values unsigned int ht_len = 2*k*m+1; // transmit filter order unsigned int hp_len = 2*k*p+1; // equalizer order float nstd = powf(10.0f, -SNRdB/20.0f); float dt = tau; // fractional sample offset unsigned int ds = 0; // full sample delay unsigned int i; unsigned int num_samples = k*num_symbols; float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples]; // channel output float complex z[k*num_symbols + 64]; // synchronized samples float complex sym_out[num_symbols + 64]; // synchronized symbols for (i=0; i 0.0f ? M_SQRT1_2 : -M_SQRT1_2) + (cimagf(d_hat) > 0.0f ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; // update equalizer eqlms_cccf_step(eq, d_prime, d_hat); } // get equalizer weights eqlms_cccf_copy_coefficients(eq, hp); // destroy equalizer object eqlms_cccf_destroy(eq); // print last several symbols to screen printf("output symbols:\n"); for (i=num_symbols_sync-10; i #include #include #include #include "liquid.internal.h" void compute_thiran_allpass(unsigned int _n, float _mu, float * _b, float * _a); int main() { unsigned int n = 4; float mu = 0.1f; float b[n+1]; float a[n+1]; // compute filter coefficients compute_thiran_allpass(n,mu,b,a); // print coefficients to screen unsigned int i; for (i=0; i<=n; i++) printf("a(%3u) = %12.8f; b(%3u) = %12.8f;\n", i+1, a[i], i+1, b[i]); // compute group delay float g = iir_group_delay(b,n+1,a,n+1,0.0f); printf(" g = %f\n", g); printf("done.\n"); return 0; } void compute_thiran_allpass(unsigned int _n, float _mu, float * _b, float * _a) { float nf = (float)_n; unsigned int k; for (k=0; k<=_n; k++) { _a[k] = ((k%2)==0 ? 1.0f : -1.0f) * liquid_nchoosek(_n, k); // check condition when mu is very small (eliminate divide-by-zero) if ( fabsf(_mu) < 1e-6f ) { _a[k] = _a[k]*_a[k]; continue; } // TODO : expand as sum of logarithms unsigned int n; for (n=0; n<=_n; n++) { _a[k] *= (_mu - nf + (float)n) / (_mu - nf + (float)(n+k)); } } for (k=0; k<=_n; k++) _b[k] = _a[_n-k]; } liquid-dsp-1.7.0/sandbox/throttle_test.c000066400000000000000000000037021474751757600203310ustar00rootroot00000000000000// // throttle_test.c // // Test throttling down processor to reach target rate by inserting sleep // statements in between processing blocks // #include #include #include #include #include #include #include "liquid.h" int main() { // options float target_rate = 200e3f; // target processing rate [samples/second] // design filter from prototype firfilt_crcf filter = firfilt_crcf_create_kaiser(25, 0.25f, 60.0f, 0.0f); // generate dummy buffers for processing unsigned int buf_len = 1024; float complex buf_0[buf_len]; float complex buf_1[buf_len]; memset(buf_0, 0x00, buf_len*sizeof(complex float)); // run with updates struct timespec t0, t1; float sleep_time = 200.0f; // initial guess unsigned int i; for (i=0; i<100; i++) { // run block of samples for 200 ms unsigned int num_samples_processed = 0; clock_gettime(CLOCK_REALTIME, &t0); float block_time = 0; while (block_time < 0.2) { // process a block of samples firfilt_crcf_execute_block(filter, buf_0, buf_len, buf_1); num_samples_processed += buf_len; // throttle by calling sleep usleep((unsigned int)sleep_time); // update time reference clock_gettime(CLOCK_REALTIME, &t1); block_time = t1.tv_sec - t0.tv_sec + 1e-9*(t1.tv_nsec - t0.tv_nsec); } // get processing rate float rate = (float)num_samples_processed / block_time; printf(" %6u, rate = %12.3f k (target = %12.3f k), sleep time = %12.1f us\r", i, rate*1e-3f, target_rate*1e-3f, sleep_time); fflush(stdout); // adjust sleep time proportional to deviation from target rate sleep_time *= expf(0.2f*logf(rate/target_rate)); } printf("\n"); // destroy filter object firfilt_crcf_destroy(filter); return 0; } liquid-dsp-1.7.0/sandbox/vectorcf_test.c000066400000000000000000000012461474751757600203000ustar00rootroot00000000000000// // vectorcf_test.c : test complex floating-point vector operations // #include #include #include #include //#include #include "liquid.h" int main() { // options unsigned int n = 64; // unsigned int i; float complex v[n]; for (i=0; i #include #include #include "autoscript.h" #define NAME_LEN (256) #define AUTOSCRIPT_VERSION "0.3.1" #define DEBUG_AUTOSCRIPT 0 struct script_s { char name[NAME_LEN]; struct package_s * package; }; struct package_s { char name[NAME_LEN]; char filename[NAME_LEN]; struct script_s * scripts; unsigned int num_scripts; }; struct autoscript_s { char type[NAME_LEN]; char delim; unsigned int num_packages; struct package_s * packages; }; // create autoscript generator object autoscript autoscript_create(char * _type, char _delim) { autoscript q = (autoscript) malloc(sizeof(struct autoscript_s)); // copy type and delimiter (path separator) strncpy(q->type, _type, NAME_LEN-1); q->type[NAME_LEN-1] = '\0'; q->delim = _delim; q->num_packages = 0; q->packages = NULL; return q; } void autoscript_destroy(autoscript _q) { // free all internal scripts unsigned int i; for (i=0; i<_q->num_packages; i++) { if (_q->packages[i].scripts != NULL) free(_q->packages[i].scripts); } // free all internal packages if (_q->packages != NULL) free(_q->packages); // free main object memory free(_q); } // parse filename and file void autoscript_parse(autoscript _q, char * _filename) { #if DEBUG_AUTOSCRIPT fprintf(stderr,"autoscript_parse('%s')...\n", _filename); #endif char package_name[NAME_LEN]; // parse filename... autoscript_parsefilename(_q, _filename, package_name); // parse actual file... autoscript_parsefile(_q, _filename, package_name); } void autoscript_print(autoscript _q) { unsigned int i; unsigned int j; unsigned int n; // count total number of scripts unsigned int num_scripts = 0; for (i=0; i<_q->num_packages; i++) num_scripts += _q->packages[i].num_scripts; // print header printf("// auto-generated file, do not edit\n"); printf("// invoked with script type '%s' and delimiter '%c'\n", _q->type, _q->delim); printf("// the following types need to be defined externally:\n"); printf("// typedef ...(%s_function_t)(...);\n", _q->type); printf("// typedef struct {\n"); printf("// unsigned int id; // script identification number\n"); printf("// %s_function_t * api; // pointer to function API\n", _q->type); printf("// const char * name; // script name\n"); printf("// ...\n"); printf("// } %s_t;\n", _q->type); printf("// typedef struct {\n"); printf("// unsigned int id; // package identification number\n"); printf("// unsigned int index; // index of first script\n"); printf("// unsigned int n; // number of scripts in package\n"); printf("// const char * name; // name of package\n"); printf("// } package_t;\n"); printf("\n"); printf("#ifndef __LIQUID_AUTOSCRIPT_INCLUDE_H__\n"); printf("#define __LIQUID_AUTOSCRIPT_INCLUDE_H__\n\n"); printf("#define AUTOSCRIPT_VERSION \"%s\"\n\n", AUTOSCRIPT_VERSION); printf("// number of packages\n"); printf("#define NUM_PACKAGES (%u)\n\n", _q->num_packages); printf("// number of scripts\n"); printf("#define NUM_AUTOSCRIPTS (%u)\n\n", num_scripts); printf("// function declarations\n"); for (i=0; i<_q->num_packages; i++) { struct package_s * p = &_q->packages[i]; printf("// %s\n", p->filename); #if 0 for (j=0; jnum_scripts; j++) printf("void benchmark_%s(AUTOSCRIPT_ARGS);\n", p->scripts[j].name); #else for (j=0; jnum_scripts; j++) printf("%s_function_t %s_%s;\n", _q->type, _q->type, p->scripts[j].name); #endif } printf("\n"); // find longest name unsigned int max_len = 0; for (i=0; i<_q->num_packages; i++) { //struct package_s * p = &_q->packages[i]; for (j=0; j<_q->packages[i].num_scripts; j++) { unsigned int str_len = strlen(_q->packages[i].scripts[j].name); max_len = str_len > max_len ? str_len : max_len; } } char space[max_len+1]; memset(space, ' ', max_len); space[max_len] = '\0'; printf("// array of scripts\n"); printf("%s_t scripts[NUM_AUTOSCRIPTS] = {\n", _q->type); n=0; for (i=0; i<_q->num_packages; i++) { struct package_s * p = &_q->packages[i]; for (j=0; jnum_scripts; j++) { // print formatting line, adding appropriate space to align columns printf(" {.id = %4u, .api = &%s_%s,%s .name = \"%s\"}", n, _q->type, p->scripts[j].name, &space[strlen(p->scripts[j].name)], p->scripts[j].name); if ( n < num_scripts-1 ) printf(","); printf("\n"); n++; } } printf("};\n\n"); n=0; printf("// array of packages\n"); printf("package_t packages[NUM_PACKAGES] = {\n"); for (i=0; i<_q->num_packages; i++) { printf(" {.id = %4u, .index = %4u, .num_scripts = %4u, .name = \"%s\"}", i, n, _q->packages[i].num_scripts, _q->packages[i].name); if (i<_q->num_packages-1) printf(","); printf("\n"); n += _q->packages[i].num_scripts; } printf("};\n\n"); printf("#endif // __LIQUID_AUTOSCRIPT_INCLUDE_H__\n\n"); } // // internal methods // // parse filename // _q : generator object // _filename : name of file // _package_name : output package name (stripped filename) void autoscript_parsefilename(autoscript _q, char * _filename, char * _package_name) { #if DEBUG_AUTOSCRIPT fprintf(stderr,"autoscript_parsefilename('%s')...\n", _filename); #endif char * sptr; // pointer to base name char * tptr; // pointer to terminating tag char pathsep = _q->delim; // path separator character // generate tag (e.g. "_benchmark") unsigned int tag_len = strlen(_q->type) + 2; char tag[tag_len]; tag[0] = '_'; strcpy(tag+1, _q->type); tag[tag_len-1] = '\0'; //printf("// tag : '%s'\n", tag); // try to strip out path: find rightmost occurrence of pathsep //printf("%s\n", _filename); sptr = strrchr(_filename, pathsep); // obtain index of last pathsep if (sptr == NULL) { // path delimiter not found sptr = _filename; } else { sptr++; // increment to remove path separator character } // try to strip out tag tptr = strstr( sptr, tag ); if (tptr == NULL) { // TODO : handle this case differently otherwise fprintf(stderr,"error: autoscript_parsefilename('%s'), tag '%s' not found\n", _filename, tag); exit(1); } // copy base name to output int n = tptr - sptr; strncpy(_package_name, sptr, n); _package_name[n] = '\0'; //printf("// package name : '%s'\n", _package_name); } // parse file // _q : generator object // _filename : name of file // _package_name : input package name (stripped filename) void autoscript_parsefile(autoscript _q, char * _filename, char * _package_name) { // flag indicating if package has been added or not int package_added = 0; #if DEBUG_AUTOSCRIPT fprintf(stderr,"autoscript_parsefile('%s')...\n", _filename); #endif // try to open file... FILE * fid = fopen(_filename,"r"); if (!fid) { fprintf(stderr,"error: autoscript_parsefile('%s'), could not open file for reading\n", _filename); exit(1); } // generate tag (e.g. "void benchmark_"); unsigned int tag_len = 5 + strlen(_q->type) + 2; char tag[tag_len]; sprintf(tag, "void %s_", _q->type); // parse file, looking for key char buffer[1024]; // line buffer char basename[1024]; // base script name char * cptr = NULL; // readline return value char * sptr = NULL; // tag string pointer int cterm; // terminating character unsigned int n=0; // line number do { // increment line number n++; // read line cptr = fgets(buffer, 1024, fid); if (cptr != NULL) { // search for key sptr = strstr(cptr, tag); if (sptr == NULL) { // no value found continue; } // key found: find terminating character and strip out base name sptr += strlen(tag); // increment string by tag length cterm = strcspn( sptr, " (\t\n\r" ); if (cterm == strlen(sptr)) { // no terminating character found continue; } // copy base name strncpy( basename, sptr, cterm ); basename[cterm] = '\0'; //printf("// line %3u : '%s'\n", n, basename); // key found: add package if not already done if (!package_added) { // TODO : add base name autoscript_addpackage(_q, _package_name, _filename); package_added = 1; } autoscript_addscript(_q, _package_name, basename); printf("// adding %s to package %s from %s:%u\n", basename, _package_name, _filename, n); } } while (!feof(fid)); // close file fclose(fid); } void autoscript_addpackage(autoscript _q, char * _package_name, char * _filename) { // verify that package name is unique with existing scripts unsigned int i; for (i=0; i<_q->num_packages; i++) { if (strcmp(_q->packages[i].name, _package_name)==0) { fprintf(stderr,"error: duplicate package name '%s', defined in:\n", _package_name); fprintf(stderr," %s\n", _q->packages[i].filename); fprintf(stderr," %s\n", _filename); exit(1); } } // increase package size _q->num_packages++; // re-allocate memory for packages _q->packages = (struct package_s *) realloc(_q->packages, _q->num_packages*sizeof(struct package_s)); // initialize new package strncpy(_q->packages[_q->num_packages-1].name, _package_name, NAME_LEN-1); _q->packages[_q->num_packages-1].name[NAME_LEN-1] = '\0'; // initialize new package strncpy(_q->packages[_q->num_packages-1].filename, _filename, NAME_LEN-1); _q->packages[_q->num_packages-1].filename[NAME_LEN-1] = '\0'; // initialize number of scripts _q->packages[_q->num_packages-1].num_scripts = 0; // set scripts pointer to NULL _q->packages[_q->num_packages-1].scripts = NULL; } void autoscript_addscript(autoscript _q, char * _package_name, char * _script_name) { // first validate that package exists unsigned int i; int package_found = 0; for (i=0; i<_q->num_packages; i++) { if ( strcmp(_q->packages[i].name, _package_name)==0 ) { package_found = 1; break; } } if (!package_found) { fprintf(stderr,"error: autoscript_addscript(), unknown package '%s'\n", _package_name); exit(1); } struct package_s * p = &_q->packages[i]; // increase script size p->num_scripts++; // re-allocate memory for scripts p->scripts = (struct script_s *) realloc(p->scripts, p->num_scripts*sizeof(struct script_s)); // initialize new script strncpy(p->scripts[p->num_scripts-1].name, _script_name, NAME_LEN-1); p->scripts[p->num_scripts-1].name[NAME_LEN-1] = '\0'; // associate script with package //_q->scripts[_q->num_scripts-1].package = &_q->packages[i]; } liquid-dsp-1.7.0/scripts/autoscript.h000066400000000000000000000046461474751757600176700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef __LIQUID_AUTOSCRIPT_H__ #define __LIQUID_AUTOSCRIPT_H__ typedef struct autoscript_s * autoscript; // create autoscript generator object autoscript autoscript_create(char * _type, char _delim); // parse file void autoscript_parse(autoscript _q, char * _filename); void autoscript_print(autoscript _q); void autoscript_destroy(autoscript _q); // // internal methods // // parse filename // _q : generator object // _filename : name of file // _package_name : output package name (stripped filename) void autoscript_parsefilename(autoscript _q, char * _filename, char * _package_name); // parse file // _q : generator object // _filename : name of file // _package_name : input package name (stripped filename) void autoscript_parsefile(autoscript _q, char * _filename, char * _package_name); void autoscript_addpackage(autoscript _q, char * _package_name, char * _filename); void autoscript_addscript(autoscript _q, char * _package_name, char * _script_name); #endif // __LIQUID_AUTOSCRIPT_H__ liquid-dsp-1.7.0/scripts/ax_check_compile_flag.m4000066400000000000000000000062511474751757600220240ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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, either 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 for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 2 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS liquid-dsp-1.7.0/scripts/ax_ext.m4000066400000000000000000000361161474751757600170510ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_ext.html # =========================================================================== # # SYNOPSIS # # AX_EXT # # DESCRIPTION # # Find supported SIMD extensions by requesting cpuid. When a SIMD # extension is found, the -m"simdextensionname" is added to SIMD_FLAGS if # compiler supports it. For example, if "sse2" is available then "-msse2" # is added to SIMD_FLAGS. # # Find other supported CPU extensions by requesting cpuid. When a # processor extension is found, the -m"extensionname" is added to # CPUEXT_FLAGS if compiler supports it. For example, if "bmi2" is # available then "-mbmi2" is added to CPUEXT_FLAGS. # # This macro calls: # # AC_SUBST(SIMD_FLAGS) # AC_SUBST(CPUEXT_FLAGS) # # And defines: # # HAVE_RDRND / HAVE_BMI1 / HAVE_BMI2 / HAVE_ADX / HAVE_MPX # HAVE_PREFETCHWT1 / HAVE_ABM / HAVE_MMX / HAVE_SSE / HAVE_SSE2 # HAVE_SSE3 / HAVE_SSSE3 / HAVE_SSE4_1 / HAVE_SSE4_2 / HAVE_SSE4a # HAVE_SHA / HAVE_AES / HAVE_AVX / HAVE_FMA3 / HAVE_FMA4 / HAVE_XOP # HAVE_AVX2 / HAVE_AVX512_F / HAVE_AVX512_CD / HAVE_AVX512_PF # HAVE_AVX512_ER / HAVE_AVX512_VL / HAVE_AVX512_BW / HAVE_AVX512_DQ # HAVE_AVX512_IFMA / HAVE_AVX512_VBMI / HAVE_ALTIVEC / HAVE_VSX # # LICENSE # # Copyright (c) 2007 Christophe Tournayre # Copyright (c) 2013,2015 Michael Petch # Copyright (c) 2017 Rafael de Lucena Valle # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 18 AC_DEFUN([AX_EXT], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_CC]) CPUEXT_FLAGS="" SIMD_FLAGS="" case $host_cpu in powerpc*) AC_CACHE_CHECK([whether altivec is supported for old distros], [ax_cv_have_altivec_old_ext], [ if test `/usr/sbin/sysctl -a 2>/dev/null| grep -c hw.optional.altivec` != 0; then if test `/usr/sbin/sysctl -n hw.optional.altivec` = 1; then ax_cv_have_altivec_old_ext=yes fi fi ]) if test "$ax_cv_have_altivec_old_ext" = yes; then AC_DEFINE(HAVE_ALTIVEC,,[Support Altivec instructions]) AX_CHECK_COMPILE_FLAG(-faltivec, SIMD_FLAGS="$SIMD_FLAGS -faltivec", []) fi AC_CACHE_CHECK([whether altivec is supported], [ax_cv_have_altivec_ext], [ if test `LD_SHOW_AUXV=1 /bin/true 2>/dev/null|grep -c altivec` != 0; then ax_cv_have_altivec_ext=yes fi ]) if test "$ax_cv_have_altivec_ext" = yes; then AC_DEFINE(HAVE_ALTIVEC,,[Support Altivec instructions]) AX_CHECK_COMPILE_FLAG(-maltivec, SIMD_FLAGS="$SIMD_FLAGS -maltivec", []) fi AC_CACHE_CHECK([whether vsx is supported], [ax_cv_have_vsx_ext], [ if test `LD_SHOW_AUXV=1 /bin/true 2>/dev/null|grep -c vsx` != 0; then ax_cv_have_vsx_ext=yes fi ]) if test "$ax_cv_have_vsx_ext" = yes; then AC_DEFINE(HAVE_VSX,,[Support VSX instructions]) AX_CHECK_COMPILE_FLAG(-mvsx, SIMD_FLAGS="$SIMD_FLAGS -mvsx", []) fi ;; i[[3456]]86*|x86_64*|amd64*) AC_REQUIRE([AX_GCC_X86_CPUID]) AC_REQUIRE([AX_GCC_X86_CPUID_COUNT]) AC_REQUIRE([AX_GCC_X86_AVX_XGETBV]) eax_cpuid0=0 AX_GCC_X86_CPUID(0x00000000) if test "$ax_cv_gcc_x86_cpuid_0x00000000" != "unknown"; then eax_cpuid0=`echo $ax_cv_gcc_x86_cpuid_0x00000000 | cut -d ":" -f 1` fi eax_cpuid80000000=0 AX_GCC_X86_CPUID(0x80000000) if test "$ax_cv_gcc_x86_cpuid_0x80000000" != "unknown"; then eax_cpuid80000000=`echo $ax_cv_gcc_x86_cpuid_0x80000000 | cut -d ":" -f 1` fi ecx_cpuid1=0 edx_cpuid1=0 if test "$((0x$eax_cpuid0))" -ge 1 ; then AX_GCC_X86_CPUID(0x00000001) if test "$ax_cv_gcc_x86_cpuid_0x00000001" != "unknown"; then ecx_cpuid1=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 3` edx_cpuid1=`echo $ax_cv_gcc_x86_cpuid_0x00000001 | cut -d ":" -f 4` fi fi ebx_cpuid7=0 ecx_cpuid7=0 if test "$((0x$eax_cpuid0))" -ge 7 ; then AX_GCC_X86_CPUID_COUNT(0x00000007, 0x00) if test "$ax_cv_gcc_x86_cpuid_0x00000007" != "unknown"; then ebx_cpuid7=`echo $ax_cv_gcc_x86_cpuid_0x00000007 | cut -d ":" -f 2` ecx_cpuid7=`echo $ax_cv_gcc_x86_cpuid_0x00000007 | cut -d ":" -f 3` fi fi ecx_cpuid80000001=0 edx_cpuid80000001=0 if test "$((0x$eax_cpuid80000000))" -ge "$((0x80000001))" ; then AX_GCC_X86_CPUID(0x80000001) if test "$ax_cv_gcc_x86_cpuid_0x80000001" != "unknown"; then ecx_cpuid80000001=`echo $ax_cv_gcc_x86_cpuid_0x80000001 | cut -d ":" -f 3` edx_cpuid80000001=`echo $ax_cv_gcc_x86_cpuid_0x80000001 | cut -d ":" -f 4` fi fi AC_CACHE_VAL([ax_cv_have_mmx_os_support_ext], [ ax_cv_have_mmx_os_support_ext=yes ]) ax_cv_have_none_os_support_ext=yes AC_CACHE_VAL([ax_cv_have_sse_os_support_ext], [ ax_cv_have_sse_os_support_ext=no, if test "$((0x$edx_cpuid1>>25&0x01))" = 1; then AC_LANG_PUSH([C]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include /* No way at ring1 to ring3 in protected mode to check the CR0 and CR4 control registers directly. Execute an SSE instruction. If it raises SIGILL then OS doesn't support SSE based instructions */ void sig_handler(int signum){ exit(1); } int main(){ signal(SIGILL, sig_handler); /* SSE instruction xorps %xmm0,%xmm0 */ __asm__ __volatile__ (".byte 0x0f, 0x57, 0xc0"); return 0; }]])], [ax_cv_have_sse_os_support_ext=yes], [ax_cv_have_sse_os_support_ext=no], [ax_cv_have_sse_os_support_ext=no]) AC_LANG_POP([C]) fi ]) xgetbv_eax=0 if test "$((0x$ecx_cpuid1>>28&0x01))" = 1; then AX_GCC_X86_AVX_XGETBV(0x00000000) if test x"$ax_cv_gcc_x86_avx_xgetbv_0x00000000" != x"unknown"; then xgetbv_eax=`echo $ax_cv_gcc_x86_avx_xgetbv_0x00000000 | cut -d ":" -f 1` fi AC_CACHE_VAL([ax_cv_have_avx_os_support_ext], [ ax_cv_have_avx_os_support_ext=no if test "$((0x$ecx_cpuid1>>27&0x01))" = 1; then if test "$((0x$xgetbv_eax&0x6))" = 6; then ax_cv_have_avx_os_support_ext=yes fi fi ]) fi AC_CACHE_VAL([ax_cv_have_avx512_os_support_ext], [ ax_cv_have_avx512_os_support_ext=no if test "$ax_cv_have_avx_os_support_ext" = yes; then if test "$((0x$xgetbv_eax&0xe6))" = "$((0xe6))"; then ax_cv_have_avx512_os_support_ext=yes fi fi ]) for ac_instr_info dnl in "none;rdrnd;RDRND;ecx_cpuid1,30;-mrdrnd;HAVE_RDRND;CPUEXT_FLAGS" dnl "none;bmi1;BMI1;ebx_cpuid7,3;-mbmi;HAVE_BMI1;CPUEXT_FLAGS" dnl "none;bmi2;BMI2;ebx_cpuid7,8;-mbmi2;HAVE_BMI2;CPUEXT_FLAGS" dnl "none;adx;ADX;ebx_cpuid7,19;-madx;HAVE_ADX;CPUEXT_FLAGS" dnl "none;mpx;MPX;ebx_cpuid7,14;-mmpx;HAVE_MPX;CPUEXT_FLAGS" dnl "none;prefetchwt1;PREFETCHWT1;ecx_cpuid7,0;-mprefetchwt1;HAVE_PREFETCHWT1;CPUEXT_FLAGS" dnl "none;abm;ABM;ecx_cpuid80000001,5;-mabm;HAVE_ABM;CPUEXT_FLAGS" dnl "mmx;mmx;MMX;edx_cpuid1,23;-mmmx;HAVE_MMX;SIMD_FLAGS" dnl "sse;sse;SSE;edx_cpuid1,25;-msse;HAVE_SSE;SIMD_FLAGS" dnl "sse;sse2;SSE2;edx_cpuid1,26;-msse2;HAVE_SSE2;SIMD_FLAGS" dnl "sse;sse3;SSE3;ecx_cpuid1,1;-msse3;HAVE_SSE3;SIMD_FLAGS" dnl "sse;ssse3;SSSE3;ecx_cpuid1,9;-mssse3;HAVE_SSSE3;SIMD_FLAGS" dnl "sse;sse41;SSE4.1;ecx_cpuid1,19;-msse4.1;HAVE_SSE4_1;SIMD_FLAGS" dnl "sse;sse42;SSE4.2;ecx_cpuid1,20;-msse4.2;HAVE_SSE4_2;SIMD_FLAGS" dnl "sse;sse4a;SSE4a;ecx_cpuid80000001,6;-msse4a;HAVE_SSE4a;SIMD_FLAGS" dnl "sse;sha;SHA;ebx_cpuid7,29;-msha;HAVE_SHA;SIMD_FLAGS" dnl "sse;aes;AES;ecx_cpuid1,25;-maes;HAVE_AES;SIMD_FLAGS" dnl "avx;avx;AVX;ecx_cpuid1,28;-mavx;HAVE_AVX;SIMD_FLAGS" dnl "avx;fma3;FMA3;ecx_cpuid1,12;-mfma;HAVE_FMA3;SIMD_FLAGS" dnl "avx;fma4;FMA4;ecx_cpuid80000001,16;-mfma4;HAVE_FMA4;SIMD_FLAGS" dnl "avx;xop;XOP;ecx_cpuid80000001,11;-mxop;HAVE_XOP;SIMD_FLAGS" dnl "avx;avx2;AVX2;ebx_cpuid7,5;-mavx2;HAVE_AVX2;SIMD_FLAGS" dnl "avx512;avx512f;AVX512-F;ebx_cpuid7,16;-mavx512f;HAVE_AVX512_F;SIMD_FLAGS" dnl "avx512;avx512cd;AVX512-CD;ebx_cpuid7,28;-mavx512cd;HAVE_AVX512_CD;SIMD_FLAGS" dnl "avx512;avx512pf;AVX512-PF;ebx_cpuid7,26;-mavx512pf;HAVE_AVX512_PF;SIMD_FLAGS" dnl "avx512;avx512er;AVX512-ER;ebx_cpuid7,27;-mavx512er;HAVE_AVX512_ER;SIMD_FLAGS" dnl "avx512;avx512vl;AVX512-VL;ebx_cpuid7,31;-mavx512vl;HAVE_AVX512_VL;SIMD_FLAGS" dnl "avx512;avx512bw;AVX512-BW;ebx_cpuid7,30;-mavx512bw;HAVE_AVX512_BW;SIMD_FLAGS" dnl "avx512;avx512dq;AVX512-DQ;ebx_cpuid7,17;-mavx512dq;HAVE_AVX512_DQ;SIMD_FLAGS" dnl "avx512;avx512ifma;AVX512-IFMA;ebx_cpuid7,21;-mavx512ifma;HAVE_AVX512_IFMA;SIMD_FLAGS" dnl "avx512;avx512vbmi;AVX512-VBMI;ecx_cpuid7,1;-mavx512vbmi;HAVE_AVX512_VBMI;SIMD_FLAGS" dnl # do ac_instr_os_support=$(eval echo \$ax_cv_have_$(echo $ac_instr_info | cut -d ";" -f 1)_os_support_ext) ac_instr_acvar=$(echo $ac_instr_info | cut -d ";" -f 2) ac_instr_shortname=$(echo $ac_instr_info | cut -d ";" -f 3) ac_instr_chk_loc=$(echo $ac_instr_info | cut -d ";" -f 4) ac_instr_chk_reg=0x$(eval echo \$$(echo $ac_instr_chk_loc | cut -d "," -f 1)) ac_instr_chk_bit=$(echo $ac_instr_chk_loc | cut -d "," -f 2) ac_instr_compiler_flags=$(echo $ac_instr_info | cut -d ";" -f 5) ac_instr_have_define=$(echo $ac_instr_info | cut -d ";" -f 6) ac_instr_flag_type=$(echo $ac_instr_info | cut -d ";" -f 7) AC_CACHE_CHECK([whether ${ac_instr_shortname} is supported by the processor], [ax_cv_have_${ac_instr_acvar}_cpu_ext], [ eval ax_cv_have_${ac_instr_acvar}_cpu_ext=no if test "$((${ac_instr_chk_reg}>>${ac_instr_chk_bit}&0x01))" = 1 ; then eval ax_cv_have_${ac_instr_acvar}_cpu_ext=yes fi ]) if test x"$(eval echo \$ax_cv_have_${ac_instr_acvar}_cpu_ext)" = x"yes"; then AC_CACHE_CHECK([whether ${ac_instr_shortname} is supported by the processor and OS], [ax_cv_have_${ac_instr_acvar}_ext], [ eval ax_cv_have_${ac_instr_acvar}_ext=no if test x"${ac_instr_os_support}" = x"yes"; then eval ax_cv_have_${ac_instr_acvar}_ext=yes fi ]) if test "$(eval echo \$ax_cv_have_${ac_instr_acvar}_ext)" = yes; then AX_CHECK_COMPILE_FLAG(${ac_instr_compiler_flags}, eval ax_cv_support_${ac_instr_acvar}_ext=yes, eval ax_cv_support_${ac_instr_acvar}_ext=no) if test x"$(eval echo \$ax_cv_support_${ac_instr_acvar}_ext)" = x"yes"; then eval ${ac_instr_flag_type}=\"\$${ac_instr_flag_type} ${ac_instr_compiler_flags}\" AC_DEFINE_UNQUOTED([${ac_instr_have_define}]) else AC_MSG_WARN([Your processor and OS supports ${ac_instr_shortname} instructions but not your compiler, can you try another compiler?]) fi else if test x"${ac_instr_os_support}" = x"no"; then AC_CACHE_VAL(ax_cv_support_${ac_instr_acvar}_ext, eval ax_cv_support_${ac_instr_acvar}_ext=no) AC_MSG_WARN([Your processor supports ${ac_instr_shortname}, but your OS doesn't]) fi fi else AC_CACHE_VAL(ax_cv_have_${ac_instr_acvar}_ext, eval ax_cv_have_${ac_instr_acvar}_ext=no) AC_CACHE_VAL(ax_cv_support_${ac_instr_acvar}_ext, eval ax_cv_support_${ac_instr_acvar}_ext=no) fi done ;; esac AH_TEMPLATE([HAVE_RDRND],[Define to 1 to support Digital Random Number Generator]) AH_TEMPLATE([HAVE_BMI1],[Define to 1 to support Bit Manipulation Instruction Set 1]) AH_TEMPLATE([HAVE_BMI2],[Define to 1 to support Bit Manipulation Instruction Set 2]) AH_TEMPLATE([HAVE_ADX],[Define to 1 to support Multi-Precision Add-Carry Instruction Extensions]) AH_TEMPLATE([HAVE_MPX],[Define to 1 to support Memory Protection Extensions]) AH_TEMPLATE([HAVE_PREFETCHWT1],[Define to 1 to support Prefetch Vector Data Into Caches WT1]) AH_TEMPLATE([HAVE_ABM],[Define to 1 to support Advanced Bit Manipulation]) AH_TEMPLATE([HAVE_MMX],[Define to 1 to support Multimedia Extensions]) AH_TEMPLATE([HAVE_SSE],[Define to 1 to support Streaming SIMD Extensions]) AH_TEMPLATE([HAVE_SSE2],[Define to 1 to support Streaming SIMD Extensions]) AH_TEMPLATE([HAVE_SSE3],[Define to 1 to support Streaming SIMD Extensions 3]) AH_TEMPLATE([HAVE_SSSE3],[Define to 1 to support Supplemental Streaming SIMD Extensions 3]) AH_TEMPLATE([HAVE_SSE4_1],[Define to 1 to support Streaming SIMD Extensions 4.1]) AH_TEMPLATE([HAVE_SSE4_2],[Define to 1 to support Streaming SIMD Extensions 4.2]) AH_TEMPLATE([HAVE_SSE4a],[Define to 1 to support AMD Streaming SIMD Extensions 4a]) AH_TEMPLATE([HAVE_SHA],[Define to 1 to support Secure Hash Algorithm Extension]) AH_TEMPLATE([HAVE_AES],[Define to 1 to support Advanced Encryption Standard New Instruction Set (AES-NI)]) AH_TEMPLATE([HAVE_AVX],[Define to 1 to support Advanced Vector Extensions]) AH_TEMPLATE([HAVE_FMA3],[Define to 1 to support Fused Multiply-Add Extensions 3]) AH_TEMPLATE([HAVE_FMA4],[Define to 1 to support Fused Multiply-Add Extensions 4]) AH_TEMPLATE([HAVE_XOP],[Define to 1 to support eXtended Operations Extensions]) AH_TEMPLATE([HAVE_AVX2],[Define to 1 to support Advanced Vector Extensions 2]) AH_TEMPLATE([HAVE_AVX512_F],[Define to 1 to support AVX-512 Foundation Extensions]) AH_TEMPLATE([HAVE_AVX512_CD],[Define to 1 to support AVX-512 Conflict Detection Instructions]) AH_TEMPLATE([HAVE_AVX512_PF],[Define to 1 to support AVX-512 Conflict Prefetch Instructions]) AH_TEMPLATE([HAVE_AVX512_ER],[Define to 1 to support AVX-512 Exponential & Reciprocal Instructions]) AH_TEMPLATE([HAVE_AVX512_VL],[Define to 1 to support AVX-512 Vector Length Extensions]) AH_TEMPLATE([HAVE_AVX512_BW],[Define to 1 to support AVX-512 Byte and Word Instructions]) AH_TEMPLATE([HAVE_AVX512_DQ],[Define to 1 to support AVX-512 Doubleword and Quadword Instructions]) AH_TEMPLATE([HAVE_AVX512_IFMA],[Define to 1 to support AVX-512 Integer Fused Multiply Add Instructions]) AH_TEMPLATE([HAVE_AVX512_VBMI],[Define to 1 to support AVX-512 Vector Byte Manipulation Instructions]) AC_SUBST(SIMD_FLAGS) AC_SUBST(CPUEXT_FLAGS) ]) liquid-dsp-1.7.0/scripts/ax_gcc_archflag.m4000066400000000000000000000226511474751757600206330ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_gcc_archflag.html # =========================================================================== # # SYNOPSIS # # AX_GCC_ARCHFLAG([PORTABLE?], [ACTION-SUCCESS], [ACTION-FAILURE]) # # DESCRIPTION # # This macro tries to guess the "native" arch corresponding to the target # architecture for use with gcc's -march=arch or -mtune=arch flags. If # found, the cache variable $ax_cv_gcc_archflag is set to this flag and # ACTION-SUCCESS is executed; otherwise $ax_cv_gcc_archflag is set to # "unknown" and ACTION-FAILURE is executed. The default ACTION-SUCCESS is # to add $ax_cv_gcc_archflag to the end of $CFLAGS. # # PORTABLE? should be either [yes] (default) or [no]. In the former case, # the flag is set to -mtune (or equivalent) so that the architecture is # only used for tuning, but the instruction set used is still portable. In # the latter case, the flag is set to -march (or equivalent) so that # architecture-specific instructions are enabled. # # The user can specify --with-gcc-arch= in order to override the # macro's choice of architecture, or --without-gcc-arch to disable this. # # When cross-compiling, or if $CC is not gcc, then ACTION-FAILURE is # called unless the user specified --with-gcc-arch manually. # # Requires macros: AX_CHECK_COMPILE_FLAG, AX_GCC_X86_CPUID # # (The main emphasis here is on recent CPUs, on the principle that doing # high-performance computing on old hardware is uncommon.) # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # Copyright (c) 2012 Tsukasa Oi # # 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, either 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 for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 13 AC_DEFUN([AX_GCC_ARCHFLAG], [AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_ARG_WITH(gcc-arch, [AS_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], ax_gcc_arch=$withval, ax_gcc_arch=yes) AC_MSG_CHECKING([for gcc architecture flag]) AC_MSG_RESULT([]) AC_CACHE_VAL(ax_cv_gcc_archflag, [ ax_cv_gcc_archflag="unknown" if test "$GCC" = yes; then if test "x$ax_gcc_arch" = xyes; then ax_gcc_arch="" if test "$cross_compiling" = no; then case $host_cpu in i[[3456]]86*|x86_64*|amd64*) # use cpuid codes AX_GCC_X86_CPUID(0) AX_GCC_X86_CPUID(1) case $ax_cv_gcc_x86_cpuid_0 in *:756e6547:*:*) # Intel case $ax_cv_gcc_x86_cpuid_1 in *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; *5??:*:*:*) ax_gcc_arch=pentium ;; *1?6[[7d]]?:*:*:*) ax_gcc_arch="penryn core2 pentium-m pentium3 pentiumpro" ;; *1?6[[aef]]?:*:*:*|*2?6[[5cef]]?:*:*:*) ax_gcc_arch="corei7 core2 pentium-m pentium3 pentiumpro" ;; *1?6c?:*:*:*|*[[23]]?66?:*:*:*) ax_gcc_arch="atom core2 pentium-m pentium3 pentiumpro" ;; *2?6[[ad]]?:*:*:*) ax_gcc_arch="corei7-avx corei7 core2 pentium-m pentium3 pentiumpro" ;; *[[1-9a-f]]?6??:*:*:*) ax_gcc_arch="core2 pentiumpro" ;; *6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; *6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; *6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; *6[[9de]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; *6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; *6f?:*:*:*) ax_gcc_arch="core2 pentium-m pentium3 pentiumpro" ;; *6??:*:*:*) ax_gcc_arch=pentiumpro ;; *f3[[347]]:*:*:*|*f4[1347]:*:*:*|*f6?:*:*:*) case $host_cpu in x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;; *) ax_gcc_arch="prescott pentium4 pentiumpro" ;; esac ;; *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";; esac ;; *:68747541:*:*) # AMD case $ax_cv_gcc_x86_cpuid_1 in *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; *60?:*:*:*) ax_gcc_arch=k7 ;; *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;; *6[[68a]]?:*:*:*) AX_GCC_X86_CPUID(0x80000006) # L2 cache size case $ax_cv_gcc_x86_cpuid_0x80000006 in *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256 ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; *) ax_gcc_arch="athlon-4 athlon k7" ;; esac ;; *5??f??:*:*:*) ax_gcc_arch="btver1 amdfam10 k8" ;; *6??f??:*:*:*) ax_gcc_arch="bdver1 amdfam10 k8" ;; *[[1-9a-f]]??f??:*:*:*) ax_gcc_arch="amdfam10 k8" ;; *f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; *f5?:*:*:*) ax_gcc_arch="opteron k8" ;; *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;; *f??:*:*:*) ax_gcc_arch="k8" ;; esac ;; *:746e6543:*:*) # IDT case $ax_cv_gcc_x86_cpuid_1 in *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; *58?:*:*:*) ax_gcc_arch=winchip2 ;; *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;; esac ;; esac if test x"$ax_gcc_arch" = x; then # fallback case $host_cpu in i586*) ax_gcc_arch=pentium ;; i686*) ax_gcc_arch=pentiumpro ;; esac fi ;; sparc*) AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters` case $cputype in *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; *cypress*) ax_gcc_arch=cypress ;; esac ;; alphaev5) ax_gcc_arch=ev5 ;; alphaev56) ax_gcc_arch=ev56 ;; alphapca56) ax_gcc_arch="pca56 ev56" ;; alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; alphaev6) ax_gcc_arch=ev6 ;; alphaev67) ax_gcc_arch=ev67 ;; alphaev68) ax_gcc_arch="ev68 ev67" ;; alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; powerpc*) cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'` case $cputype in *750*) ax_gcc_arch="750 G3" ;; *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; *970*) ax_gcc_arch="970 G5 power4";; *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; 603ev|8240) ax_gcc_arch="$cputype 603e 603";; *) ax_gcc_arch=$cputype ;; esac ax_gcc_arch="$ax_gcc_arch powerpc" ;; esac fi # not cross-compiling fi # guess arch if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then for arch in $ax_gcc_arch; do if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code flags="-mtune=$arch" # -mcpu=$arch and m$arch generate nonportable code on every arch except # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac else flags="-march=$arch -mcpu=$arch -m$arch" fi for flag in $flags; do AX_CHECK_COMPILE_FLAG($flag, [ax_cv_gcc_archflag=$flag; break]) done test "x$ax_cv_gcc_archflag" = xunknown || break done fi fi # $GCC=yes ]) AC_MSG_CHECKING([for gcc architecture flag]) AC_MSG_RESULT($ax_cv_gcc_archflag) if test "x$ax_cv_gcc_archflag" = xunknown; then m4_default([$3],:) else m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) fi ]) liquid-dsp-1.7.0/scripts/ax_gcc_x86_avx_xgetbv.m4000066400000000000000000000064221474751757600217440ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_x86_avx_xgetbv.html # =========================================================================== # # SYNOPSIS # # AX_GCC_X86_AVX_XGETBV # # DESCRIPTION # # On later x86 processors with AVX SIMD support, with gcc or a compiler # that has a compatible syntax for inline assembly instructions, run a # small program that executes the xgetbv instruction with input OP. This # can be used to detect if the OS supports AVX instruction usage. # # On output, the values of the eax and edx registers are stored as # hexadecimal strings as "eax:edx" in the cache variable # ax_cv_gcc_x86_avx_xgetbv. # # If the xgetbv instruction fails (because you are running a # cross-compiler, or because you are not using gcc, or because you are on # a processor that doesn't have this instruction), # ax_cv_gcc_x86_avx_xgetbv_OP is set to the string "unknown". # # This macro mainly exists to be used in AX_EXT. # # LICENSE # # Copyright (c) 2013 Michael Petch # # 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, either 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 for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_GCC_X86_AVX_XGETBV], [AC_REQUIRE([AC_PROG_CC]) AC_LANG_PUSH([C]) AC_CACHE_CHECK(for x86-AVX xgetbv $1 output, ax_cv_gcc_x86_avx_xgetbv_$1, [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ int op = $1, eax, edx; FILE *f; /* Opcodes for xgetbv */ __asm__ __volatile__ (".byte 0x0f, 0x01, 0xd0" : "=a" (eax), "=d" (edx) : "c" (op)); f = fopen("conftest_xgetbv", "w"); if (!f) return 1; fprintf(f, "%x:%x\n", eax, edx); fclose(f); return 0; ])], [ax_cv_gcc_x86_avx_xgetbv_$1=`cat conftest_xgetbv`; rm -f conftest_xgetbv], [ax_cv_gcc_x86_avx_xgetbv_$1=unknown; rm -f conftest_xgetbv], [ax_cv_gcc_x86_avx_xgetbv_$1=unknown])]) AC_LANG_POP([C]) ]) liquid-dsp-1.7.0/scripts/ax_gcc_x86_cpuid.m4000066400000000000000000000071671474751757600207020ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_gcc_x86_cpuid.html # =========================================================================== # # SYNOPSIS # # AX_GCC_X86_CPUID(OP) # AX_GCC_X86_CPUID_COUNT(OP, COUNT) # # DESCRIPTION # # On Pentium and later x86 processors, with gcc or a compiler that has a # compatible syntax for inline assembly instructions, run a small program # that executes the cpuid instruction with input OP. This can be used to # detect the CPU type. AX_GCC_X86_CPUID_COUNT takes an additional COUNT # parameter that gets passed into register ECX before calling cpuid. # # On output, the values of the eax, ebx, ecx, and edx registers are stored # as hexadecimal strings as "eax:ebx:ecx:edx" in the cache variable # ax_cv_gcc_x86_cpuid_OP. # # If the cpuid instruction fails (because you are running a # cross-compiler, or because you are not using gcc, or because you are on # a processor that doesn't have this instruction), ax_cv_gcc_x86_cpuid_OP # is set to the string "unknown". # # This macro mainly exists to be used in AX_GCC_ARCHFLAG. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2008 Matteo Frigo # Copyright (c) 2015 Michael Petch # # 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, either 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 for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 10 AC_DEFUN([AX_GCC_X86_CPUID], [AX_GCC_X86_CPUID_COUNT($1, 0) ]) AC_DEFUN([AX_GCC_X86_CPUID_COUNT], [AC_REQUIRE([AC_PROG_CC]) AC_LANG_PUSH([C]) AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ int op = $1, level = $2, eax, ebx, ecx, edx; FILE *f; __asm__ __volatile__ ("xchg %%ebx, %1\n" "cpuid\n" "xchg %%ebx, %1\n" : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx) : "a" (op), "2" (level)); f = fopen("conftest_cpuid", "w"); if (!f) return 1; fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); fclose(f); return 0; ])], [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], [ax_cv_gcc_x86_cpuid_$1=unknown])]) AC_LANG_POP([C]) ]) liquid-dsp-1.7.0/scripts/benchmark_compare.py000077500000000000000000000017521474751757600213320ustar00rootroot00000000000000#!/usr/bin/env python3 '''Compare benchmark results''' import argparse, json, numpy as np # parse command-line arguments p = argparse.ArgumentParser(description=__doc__) p.add_argument('old', help='old benchmark file (.json)') p.add_argument('new', help='new benchmark file (.json)') p.add_argument('-thresh', default=1.5, type=float, help='threshold for displaying deltas') args = p.parse_args() # load json files v0 = json.load(open(args.old,'r')) v1 = json.load(open(args.new,'r')) # convert to dictionary and get set of common names b0 = {v['name']:v for v in v0['benchmarks']} b1 = {v['name']:v for v in v1['benchmarks']} set_common = set(b0.keys()).intersection(set(b1.keys())) # iterate over common benchmarks and print results for key in set_common: r0,r1 = b0[key], b1[key] if 0 in (r0['trials'],r1['trials']): continue rate = r1['rate'] / r0['rate'] if np.exp(np.abs(np.log(rate))) < args.thresh: continue print(' %32s, rate = %12.8f' % (key, rate)) liquid-dsp-1.7.0/scripts/config.guess000066400000000000000000001414221474751757600176310ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-01-01' # This file 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, either 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 for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: liquid-dsp-1.7.0/scripts/config.h000066400000000000000000000154411474751757600167330ustar00rootroot00000000000000/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* This is the default config.h to be included without running bootstrap and configure */ #ifndef __LIQUID_CONFIG_H__ #define __LIQUID_CONFIG_H__ /* Support AVX (Advanced Vector Extensions) instructions */ /* #undef HAVE_AVX */ /* Define to 1 if you have the `cargf' function. */ #define HAVE_CARGF 1 /* Define to 1 if you have the `cexpf' function. */ #define HAVE_CEXPF 1 /* Define to 1 if you have the `cimagf' function. */ #define HAVE_CIMAGF 1 /* Define to 1 if you have the header file. */ #define HAVE_COMPLEX_H 1 /* Define to 1 if you have the `cosf' function. */ #define HAVE_COSF 1 /* Define to 1 if you have the `crealf' function. */ #define HAVE_CREALF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_EMMINTRIN_H */ /* Define to 1 if you have the `expf' function. */ #define HAVE_EXPF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_FEC_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_FFTW3_H */ /* Define to 1 if you have the header file. */ #define HAVE_FLOAT_H 1 /* Define to 1 if you have the `free' function. */ #define HAVE_FREE 1 /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_IMMINTRIN_H */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `c' library (-lc). */ #define HAVE_LIBC 1 /* Define to 1 if you have the `fec' library (-lfec). */ /* #undef HAVE_LIBFEC */ /* Define to 1 if you have the `fftw3f' library (-lfftw3f). */ #define HAVE_LIBFFTW3F 1 /* Define to 1 if you have the `m' library (-lm). */ #define HAVE_LIBM 1 /* Define to 1 if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define to 1 if you have the `malloc' function. */ #define HAVE_MALLOC 1 /* Define to 1 if you have the `memmove' function. */ #define HAVE_MEMMOVE 1 /* Define to 1 if you have the `memset' function. */ #define HAVE_MEMSET 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_MMINTRIN_H */ /* Support MMX instructions */ /* #undef HAVE_MMX */ /* Define to 1 if you have the header file. */ /* #undef HAVE_PMMINTRIN_H */ /* Define to 1 if you have the `realloc' function. */ #define HAVE_REALLOC 1 /* Define to 1 if you have the `sinf' function. */ #define HAVE_SINF 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_SMMINTRIN_H */ /* Define to 1 if you have the `sqrtf' function. */ #define HAVE_SQRTF 1 /* Support SSE (Streaming SIMD Extensions) instructions */ /* #undef HAVE_SSE */ /* Support SSE2 (Streaming SIMD Extensions 2) instructions */ /* #undef HAVE_SSE2 */ /* Support SSE3 (Streaming SIMD Extensions 3) instructions */ /* #undef HAVE_SSE3 */ /* Support SSE4.1 (Streaming SIMD Extensions 4.1) instructions */ /* #undef HAVE_SSE41 */ /* Support SSE4.2 (Streaming SIMD Extensions 4.2) instructions */ /* #undef HAVE_SSE42 */ /* Support SSSE3 (Supplemental Streaming SIMD Extensions 3) instructions */ /* #undef HAVE_SSSE3 */ /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDIO_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_RESOURCE_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_TMMINTRIN_H */ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_XMMINTRIN_H */ /* Force internal FFT even if libfftw is available */ #define LIQUID_FFTOVERRIDE 1 /* Force overriding of SIMD (use portable C code) */ #define LIQUID_SIMDOVERRIDE 1 /* Enable strict program exit on error */ /* #undef LIQUID_STRICT_EXIT */ /* Suppress printing errors to stderr */ /* #undef LIQUID_SUPPRESS_ERROR_OUTPUT */ /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "joseph@liquidsdr.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "liquid-dsp" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "liquid-dsp 1.7.0" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "liquid-dsp" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "1.7.0" /* The size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 /* The size of `long int', as computed by sizeof. */ #define SIZEOF_LONG_INT 8 /* The size of `long long int', as computed by sizeof. */ #define SIZEOF_LONG_LONG_INT 8 /* The size of `short int', as computed by sizeof. */ #define SIZEOF_SHORT_INT 2 /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT32_T */ /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ /* #undef _UINT8_T */ /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus /* #undef inline */ #endif /* Define to rpl_malloc if the replacement function should be used. */ /* #undef malloc */ /* Define to rpl_realloc if the replacement function should be used. */ /* #undef realloc */ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ /* #undef uint32_t */ /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ /* #undef uint8_t */ #endif // __LIQUID_CONFIG_H__ liquid-dsp-1.7.0/scripts/config.sub000066400000000000000000001057521474751757600173020ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-01-21' # This file 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, either 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 for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-*) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x$basic_os != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os in linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* ) ;; uclinux-uclibc* ) ;; managarm-mlibc* | managarm-kernel* ) ;; -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel* ) echo "Invalid configuration \`$1': \`$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel* ) echo "Invalid configuration \`$1': \`$kernel' does not support \`$os'." 1>&2 exit 1 ;; kfreebsd*-gnu* | kopensolaris*-gnu*) ;; vxworks-simlinux | vxworks-simwindows | vxworks-spe) ;; nto-qnx*) ;; os2-emx) ;; *-eabi* | *-gnueabi*) ;; -*) # Blank kernel with real OS is always fine. ;; *-*) echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: liquid-dsp-1.7.0/scripts/example_autotest.h000066400000000000000000000023731474751757600210510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Example of a benchmark header // #include #include void autotest_mytest() { printf("this is my test\n"); } liquid-dsp-1.7.0/scripts/example_benchmark.h000066400000000000000000000035251474751757600211330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Example of a benchmark header // #include #include // strings parsed by benchmarkgen.py const char * mybench_opts[3] = { "opt1a opt1b", "opt2a opt2b opt2c", "opt3a opt3b opt3c" }; void benchmark_mybench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) // unsigned int argc, // char *argv[]) { // DSP initiazation goes here unsigned int i; float x, y, theta; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // DSP execution goes here x = cosf(M_PI/2.0f); y = sinf(M_PI/2.0f); theta = atan2(y,x); } getrusage(RUSAGE_SELF, _finish); // DSP cleanup goes here } liquid-dsp-1.7.0/scripts/framesync64_debug.py000077500000000000000000000055221474751757600212000ustar00rootroot00000000000000#!/usr/bin/env python3 '''plot frame sync debug files''' import argparse, os, sys import numpy as np, matplotlib.pyplot as plt def main(argv=None): p = argparse.ArgumentParser(description=__doc__) p.add_argument('sources', nargs='+', help='input files') p.add_argument('-export', default=None, action='store_true', help='export figure') p.add_argument('-nodisplay', action='store_true', help='disable display') args = p.parse_args() for fname in args.sources: filename = framesync64_plot(fname,args.export,args.nodisplay) def framesync64_plot(filename,export=None,nodisplay=True): # open file and read values fid = open(filename,'rb') buf = np.fromfile(fid, count=1440, dtype=np.csingle) tau_hat = np.fromfile(fid, count= 1, dtype=np.single) dphi_hat = np.fromfile(fid, count= 1, dtype=np.single) phi_hat = np.fromfile(fid, count= 1, dtype=np.single) gamma_hat = np.fromfile(fid, count= 1, dtype=np.single) evm = np.fromfile(fid, count= 1, dtype=np.single) payload_rx = np.fromfile(fid, count= 630, dtype=np.csingle) payload_sym = np.fromfile(fid, count= 600, dtype=np.csingle) payload_dec = np.fromfile(fid, count= 72, dtype=np.int8) # compute smooth spectral response in dB nfft = 2400 f = np.arange(nfft)/nfft-0.5 psd = np.abs(np.fft.fftshift(np.fft.fft(buf, nfft)))**2 m = int(0.01*nfft) w = np.hamming(2*m+1) h = np.concatenate((w[m:], np.zeros(nfft-2*m-1), w[:m])) / (sum(w) * nfft) H = np.fft.fft(h) psd = 10*np.log10( np.real(np.fft.ifft(H * np.fft.fft(psd))) ) # plot impulse and spectral responses fig, _ax = plt.subplots(2,2,figsize=(12,12)) ax = _ax.flatten() t = np.arange(len(buf)) qpsk = np.exp(0.5j*np.pi*(np.arange(4)+0.5)) # payload constellation ax[0].plot(t,np.real(buf), t,np.imag(buf)) ax[0].set_title('Raw I/Q Samples') ax[1].plot(f,psd) ax[1].set(xlim=(-0.5,0.5)) ax[1].set_title('Power Spectral Density') ax[2].plot(np.real(payload_rx), np.imag(payload_rx), '.') ax[2].set_title('RX Payload Syms') ax[3].plot(np.real(payload_sym), np.imag(payload_sym), '.') ax[3].set_title('Synchronized Payload Syms') for _ax in ax[2:]: _ax.set(xlim=(-1.3,1.3), ylim=(-1.3,1.3)) _ax.plot(np.real(qpsk),np.imag(qpsk),'rx') _ax.set_xlabel('Real') _ax.set_ylabel('Imag') for _ax in ax: _ax.grid(True) title = '%s, tau:%9.6f, dphi:%9.6f, phi:%9.6f, rssi:%6.3f dB, evm:%6.3f' % \ (filename, tau_hat, dphi_hat, phi_hat, 20*np.log10(gamma_hat), evm) print(title) fig.suptitle(title) if not nodisplay: plt.show() if export is not None: fig.savefig(os.path.splitext(filename)[0]+'.png',bbox_inches='tight') plt.close() if __name__ == '__main__': sys.exit(main()) liquid-dsp-1.7.0/scripts/generate_headers.py000077500000000000000000000001551474751757600211530ustar00rootroot00000000000000#!/usr/bin/env python3 '''Generate (or copy) configuration header''' import os os.system('cp config.h ..') liquid-dsp-1.7.0/scripts/install-sh000077500000000000000000000316001474751757600173140ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-10-14.15 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" posix_glob= posix_mkdir= # Desired mode of installed file. mode=0755 chmodcmd=$chmodprog chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) mode=$2 shift shift case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac done if test $# -ne 0 && test -z "$dir_arg$dstarg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix=/ ;; -*) prefix=./ ;; *) prefix= ;; esac case $posix_glob in '') if (set -f) 2>/dev/null; then posix_glob=true else posix_glob=false fi ;; esac oIFS=$IFS IFS=/ $posix_glob && set -f set fnord $dstdir shift $posix_glob && set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dst"; then $doit $rmcmd -f "$dst" 2>/dev/null \ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } } || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: liquid-dsp-1.7.0/scripts/liquid_linker_test.c000066400000000000000000000011471474751757600213510ustar00rootroot00000000000000// test linking to liquid after library has been installed #include #include #include int main() { // test liquid version number printf("checking installed liquid version numbers...\n"); printf(" header : 0x%.6x\n", LIQUID_VERSION_NUMBER); printf(" library : 0x%.6x\n", liquid_libversion_number()); LIQUID_VALIDATE_LIBVERSION; // create object, print and return printf("creating test object...\n"); resamp_crcf q = resamp_crcf_create(0.12345f, 12, 0.25f, 60.0f, 256); resamp_crcf_print(q); resamp_crcf_destroy(q); return 0; } liquid-dsp-1.7.0/scripts/liquid_linker_test.mk000066400000000000000000000003551474751757600215360ustar00rootroot00000000000000# simple makefile to test linking to liquid after library has been installed all: check check: liquid_linker_test ./$< liquid_linker_test: % : scripts/%.c $(CC) -Wall -O2 -o $@ $< -lm -lc -lliquid clean: rm -f liquid_linker_test liquid-dsp-1.7.0/scripts/main.c000066400000000000000000000045731474751757600164110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // scripts/main.c // // Auto-script generator test program #include #include #include #include "autoscript.h" void usage() { printf("Usage: autoscript_test DELIM TYPE [LIST OF FILES]\n"); printf(" DELIM : path separation delimiter (e.g. '/')\n"); printf(" TYPE : base type for parsing (e.g. \"benchmark\")\n"); printf(" [LIST] : list of auto-script files, named MYPACKAGE_TYPE.h\n"); printf(" with internal scripts \"void TYPE_MYSCRIPT(...)\"\n"); } int main(int argc, char*argv[]) { // if (argc < 3) { // print help fprintf(stderr,"error: %s, too few arguments\n", argv[0]); usage(); exit(1); } else { //printf("// delim : '%c'\n", argv[1][0]); //printf("// type : \"%s\"\n", argv[2]); } // create autoscript object // first argument : type string (e.g. "benchmark") // second argument : delimiter character (file system) autoscript q = autoscript_create(argv[2], argv[1][0]); // parse files int i; for (i=3; i ''' import os import sys import re def usage(): print __doc__ if len(sys.argv) != 2: sys.stderr.write("error: please provide an input directory\n") usage() sys.exit(-1) elif sys.argv[1] in ('-h','--help'): usage() sys.exit(0) # new copyright newcopy = '''\ Copyright (c) 2007 - 2015 Joseph Gaeddert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'''.splitlines() # add new line character to end of each line for i in xrange(len(newcopy)): newcopy[i] += '\n' rootdir = sys.argv[1] # specific files to ignore ignore_files = ['update_copyright.py',] # directories to ignore ignore_directories = ['.git',] # only look at these extensions include_extensions = ['.h', '.c', '.md', '.tex', '.ac', '.in', '.m',] # print alignment for status align = 56 # def update_copyright(filename=""): """ Update copyright on file. """ # try to open file contents = [] with open( filename, 'r' ) as f: # read lines from file (removing newline character at end) for line in f: #contents.append(line.strip('\n\r')) contents.append(line) # parse contents index_start = -1 index_stop = -1 # search for copyright; starts at top of file for i in range(min(10, len(contents))): if re.search(r'Copyright .* Joseph Gaeddert',contents[i]): index_start = i break if index_start == -1: print " " + filename + ":" + " "*(align-len(filename)) + "no copyright found" return # look for end of copyright #for i in range(index_start+15,index_start+15+min(10, len(contents))): i = index_start + 15 if re.search(r'along with liquid. If not, see',contents[i]): index_stop = i elif re.search(r'AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM',contents[i]): print " " + filename + ":" + " "*(align-len(filename)) + "copyright already updated" return else: print " " + filename + ":" + " "*(align-len(filename)) + "could not find end of copyright" return # check comment type m = re.search(r'^( \*|#+) +Copyright',contents[index_start]) if m: comment = m.group(1) else: raise Exception('unexpected error') # delete items in list contents.__delslice__(index_start, index_stop+1) # insert new copyright for i in range(len(newcopy)): # only add space after comment characters if string is not empty # (e.g. print ' *' instead of ' * ') space = ' ' if len(newcopy[i].strip()) > 0 else '' # insert new comment contents.insert(index_start+i, comment + space + newcopy[i]) # open original file for writing with open( filename, 'w' ) as f: for line in contents: f.write(line) print " " + filename + ":" + " "*(align-len(filename)) + "updated" # for root, subFolders, files in os.walk(rootdir): # strip off leading './' if it exists if root.startswith('./'): root = root[2:] # print root directory print root # ignore certain directories if root in ignore_directories: print "(skipping directory)" continue # print subfolders #for folder in subFolders: # print "%s has subdirectory %s" % (root, folder) # parse each filename in directory for filename in files: filePath = os.path.join(root, filename) # check filename if filePath in ignore_files: print " " + filePath + ":" + " "*(align-len(filePath)) + "ignoring this specific file" continue; # check filename extension baseName, extension = os.path.splitext(filename) if extension not in include_extensions: print " " + filePath + ":" + " "*(align-len(filePath)) + "improper extension; ignoring file" continue; # continue on with this file update_copyright(filePath) liquid-dsp-1.7.0/scripts/valgrind_eval.py000077500000000000000000000036721474751757600205120ustar00rootroot00000000000000#!/usr/bin/env python3 '''Run valgrind on each autotest and catalog memory errors''' import argparse, json, os, sys, subprocess def generate_json(path: str='valgrind', overwrite=False): filename = path + '/init.json' if overwrite or not os.path.exists(filename): os.system('./xautotest -t0 -o %s' % (filename,)) return json.load(open(filename,'r')) def run_test(test: dict, opts: str='--tool=memcheck --leak-check=full --track-origins=yes', path: str='valgrind', seed: int=1, debug: bool=True): '''run a specific test''' filename = '%s/memcheck.%.4u.%s.log' % (path, test['id'], test['name']) cmd = 'valgrind %s --log-file=%s ./xautotest -t %u -R %u' % (opts, filename, test['id'], seed) if debug: print(cmd) os.system(cmd) # TODO parse result def main(argv=None): p = argparse.ArgumentParser(description=__doc__) p.add_argument('-output', default='valgrind', type=str, help='output directory') p.add_argument('-search', default=None, type=str, help='search') p.add_argument('-test', default=None, type=int, help='run a specific test') args = p.parse_args() # generate and load .json object v = generate_json(args.output) # set additional configuration options opts = '--tool=memcheck --leak-check=full --track-origins=yes' if args.test is not None: # run a specific test run_test(v['tests'][args.test], opts, seed=v['rseed']) elif args.search is not None: # run all tests matching search string print("running all tests containing '%s'...\n" % (args.search)) for i,test in enumerate(v['tests']): if test['name'].lower().__contains__(args.search.lower()): run_test(test, opts, seed=v['rseed']) else: # iterate over all tests and execute for i,test in enumerate(v['tests']): run_test(test, opts, seed=v['rseed']) if __name__ == '__main__': sys.exit(main()) liquid-dsp-1.7.0/scripts/version.sh000077500000000000000000000023241474751757600173350ustar00rootroot00000000000000#!/bin/sh # This script parses the global header and extracts the major.minor.patch version for # liquid-dsp and prints to the screen. This is a simplified version of: # https://github.com/tinyalsa/tinyalsa/blob/master/scripts/version.sh INCLUDE_FILE="include/liquid.h" # exit program with error die() { echo "error: $@" 1>&2 exit 1 } # check that file exists check_files() { [ -f ${INCLUDE_FILE} ] || die "No ${INCLUDE_FILE} found!"; } # get a part of the version from the header, e.g. LIQUID_VERSION_MAJOR get_version_part() { set -- "$1" "$(grep -m 1 "^#define\([ \t]*\)$1" ${INCLUDE_FILE} | sed 's/[^0-9]*//g')" if [ -z "$2" ]; then die "Could not get $1 from ${INCLUDE_FILE}" fi echo "$2" } # gets the complete version from the include file get_version() { VERSION_MAJOR=$(get_version_part "LIQUID_VERSION_MAJOR") VERSION_MINOR=$(get_version_part "LIQUID_VERSION_MINOR") VERSION_PATCH=$(get_version_part "LIQUID_VERSION_PATCH") } print_version() { printf "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${LF}" return 0 } check_files get_version print_version "$2" exit $? # The script should never reach this place. die "Internal error. Please report this." liquid-dsp-1.7.0/src/000077500000000000000000000000001474751757600144105ustar00rootroot00000000000000liquid-dsp-1.7.0/src/agc/000077500000000000000000000000001474751757600151425ustar00rootroot00000000000000liquid-dsp-1.7.0/src/agc/bench/000077500000000000000000000000001474751757600162215ustar00rootroot00000000000000liquid-dsp-1.7.0/src/agc/bench/agc_crcf_benchmark.c000066400000000000000000000040621474751757600221300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // helper function to keep code base small void benchmark_agc_crcf(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { unsigned int i; // initialize AGC object agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q,0.05f); float complex x = 1e-6f; // input sample float complex y; // output sample getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); agc_crcf_execute(q, x, &y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 8; // destroy object agc_crcf_destroy(q); } liquid-dsp-1.7.0/src/agc/src/000077500000000000000000000000001474751757600157315ustar00rootroot00000000000000liquid-dsp-1.7.0/src/agc/src/agc.proto.c000066400000000000000000000273521474751757600200020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Automatic gain control // #include #include #include #include #include "liquid.internal.h" // default AGC loop bandwidth #define AGC_DEFAULT_BW (1e-2f) // internal method definition int AGC(_squelch_update_mode)(AGC() _q); // agc structure object struct AGC(_s) { // gain variables T g; // current gain value T scale; // output scale value // gain control loop filter parameters float bandwidth;// bandwidth-time constant T alpha; // feed-back gain // signal level estimate T y2_prime; // filtered output signal energy estimate // AGC locked flag int is_locked; // squelch mode agc_squelch_mode squelch_mode; // squelch threshold T squelch_threshold; // squelch timeout unsigned int squelch_timeout; unsigned int squelch_timer; }; // create agc object AGC() AGC(_create)(void) { // create object and initialize to default parameters AGC() _q = (AGC()) malloc(sizeof(struct AGC(_s))); // initialize bandwidth AGC(_set_bandwidth)(_q, AGC_DEFAULT_BW); // reset object AGC(_reset)(_q); // squelch AGC(_squelch_disable)(_q); AGC(_squelch_set_threshold)(_q, 0.0f); AGC(_squelch_set_timeout )(_q, 100); // set default output gain _q->scale = 1; // return object return _q; } // copy object AGC() AGC(_copy)(AGC() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("agc_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy memory AGC() q_copy = (AGC()) malloc(sizeof(struct AGC(_s))); memmove(q_copy, q_orig, sizeof(struct AGC(_s))); return q_copy; } // destroy agc object, freeing all internally-allocated memory int AGC(_destroy)(AGC() _q) { // free main object memory free(_q); return LIQUID_OK; } // print agc object internals int AGC(_print)(AGC() _q) { printf("\n", AGC(_get_rssi)(_q), _q->scale > 0 ? 10.*log10f(_q->scale) : -100.0f, _q->bandwidth, _q->is_locked ? "true" : "false", _q->squelch_mode == LIQUID_AGC_SQUELCH_DISABLED ? "disabled" : "enabled"); return LIQUID_OK; } // reset agc object's internal state int AGC(_reset)(AGC() _q) { // reset gain estimate _q->g = 1.0f; // reset signal level estimate _q->y2_prime = 1.0f; // unlock gain control AGC(_unlock)(_q); // reset squelch state _q->squelch_mode = (_q->squelch_mode == LIQUID_AGC_SQUELCH_DISABLED) ? LIQUID_AGC_SQUELCH_DISABLED : LIQUID_AGC_SQUELCH_ENABLED; return LIQUID_OK; } // execute automatic gain control loop // _q : agc object // _x : input sample // _y : output sample int AGC(_execute)(AGC() _q, TC _x, TC * _y) { // apply gain to input sample *_y = _x * _q->g; // compute output signal energy T y2 = crealf( (*_y)*conjf(*_y) ); // smooth energy estimate using single-pole low-pass filter _q->y2_prime = (1.0-_q->alpha)*_q->y2_prime + _q->alpha*y2; // return if locked if (_q->is_locked) return LIQUID_OK; // update gain according to output energy if (_q->y2_prime > 1e-6f) _q->g *= expf( -0.5f*_q->alpha*logf(_q->y2_prime) ); // clamp to 120 dB gain _q->g = (_q->g > 1e6f) ? 1e6f : _q->g; // update squelch mode appropriately AGC(_squelch_update_mode)(_q); // apply output scale *_y *= _q->scale; return LIQUID_OK; } // execute automatic gain control on block of samples // _q : automatic gain control object // _x : input data array, [size: _n x 1] // _n : number of input, output samples // _y : output data array, [size: _n x 1] int AGC(_execute_block)(AGC() _q, TC * _x, unsigned int _n, TC * _y) { unsigned int i; int rc = LIQUID_OK; for (i=0; i<_n; i++) { rc |= AGC(_execute)(_q, _x[i], &_y[i]); } return rc; } // lock agc int AGC(_lock)(AGC() _q) { _q->is_locked = 1; return LIQUID_OK; } // unlock agc int AGC(_unlock)(AGC() _q) { _q->is_locked = 0; return LIQUID_OK; } // get lock state of agc object int AGC(_is_locked)(AGC() _q) { return _q->is_locked; } // get agc loop bandwidth float AGC(_get_bandwidth)(AGC() _q) { return _q->bandwidth; } // set agc loop bandwidth // _q : agc object // _BT : bandwidth int AGC(_set_bandwidth)(AGC() _q, float _bt) { // check to ensure bandwidth is reasonable if ( _bt < 0 ) return liquid_error(LIQUID_EICONFIG,"agc_%s_set_bandwidth(), bandwidth must be positive", EXTENSION_FULL); if ( _bt > 1.0f ) return liquid_error(LIQUID_EICONFIG,"agc_%s_set_bandwidth(), bandwidth must less than 1.0", EXTENSION_FULL); // set internal bandwidth _q->bandwidth = _bt; // compute filter coefficient based on bandwidth _q->alpha = _q->bandwidth; return LIQUID_OK; } // get estimated signal level (linear) float AGC(_get_signal_level)(AGC() _q) { return 1.0f / _q->g; } // set estimated signal level (linear) int AGC(_set_signal_level)(AGC() _q, float _x2) { // check to ensure signal level is reasonable if ( _x2 <= 0 ) return liquid_error(LIQUID_EICONFIG,"error: agc_%s_set_signal_level(), bandwidth must be greater than zero", EXTENSION_FULL); // set internal gain appropriately _q->g = 1.0f / _x2; // reset internal output signal level _q->y2_prime = 1.0f; return LIQUID_OK; } // get estimated signal level (dB) float AGC(_get_rssi)(AGC() _q) { return -20*log10(_q->g); } // set estimated signal level (dB) int AGC(_set_rssi)(AGC() _q, float _rssi) { // set internal gain appropriately _q->g = powf(10.0f, -_rssi/20.0f); // ensure resulting gain is not arbitrarily low _q->g = (_q->g < 1e-16f) ? 1e-16f : _q->g; // reset internal output signal level _q->y2_prime = 1.0f; return LIQUID_OK; } // get internal gain float AGC(_get_gain)(AGC() _q) { return _q->g; } // set internal gain int AGC(_set_gain)(AGC() _q, float _gain) { // check to ensure gain is reasonable if ( _gain <= 0 ) return liquid_error(LIQUID_EICONFIG,"error: agc_%s_set_gain(), gain must be greater than zero", EXTENSION_FULL); // set internal gain appropriately _q->g = _gain; return LIQUID_OK; } // get scale float AGC(_get_scale)(AGC() _q) { return _q->scale; } // set scale int AGC(_set_scale)(AGC() _q, float _scale) { // check to ensure gain is reasonable if ( _scale <= 0 ) return liquid_error(LIQUID_EICONFIG,"error: agc_%s_set_scale(), scale must be greater than zero", EXTENSION_FULL); // set internal gain appropriately _q->scale = _scale; return LIQUID_OK; } // initialize internal gain on input array // _q : automatic gain control object // _x : input data array, [size: _n x 1] // _n : number of input, output samples int AGC(_init)(AGC() _q, TC * _x, unsigned int _n) { // ensure number of samples is greater than zero if ( _n == 0 ) return liquid_error(LIQUID_EICONFIG,"error: agc_%s_init(), number of samples must be greater than zero", EXTENSION_FULL); // compute sum squares on input // TODO: use vector methods for this unsigned int i; T x2 = 0; for (i=0; i<_n; i++) x2 += crealf( _x[i]*conjf(_x[i]) ); // compute RMS level and ensure result is positive x2 = sqrtf( x2 / (float) _n ) + 1e-16f; // set internal gain based on estimated signal level AGC(_set_signal_level)(_q, x2); return LIQUID_OK; } // enable squelch mode int AGC(_squelch_enable)(AGC() _q) { _q->squelch_mode = LIQUID_AGC_SQUELCH_ENABLED; return LIQUID_OK; } // disable squelch mode int AGC(_squelch_disable)(AGC() _q) { _q->squelch_mode = LIQUID_AGC_SQUELCH_DISABLED; return LIQUID_OK; } // is squelch enabled? int AGC(_squelch_is_enabled)(AGC() _q) { return _q->squelch_mode == LIQUID_AGC_SQUELCH_DISABLED ? 0 : 1; } // set squelch threshold // _q : automatic gain control object // _thresh_dB : threshold for enabling squelch [dB] int AGC(_squelch_set_threshold)(AGC() _q, T _threshold) { _q->squelch_threshold = _threshold; return LIQUID_OK; } // get squelch threshold [dB] T AGC(_squelch_get_threshold)(AGC() _q) { return _q->squelch_threshold; } // set squelch timeout // _q : automatic gain control object // _timeout : timeout before enabling squelch [samples] int AGC(_squelch_set_timeout)(AGC() _q, unsigned int _timeout) { _q->squelch_timeout = _timeout; return LIQUID_OK; } // get squelch timeout [samples] unsigned int AGC(_squelch_get_timeout)(AGC() _q) { return _q->squelch_timeout; } // get squelch mode int AGC(_squelch_get_status)(AGC() _q) { return _q->squelch_mode; } // // internal methods // // update squelch mode appropriately int AGC(_squelch_update_mode)(AGC() _q) { // int threshold_exceeded = (AGC(_get_rssi)(_q) > _q->squelch_threshold); // update state switch (_q->squelch_mode) { case LIQUID_AGC_SQUELCH_ENABLED: _q->squelch_mode = threshold_exceeded ? LIQUID_AGC_SQUELCH_RISE : LIQUID_AGC_SQUELCH_ENABLED; break; case LIQUID_AGC_SQUELCH_RISE: _q->squelch_mode = threshold_exceeded ? LIQUID_AGC_SQUELCH_SIGNALHI : LIQUID_AGC_SQUELCH_FALL; break; case LIQUID_AGC_SQUELCH_SIGNALHI: _q->squelch_mode = threshold_exceeded ? LIQUID_AGC_SQUELCH_SIGNALHI : LIQUID_AGC_SQUELCH_FALL; break; case LIQUID_AGC_SQUELCH_FALL: _q->squelch_mode = threshold_exceeded ? LIQUID_AGC_SQUELCH_SIGNALHI : LIQUID_AGC_SQUELCH_SIGNALLO; _q->squelch_timer = _q->squelch_timeout; break; case LIQUID_AGC_SQUELCH_SIGNALLO: _q->squelch_timer--; if (_q->squelch_timer == 0) _q->squelch_mode = LIQUID_AGC_SQUELCH_TIMEOUT; else if (threshold_exceeded) _q->squelch_mode = LIQUID_AGC_SQUELCH_SIGNALHI; break; case LIQUID_AGC_SQUELCH_TIMEOUT: _q->squelch_mode = LIQUID_AGC_SQUELCH_ENABLED; break; case LIQUID_AGC_SQUELCH_DISABLED: break; case LIQUID_AGC_SQUELCH_UNKNOWN: default: return liquid_error(LIQUID_EINT,"agc_%s_execute(), invalid/unsupported squelch mode: %d", EXTENSION_FULL, _q->squelch_mode); } return LIQUID_OK; } liquid-dsp-1.7.0/src/agc/src/agc_crcf.c000066400000000000000000000030451474751757600176260ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // AGC API: floating-point [complex] // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "crcf" // macros #define AGC(name) LIQUID_CONCAT(agc_crcf,name) #define T float // general #define TC float complex // input/output #define TC_COMPLEX 1 // prototypes #include "agc.proto.c" liquid-dsp-1.7.0/src/agc/src/agc_rrrf.c000066400000000000000000000030421474751757600176610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // AGC API: floating-point [real] // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "rrrf" // macros #define AGC(name) LIQUID_CONCAT(agc_rrrf,name) #define T float // general #define TC float // input/output #define TC_COMPLEX 0 // prototypes #include "agc.proto.c" liquid-dsp-1.7.0/src/agc/tests/000077500000000000000000000000001474751757600163045ustar00rootroot00000000000000liquid-dsp-1.7.0/src/agc/tests/agc_crcf_autotest.c000066400000000000000000000262761474751757600221440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // Test DC gain control void autotest_agc_crcf_dc_gain_control() { // set parameters float gamma = 0.1f; // nominal signal level float bt = 0.1f; // bandwidth-time product float tol = 0.001f; // error tolerance // create AGC object and initialize agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); unsigned int i; float complex x = gamma; // input sample float complex y; // output sample for (i=0; i<256; i++) agc_crcf_execute(q, x, &y); // Check results CONTEND_DELTA( crealf(y), 1.0f, tol ); CONTEND_DELTA( cimagf(y), 0.0f, tol ); CONTEND_DELTA( agc_crcf_get_gain(q), 1.0f/gamma, tol ); // explicitly set gain and check result agc_crcf_set_gain(q, 1.0f); CONTEND_EQUALITY( agc_crcf_get_gain(q), 1.0f ); // destroy AGC object agc_crcf_destroy(q); } // test gain control on DC input with separate scale void autotest_agc_crcf_scale() { // set parameters float scale = 4.0f; // output scale (independent of AGC loop) float tol = 0.001f; // error tolerance // create AGC object and initialize agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, 0.1f); agc_crcf_set_scale (q, scale); CONTEND_EQUALITY(agc_crcf_get_scale(q), scale); unsigned int i; float complex x = 0.1f; // input sample float complex y; // output sample for (i=0; i<256; i++) agc_crcf_execute(q, x, &y); // Check results CONTEND_DELTA( crealf(y), scale, tol ); CONTEND_DELTA( cimagf(y), 0.0f, tol ); // destroy AGC object agc_crcf_destroy(q); } // Test AC gain control void autotest_agc_crcf_ac_gain_control() { // set parameters float gamma = 0.1f; // nominal signal level float bt = 0.1f; // bandwidth-time product float tol = 0.001f; // error tolerance float dphi = 0.1f; // NCO frequency // create AGC object and initialize agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); unsigned int i; float complex x; float complex y; for (i=0; i<256; i++) { x = gamma * cexpf(_Complex_I*i*dphi); agc_crcf_execute(q, x, &y); } if (liquid_autotest_verbose) printf("gamma : %12.8f, rssi : %12.8f\n", gamma, agc_crcf_get_signal_level(q)); // Check results CONTEND_DELTA( agc_crcf_get_gain(q), 1.0f/gamma, tol); // destroy AGC object agc_crcf_destroy(q); } // Test RSSI on sinusoidal input void autotest_agc_crcf_rssi_sinusoid() { // set parameters float gamma = 0.3f; // nominal signal level float bt = 0.05f; // agc bandwidth float tol = 0.001f; // error tolerance // signal properties float dphi = 0.1f; // signal frequency // create AGC object and initialize agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); unsigned int i; float complex x, y; for (i=0; i<512; i++) { // generate sample (complex sinusoid) x = gamma * cexpf(_Complex_I*dphi*i); // execute agc agc_crcf_execute(q, x, &y); } // get received signal strength indication float rssi = agc_crcf_get_signal_level(q); if (liquid_autotest_verbose) printf("gamma : %12.8f, rssi : %12.8f\n", gamma, rssi); // Check results CONTEND_DELTA( rssi, gamma, tol ); // destroy agc object agc_crcf_destroy(q); } // Test RSSI on noise input void autotest_agc_crcf_rssi_noise() { // set parameters float gamma = -30.0f; // nominal signal level [dB] float bt = 2e-3f; // agc bandwidth float tol = 1.0f; // error tolerance [dB] // signal properties float nstd = powf(10.0f, gamma/20); // create AGC object and initialize agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, bt); unsigned int i; float complex x, y; for (i=0; i<8000; i++) { // generate sample (circular complex noise) x = nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; // execute agc agc_crcf_execute(q, x, &y); } // get received signal strength indication float rssi = agc_crcf_get_rssi(q); if (liquid_autotest_verbose) printf("gamma : %12.8f, rssi : %12.8f\n", gamma, rssi); // Check results CONTEND_DELTA( rssi, gamma, tol ); // destroy agc object agc_crcf_destroy(q); } // Test squelch functionality void autotest_agc_crcf_squelch() { // create agc object, set loop bandwidth, and initialize parameters agc_crcf q = agc_crcf_create(); agc_crcf_set_bandwidth(q, 0.25); agc_crcf_set_signal_level(q,1e-3f); // initial guess at starting signal level // initialize squelch functionality CONTEND_FALSE(agc_crcf_squelch_is_enabled(q)); agc_crcf_squelch_enable(q); // enable squelch agc_crcf_squelch_set_threshold(q, -50); // threshold for detection [dB] agc_crcf_squelch_set_timeout (q, 100); // timeout for hysteresis CONTEND_TRUE(agc_crcf_squelch_is_enabled(q)); CONTEND_EQUALITY(agc_crcf_squelch_get_threshold(q), -50); CONTEND_EQUALITY(agc_crcf_squelch_get_timeout (q), 100); // run agc unsigned int num_samples = 2000; // total number of samples to run unsigned int i; for (i=0; i #include "liquid.h" // benchmark CVSD encoder void benchmark_cvsd_encode(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { unsigned long int i; // options unsigned int nbits=4; // number of adjacent bits to observe float zeta=1.5f; // slope adjustment multiplier float alpha = 0.95; // pre-/post-filter coefficient char bit = 0; // output bit // create cvsd encoder cvsd encoder = cvsd_create(nbits, zeta, alpha); // input time series (random) float x[8] = { 1.19403f, -0.76765f, -1.08415f, 0.65095f, 0.11647f, -0.80130f, -0.87540f, -0.14888f}; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { bit ^= cvsd_encode(encoder, x[0]); bit ^= cvsd_encode(encoder, x[2]); bit ^= cvsd_encode(encoder, x[3]); bit ^= cvsd_encode(encoder, x[3]); bit ^= cvsd_encode(encoder, x[4]); bit ^= cvsd_encode(encoder, x[5]); bit ^= cvsd_encode(encoder, x[6]); bit ^= cvsd_encode(encoder, x[7]); // randomize input x[i%8] += bit ? 0.1f : -0.1f; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 8; // destroy cvsd encoder cvsd_destroy(encoder); } // benchmark CVSD decoder void benchmark_cvsd_decode(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { unsigned long int i; // options unsigned int nbits=4; // number of adjacent bits to observe float zeta=1.5f; // slope adjustment multiplier float alpha = 0.95; // pre-/post-filter coefficient float x = 0.0f; // create cvsd decoder cvsd decoder = cvsd_create(nbits, zeta, alpha); // input bit sequence (random) unsigned char b[8] = {1, 1, 1, 0, 1, 0, 0, 0}; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += cvsd_decode(decoder, b[0]); x += cvsd_decode(decoder, b[2]); x += cvsd_decode(decoder, b[3]); x += cvsd_decode(decoder, b[3]); x += cvsd_decode(decoder, b[4]); x += cvsd_decode(decoder, b[5]); x += cvsd_decode(decoder, b[6]); x += cvsd_decode(decoder, b[7]); // randomize input b[0] ^= (x > 0); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 8; // destroy cvsd decoder cvsd_destroy(decoder); } liquid-dsp-1.7.0/src/audio/src/000077500000000000000000000000001474751757600163005ustar00rootroot00000000000000liquid-dsp-1.7.0/src/audio/src/cvsd.c000066400000000000000000000150121474751757600174020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // CVSD: continuously variable slope delta // #include #include #include "liquid.internal.h" // enable use of the pre-emphasis and post-emphasis filters #define CVSD_ENABLE_SIGNAL_CONDITIONING (1) struct cvsd_s { unsigned int num_bits; unsigned char bitref; // historical bit reference unsigned char bitmask; // historical bit reference mask float ref; // internal reference float zeta; // delta step factor float delta; // current step size float delta_min; // minimum delta float delta_max; // maximum delta #if CVSD_ENABLE_SIGNAL_CONDITIONING float alpha; // pre-/de-emphasis filter coefficient float beta; // DC-blocking coefficient (decoder) iirfilt_rrrf prefilt; // pre-emphasis filter (encoder) iirfilt_rrrf postfilt; // e-emphasis filter (decoder) #endif }; // create cvsd object // _num_bits : number of adjacent bits to observe // _zeta : slope adjustment multiplier // _alpha : pre-/post-emphasis filter coefficient (0.9 recommended) // NOTE: _alpha must be in [0,1] cvsd cvsd_create(unsigned int _num_bits, float _zeta, float _alpha) { if (_num_bits == 0) return liquid_error_config("cvsd_create(), _num_bits must be positive"); if (_zeta <= 1.0f) return liquid_error_config("cvsd_create(), zeta must be greater than 1"); if (_alpha < 0.0f || _alpha > 1.0f) return liquid_error_config("cvsd_create(), alpha must be in [0,1]"); cvsd q = (cvsd) malloc(sizeof(struct cvsd_s)); q->num_bits = _num_bits; q->bitref = 0; q->bitmask = (1<<(q->num_bits)) - 1; q->ref = 0.0f; q->zeta = _zeta; q->delta = 0.01f; q->delta_min = 0.01f; q->delta_max = 1.0f; #if CVSD_ENABLE_SIGNAL_CONDITIONING // design pre-emphasis filter q->alpha = _alpha; float b_pre[2] = {1.0f, -q->alpha}; float a_pre[2] = {1.0f, 0.0f}; q->prefilt = iirfilt_rrrf_create(b_pre,2,a_pre,2); // design post-emphasis filter q->beta = 0.99f; // DC-blocking parameter float b_post[3] = {1.0f, -1.0f, 0.0f}; float a_post[3] = {1.0f, -(q->alpha + q->beta), q->alpha*q->beta}; q->postfilt = iirfilt_rrrf_create(b_post,3,a_post,3); #endif return q; } // destroy cvsd object int cvsd_destroy(cvsd _q) { #if CVSD_ENABLE_SIGNAL_CONDITIONING // destroy filters iirfilt_rrrf_destroy(_q->prefilt); iirfilt_rrrf_destroy(_q->postfilt); #endif // free main object memory free(_q); return LIQUID_OK; } // print cvsd object parameters int cvsd_print(cvsd _q) { printf("num_bits, _q->zeta); #if CVSD_ENABLE_SIGNAL_CONDITIONING printf(", alpha=%g", _q->alpha); #endif printf(">\n"); return LIQUID_OK; } // encode single sample unsigned char cvsd_encode(cvsd _q, float _audio_sample) { // push audio sample through pre-filter float y; #if CVSD_ENABLE_SIGNAL_CONDITIONING iirfilt_rrrf_execute(_q->prefilt, _audio_sample, &y); #else y = _audio_sample; #endif // determine output value unsigned char bit = (_q->ref > y) ? 0 : 1; // shift last value into buffer _q->bitref <<= 1; _q->bitref |= bit; _q->bitref &= _q->bitmask; // update delta if (_q->bitref == 0 || _q->bitref == _q->bitmask) _q->delta *= _q->zeta; // increase delta else _q->delta /= _q->zeta; // decrease delta // limit delta _q->delta = (_q->delta > _q->delta_max) ? _q->delta_max : _q->delta; _q->delta = (_q->delta < _q->delta_min) ? _q->delta_min : _q->delta; // update reference _q->ref += (bit) ? _q->delta : -_q->delta; // limit reference _q->ref = (_q->ref > 1.0f) ? 1.0f : _q->ref; _q->ref = (_q->ref < -1.0f) ? -1.0f : _q->ref; return bit; } // decode single sample float cvsd_decode(cvsd _q, unsigned char _bit) { // append bit into register _q->bitref <<= 1; _q->bitref |= (_bit & 0x01); _q->bitref &= _q->bitmask; // update delta if (_q->bitref == 0 || _q->bitref == _q->bitmask) _q->delta *= _q->zeta; // increase delta else _q->delta /= _q->zeta; // decrease delta // limit delta _q->delta = (_q->delta > _q->delta_max) ? _q->delta_max : _q->delta; _q->delta = (_q->delta < _q->delta_min) ? _q->delta_min : _q->delta; // update reference _q->ref += (_bit&0x01) ? _q->delta : -_q->delta; // limit reference _q->ref = (_q->ref > 1.0f) ? 1.0f : _q->ref; _q->ref = (_q->ref < -1.0f) ? -1.0f : _q->ref; // push reference value through post-filter float y; #if CVSD_ENABLE_SIGNAL_CONDITIONING iirfilt_rrrf_execute(_q->postfilt, _q->ref, &y); #else y = _q->ref; #endif return y; } // encode 8 samples int cvsd_encode8(cvsd _q, float * _audio, unsigned char * _data) { unsigned char data=0x00; unsigned int i; for (i=0; i<8; i++) { data <<= 1; data |= cvsd_encode(_q, _audio[i]); } // set return value *_data = data; return LIQUID_OK; } // decode 8 samples int cvsd_decode8(cvsd _q, unsigned char _data, float * _audio) { unsigned char bit; unsigned int i; for (i=0; i<8; i++) { bit = (_data >> (8-i-1)) & 0x01; _audio[i] = cvsd_decode(_q, bit); } return LIQUID_OK; } liquid-dsp-1.7.0/src/audio/tests/000077500000000000000000000000001474751757600166535ustar00rootroot00000000000000liquid-dsp-1.7.0/src/audio/tests/cvsd_autotest.c000066400000000000000000000075541474751757600217210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // check RMS error void autotest_cvsd_rmse_sine() { unsigned int n=256; unsigned int nbits=3; float zeta=1.5f; float alpha=0.90f; // create cvsd codecs cvsd cvsd_encoder = cvsd_create(nbits,zeta,alpha); cvsd cvsd_decoder = cvsd_create(nbits,zeta,alpha); CONTEND_EQUALITY(cvsd_print(cvsd_encoder), LIQUID_OK); float phi=0.0f; float dphi=0.1f; unsigned int i; unsigned char b; float x,y; float rmse=0.0f; for (i=0; i #include #include #include "liquid.internal.h" #define CBUFFERCF_BENCH_API(N, W, R) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { cbuffercf_bench(_start, _finish, _num_iterations, N, W, R); } // Helper function to keep code base small int cbuffercf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n, unsigned int _write_size, unsigned int _read_size) { // validate input if (_n < 2) return liquid_error(LIQUID_EICONFIG,"cbuffercf_bench(), number of elements must be at least 2"); if (_write_size > _n-1) return liquid_error(LIQUID_EICONFIG,"cbuffercf_bench(), write size must be in (0,n)"); if (_read_size > _n-1) return liquid_error(LIQUID_EICONFIG,"cbuffercf_bench(), read size must be in (0,n)"); // normalize number of iterations *_num_iterations *= _n; // create object cbuffercf q = cbuffercf_create(_n); // float complex v[_write_size]; // array for writing float complex * r; // read pointer unsigned int num_requested; // number of elements requested unsigned int num_read; // number of elements read // initialize array for writing unsigned int i; for (i=0; i<_write_size; i++) v[i] = 0.0f; // accumulate total number of elements unsigned long int num_total_elements = 0; // start trials getrusage(RUSAGE_SELF, _start); while (num_total_elements < *_num_iterations) { // write elements to buffer if space is available if (_n - cbuffercf_size(q) > _write_size) cbuffercf_write(q, v, _write_size); // read up to '_read_size' elements num_requested = _read_size; cbuffercf_read(q, num_requested, &r, &num_read); // release elements that were read cbuffercf_release(q, num_read); // increment counter by number of elements passing through num_total_elements += num_read; } getrusage(RUSAGE_SELF, _finish); // total number of iterations equal to to total number of elements // that have passed through the buffer *_num_iterations = num_total_elements; // clean up allocated memory cbuffercf_destroy(q); return LIQUID_OK; } // void benchmark_cbuffercf_n16 CBUFFERCF_BENCH_API( 16, 12, 11); void benchmark_cbuffercf_n32 CBUFFERCF_BENCH_API( 32, 24, 23); void benchmark_cbuffercf_n64 CBUFFERCF_BENCH_API( 64, 48, 47); void benchmark_cbuffercf_n128 CBUFFERCF_BENCH_API( 128, 96, 95); void benchmark_cbuffercf_n256 CBUFFERCF_BENCH_API( 256, 192, 191); void benchmark_cbuffercf_n512 CBUFFERCF_BENCH_API( 512, 384, 383); void benchmark_cbuffercf_n1024 CBUFFERCF_BENCH_API(1024, 768, 767); liquid-dsp-1.7.0/src/buffer/bench/window_push_benchmark.c000066400000000000000000000047471474751757600235000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" #define WINDOW_PUSH_BENCH_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { window_push_bench(_start, _finish, _num_iterations, N); } // Helper function to keep code base small void window_push_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations *= 8; if (*_num_iterations < 1) *_num_iterations = 1; // initialize port windowcf w = windowcf_create(_n); unsigned long int i; // start trials: // write to port, read from port getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); windowcf_push(w, 1.0f); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; windowcf_destroy(w); } // void benchmark_windowcf_push_n16 WINDOW_PUSH_BENCH_API(16) void benchmark_windowcf_push_n32 WINDOW_PUSH_BENCH_API(32) void benchmark_windowcf_push_n64 WINDOW_PUSH_BENCH_API(64) void benchmark_windowcf_push_n128 WINDOW_PUSH_BENCH_API(128) void benchmark_windowcf_push_n256 WINDOW_PUSH_BENCH_API(256) liquid-dsp-1.7.0/src/buffer/bench/window_read_benchmark.c000066400000000000000000000050731474751757600234250ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" #define WINDOW_READ_BENCH_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { window_read_bench(_start, _finish, _num_iterations, N); } // Helper function to keep code base small void window_read_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations if (*_num_iterations < 1) *_num_iterations = 1; // initialize port windowcf w = windowcf_create(_n); unsigned long int i; float complex * r; // start trials: // write to buffer, read from buffer getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); windowcf_push(w,1.0f); windowcf_read(w, &r); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; windowcf_destroy(w); } // void benchmark_windowcf_read_n16 WINDOW_READ_BENCH_API(16) void benchmark_windowcf_read_n32 WINDOW_READ_BENCH_API(32) void benchmark_windowcf_read_n64 WINDOW_READ_BENCH_API(64) void benchmark_windowcf_read_n128 WINDOW_READ_BENCH_API(128) void benchmark_windowcf_read_n256 WINDOW_READ_BENCH_API(256) liquid-dsp-1.7.0/src/buffer/src/000077500000000000000000000000001474751757600164505ustar00rootroot00000000000000liquid-dsp-1.7.0/src/buffer/src/buffer.proto.c000066400000000000000000000156701474751757600212400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Buffers, defined by macro // #include #include #include #include "liquid.internal.h" struct BUFFER(_s) { T * v; unsigned int len; // length of buffer unsigned int N; // number of elements allocated // in memory unsigned int num_elements; // number of elements currently // in the buffer unsigned int read_index; unsigned int write_index; buffer_type type; // mutex/semaphore }; BUFFER() BUFFER(_create)(buffer_type _type, unsigned int _n) { BUFFER() b = (BUFFER()) malloc(sizeof(struct BUFFER(_s))); b->type = _type; b->len = _n; if (b->type == CIRCULAR) b->N = 2*(b->len) - 1; else b->N = b->len; b->v = (T*) malloc((b->N)*sizeof(T)); b->num_elements = 0; b->read_index = 0; b->write_index = 0; return b; } void BUFFER(_destroy)(BUFFER() _b) { free(_b->v); free(_b); } void BUFFER(_print)(BUFFER() _b) { if (_b->type == CIRCULAR) printf("circular "); else printf("static "); printf("buffer [%u elements] :\n", _b->num_elements); unsigned int i; for (i=0; i<_b->num_elements; i++) { printf("%u", i); BUFFER_PRINT_LINE(_b,(_b->read_index+i)%(_b->len)) printf("\n"); } } void BUFFER(_debug_print)(BUFFER() _b) { if (_b->type == CIRCULAR) printf("circular "); else printf("static "); printf("buffer [%u elements] :\n", _b->num_elements); unsigned int i; for (i=0; i<_b->len; i++) { // print read index pointer if (i==_b->read_index) printf(""); // print write index pointer if (i==_b->write_index) printf(""); // print buffer value BUFFER_PRINT_LINE(_b,i) printf("\n"); } printf("----------------------------------\n"); // print excess buffer memory for (i=_b->len; i<_b->N; i++) { BUFFER_PRINT_LINE(_b,i) printf("\n"); } } void BUFFER(_clear)(BUFFER() _b) { _b->read_index = 0; _b->write_index = 0; _b->num_elements = 0; } void BUFFER(_zero)(BUFFER() _b) { _b->read_index = 0; _b->write_index = 0; _b->num_elements = _b->len; memset(_b->v, 0, (_b->num_elements)*sizeof(T)); } void BUFFER(_read)(BUFFER() _b, T ** _v, unsigned int *_n) { if (_b->type == CIRCULAR) BUFFER(_c_read)(_b, _v, _n); else BUFFER(_s_read)(_b, _v, _n); } void BUFFER(_c_read)(BUFFER() _b, T ** _v, unsigned int *_n) { //printf("buffer_read() trying to read %u elements (%u available)\n", *_n, _b->num_elements); if (*_n > _b->num_elements) { liquid_error(LIQUID_EIRANGE,"buffer%s_read(), cannot read more elements than are available", EXTENSION); *_v = NULL; *_n = 0; return; } else if (*_n > (_b->len - _b->read_index)) { // BUFFER(_linearize)(_b); } *_v = _b->v + _b->read_index; *_n = _b->num_elements; } void BUFFER(_s_read)(BUFFER() _b, T ** _v, unsigned int *_n) { //printf("buffer_s_read() reading %u elements\n", _b->num_elements); *_v = _b->v; *_n = _b->num_elements; } void BUFFER(_release)(BUFFER() _b, unsigned int _n) { if (_b->type == CIRCULAR) BUFFER(_c_release)(_b, _n); else BUFFER(_s_release)(_b, _n); } void BUFFER(_c_release)(BUFFER() _b, unsigned int _n) { // advance read_index by _n making sure not to step on write_index if (_n > _b->num_elements) { liquid_error(LIQUID_EIRANGE,"buffer%s_c_release(), cannot release more elements in buffer than exist", EXTENSION); return; } _b->read_index = (_b->read_index + _n) % _b->len; _b->num_elements -= _n; } void BUFFER(_s_release)(BUFFER() _b, unsigned int _n) { BUFFER(_clear)(_b); } void BUFFER(_write)(BUFFER() _b, T * _v, unsigned int _n) { if (_b->type == CIRCULAR) BUFFER(_c_write)(_b, _v, _n); else BUFFER(_s_write)(_b, _v, _n); } void BUFFER(_c_write)(BUFFER() _b, T * _v, unsigned int _n) { // if (_n > (_b->len - _b->num_elements)) { liquid_error(LIQUID_EIRANGE,"buffer%s_write(), cannot write more elements than are available", EXTENSION); return; } _b->num_elements += _n; // space available at end of buffer unsigned int k = _b->len - _b->write_index; //printf("n : %u, k : %u\n", _n, k); // check for condition where we need to wrap around if (_n > k) { memcpy(_b->v + _b->write_index, _v, k*sizeof(T)); memcpy(_b->v, &_v[k], (_n-k)*sizeof(T)); _b->write_index = _n - k; } else { memcpy(_b->v + _b->write_index, _v, _n*sizeof(T)); _b->write_index += _n; } } void BUFFER(_s_write)(BUFFER() _b, T * _v, unsigned int _n) { if (_n > (_b->len - _b->num_elements)) { liquid_error(LIQUID_EIRANGE,"buffer%s_s_write(), cannot write more elements than are available", EXTENSION); return; } memcpy(_b->v + _b->num_elements, _v, _n*sizeof(T)); _b->num_elements += _n; } //void BUFFER(_force_write)(BUFFER() _b, T * _v, unsigned int _n) void BUFFER(_push)(BUFFER() _b, T _v) { // push value (force write) if (_b->type == CIRCULAR) BUFFER(_c_push)(_b, _v); else BUFFER(_s_push)(_b, _v); } void BUFFER(_c_push)(BUFFER() _b, T _v) { _b->v[_b->write_index] = _v; if (_b->num_elements < _b->len) { _b->num_elements++; } else { _b->read_index = (_b->read_index+1) % _b->len; } _b->write_index = (_b->write_index+1) % _b->len; } void BUFFER(_s_push)(BUFFER() _b, T _v) { } void BUFFER(_linearize)(BUFFER() _b) { // check to see if anything needs to be done if ( (_b->len - _b->read_index) > _b->num_elements) return; // perform memory copy memcpy(_b->v + _b->len, _b->v, (_b->write_index)*sizeof(T)); } liquid-dsp-1.7.0/src/buffer/src/buffercf.c000066400000000000000000000033561474751757600204050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex Float buffer // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION "cf" #define BUFFER_TYPE_CFLOAT #define CBUFFER(name) LIQUID_CONCAT(cbuffercf, name) #define WDELAY(name) LIQUID_CONCAT(wdelaycf, name) #define WINDOW(name) LIQUID_CONCAT(windowcf, name) #define T float complex #define BUFFER_PRINT_LINE(B,I) \ printf(" : %12.8f + %12.8f", crealf(B->v[I]), cimagf(B->v[I])); #define BUFFER_PRINT_VALUE(V) \ printf(" : %12.4e + %12.4e", crealf(V), cimagf(V)); // prototypes #include "cbuffer.proto.c" #include "window.proto.c" #include "wdelay.proto.c" liquid-dsp-1.7.0/src/buffer/src/bufferf.c000066400000000000000000000032331474751757600202340ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Float buffer // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION "f" #define BUFFER_TYPE_FLOAT #define CBUFFER(name) LIQUID_CONCAT(cbufferf, name) #define WDELAY(name) LIQUID_CONCAT(wdelayf, name) #define WINDOW(name) LIQUID_CONCAT(windowf, name) #define T float #define BUFFER_PRINT_LINE(B,I) \ printf(" : %12.8f", B->v[I]); #define BUFFER_PRINT_VALUE(V) \ printf(" : %12.4e", V); // prototypes #include "cbuffer.proto.c" #include "wdelay.proto.c" #include "window.proto.c" liquid-dsp-1.7.0/src/buffer/src/cbuffer.proto.c000066400000000000000000000213361474751757600213770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // circular buffer // #include #include #include #include "liquid.internal.h" // linearize buffer (if necessary) int CBUFFER(_linearize)(CBUFFER() _q); // cbuffer object struct CBUFFER(_s) { // allocated memory array T * v; // length of buffer unsigned int max_size; // maximum number of elements that can be read at any given time unsigned int max_read; // number of elements allocated in memory unsigned int num_allocated; // number of elements currently in buffer unsigned int num_elements; // index to read unsigned int read_index; // index to write unsigned int write_index; }; // create circular buffer object of a particular size CBUFFER() CBUFFER(_create)(unsigned int _max_size) { // create main object CBUFFER() q = CBUFFER(_create_max)(_max_size, _max_size); // return main object return q; } // create circular buffer object of a particular size and // specify the maximum number of elements that can be read // at any given time. CBUFFER() CBUFFER(_create_max)(unsigned int _max_size, unsigned int _max_read) { // create main object CBUFFER() q = (CBUFFER()) malloc(sizeof(struct CBUFFER(_s))); // set internal properties q->max_size = _max_size; q->max_read = _max_read; // internal memory allocation q->num_allocated = q->max_size + q->max_read - 1; // allocate internal memory array q->v = (T*) malloc((q->num_allocated)*sizeof(T)); // reset object CBUFFER(_reset)(q); // return main object return q; } // copy object CBUFFER() CBUFFER(_copy)(CBUFFER() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("error: cbuffer%s_copy(), window object cannot be NULL", EXTENSION); // create initial object CBUFFER() q_copy = (CBUFFER()) malloc(sizeof(struct CBUFFER(_s))); memmove(q_copy, q_orig, sizeof(struct CBUFFER(_s))); // allocate and copy full memory array q_copy->v = (T*) malloc((q_copy->num_allocated)*sizeof(T)); memmove(q_copy->v, q_orig->v, q_copy->num_allocated*sizeof(T)); // return new object return q_copy; } // destroy cbuffer object, freeing all internal memory int CBUFFER(_destroy)(CBUFFER() _q) { free(_q->v); free(_q); return LIQUID_OK; } // print cbuffer object properties int CBUFFER(_print)(CBUFFER() _q) { printf("\n", EXTENSION, _q->max_size, _q->max_read, _q->num_elements); return LIQUID_OK; } // clear internal buffer int CBUFFER(_reset)(CBUFFER() _q) { _q->read_index = 0; _q->write_index = 0; _q->num_elements = 0; return LIQUID_OK; } // get the number of elements currently in the buffer unsigned int CBUFFER(_size)(CBUFFER() _q) { return _q->num_elements; } // get the maximum number of elements the buffer can hold unsigned int CBUFFER(_max_size)(CBUFFER() _q) { return _q->max_size; } // get the maximum number of elements that can be read from // the buffer at any given time. unsigned int CBUFFER(_max_read)(CBUFFER() _q) { return _q->max_read; } // return number of elements available for writing unsigned int CBUFFER(_space_available)(CBUFFER() _q) { return _q->max_size - _q->num_elements; } // is buffer empty? int CBUFFER(_is_empty)(CBUFFER() _q) { return _q->num_elements == 0; } // is buffer full? int CBUFFER(_is_full)(CBUFFER() _q) { return (_q->num_elements == _q->max_size ? 1 : 0); } // write a single sample into the buffer // _q : circular buffer object // _v : input sample int CBUFFER(_push)(CBUFFER() _q, T _v) { // ensure buffer isn't already full if (_q->num_elements == _q->max_size) { return liquid_error(LIQUID_EIRANGE,"cbuffer%s_push(), no space available", EXTENSION); } // add sample at write index _q->v[_q->write_index] = _v; // update write index _q->write_index = (_q->write_index+1) % _q->max_size; // increment number of elements _q->num_elements++; return LIQUID_OK; } // write samples to the buffer // _q : circular buffer object // _v : output array // _n : number of samples to write int CBUFFER(_write)(CBUFFER() _q, T * _v, unsigned int _n) { // ensure number of samples to write doesn't exceed space available if (_n > (_q->max_size - _q->num_elements)) { return liquid_error(LIQUID_EIRANGE,"cbuffer%s_write(), cannot write more elements than are available", EXTENSION); } _q->num_elements += _n; // space available at end of buffer unsigned int k = _q->max_size - _q->write_index; //printf("n : %u, k : %u\n", _n, k); // check for condition where we need to wrap around if (_n > k) { memmove(_q->v + _q->write_index, _v, k*sizeof(T)); memmove(_q->v, &_v[k], (_n-k)*sizeof(T)); _q->write_index = _n - k; } else { memmove(_q->v + _q->write_index, _v, _n*sizeof(T)); _q->write_index += _n; } return LIQUID_OK; } // remove and return a single element from the buffer // _q : circular buffer object // _v : pointer to sample output int CBUFFER(_pop)(CBUFFER() _q, T * _v) { // ensure there is at least one element if (_q->num_elements == 0) { return liquid_error(LIQUID_EIRANGE,"cbuffer%s_pop(), no elements available",EXTENSION); } // set return value if (_v != NULL) *_v = _q->v[ _q->read_index ]; // increment read index _q->read_index = (_q->read_index + 1) % _q->max_size; // decrement number of elements in the buffer _q->num_elements--; return LIQUID_OK; } // read buffer contents // _q : circular buffer object // _num_requested : number of elements requested // _v : output pointer // _nr : number of elements referenced by _v int CBUFFER(_read)(CBUFFER() _q, unsigned int _num_requested, T ** _v, unsigned int * _num_read) { // adjust number requested depending upon availability if (_num_requested > _q->num_elements) _num_requested = _q->num_elements; // restrict maximum number of elements to originally specified value if (_num_requested > _q->max_read) _num_requested = _q->max_read; // linearize tail end of buffer if necessary if (_num_requested > (_q->max_size - _q->read_index)) CBUFFER(_linearize)(_q); // set output pointer appropriately *_v = _q->v + _q->read_index; *_num_read = _num_requested; return LIQUID_OK; } // release _n samples in the buffer int CBUFFER(_release)(CBUFFER() _q, unsigned int _n) { // advance read_index by _n making sure not to step on write_index if (_n > _q->num_elements) { return liquid_error(LIQUID_EIRANGE,"cbuffer%s_release(), cannot release more elements in buffer than exist",EXTENSION); } _q->read_index = (_q->read_index + _n) % _q->max_size; _q->num_elements -= _n; return LIQUID_OK; } // // internal methods // // internal linearization int CBUFFER(_linearize)(CBUFFER() _q) { #if 0 // check to see if anything needs to be done if ( (_q->max_size - _q->read_index) > _q->num_elements) return; #endif //printf("cbuffer linearize: [%6u : %6u], num elements: %6u, read index: %6u, write index: %6u\n", // _q->max_size, _q->max_read-1, _q->num_elements, _q->read_index, _q->write_index); // move maximum amount memmove(_q->v + _q->max_size, _q->v, (_q->max_read-1)*sizeof(T)); return LIQUID_OK; } liquid-dsp-1.7.0/src/buffer/src/wdelay.proto.c000066400000000000000000000104261474751757600212460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // windowed delay, defined by macro // #include "liquid.internal.h" #include #include #include struct WDELAY(_s) { T * v; // allocated array pointer unsigned int delay; // length of window unsigned int read_index; // index for reading }; // create delay buffer object with '_delay' samples WDELAY() WDELAY(_create)(unsigned int _delay) { // create main object WDELAY() q = (WDELAY()) malloc(sizeof(struct WDELAY(_s))); // set internal values q->delay = _delay; // allocate memory q->v = (T*) malloc((q->delay+1)*sizeof(T)); q->read_index = 0; // clear window WDELAY(_reset)(q); return q; } // re-create delay buffer object with '_delay' samples // _q : old delay buffer object // _delay : delay for new object WDELAY() WDELAY(_recreate)(WDELAY() _q, unsigned int _delay) { // copy internal buffer, re-aligned unsigned int ktmp = _q->delay+1; T * vtmp = (T*) malloc((_q->delay+1) * sizeof(T)); unsigned int i; for (i=0; i<_q->delay+1; i++) vtmp[i] = _q->v[ (i + _q->read_index) % (_q->delay+1) ]; // destroy object and re-create it WDELAY(_destroy)(_q); _q = WDELAY(_create)(_delay); // push old values for (i=0; iv = (T*) malloc((q_copy->delay+1)*sizeof(T)); memmove(q_copy->v, q_orig->v, (q_copy->delay+1)*sizeof(T)); // return new object return q_copy; } // destroy delay buffer object, freeing internal memory int WDELAY(_destroy)(WDELAY() _q) { // free internal array buffer free(_q->v); // free main object memory free(_q); return LIQUID_OK; } // print delay buffer object's state to stdout int WDELAY(_print)(WDELAY() _q) { printf("\n", _q->delay); return LIQUID_OK; } // clear/reset state of object int WDELAY(_reset)(WDELAY() _q) { _q->read_index = 0; memset(_q->v, 0, (_q->delay+1)*sizeof(T)); return LIQUID_OK; } // read delayed sample from delay buffer object // _q : delay buffer object // _v : value of delayed element int WDELAY(_read)(WDELAY() _q, T * _v) { // return value at end of buffer *_v = _q->v[_q->read_index]; return LIQUID_OK; } // push new sample into delay buffer object // _q : delay buffer object // _v : new value to be added to buffer int WDELAY(_push)(WDELAY() _q, T _v) { // append value to end of buffer _q->v[_q->read_index] = _v; // increment index _q->read_index++; // wrap around pointer _q->read_index %= (_q->delay+1); return LIQUID_OK; } liquid-dsp-1.7.0/src/buffer/src/window.proto.c000066400000000000000000000155661474751757600213020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // circular window buffer // #include "liquid.internal.h" #include #include #include struct WINDOW(_s) { T * v; // allocated array pointer unsigned int len; // length of window unsigned int m; // floor(log2(len)) + 1 unsigned int n; // 2^m unsigned int mask; // n-1 unsigned int num_allocated; // number of elements allocated // in memory unsigned int read_index; }; // create window buffer object of length _n WINDOW() WINDOW(_create)(unsigned int _n) { // validate input if (_n == 0) return liquid_error_config("error: window%s_create(), window size must be greater than zero", EXTENSION); // create initial object WINDOW() q = (WINDOW()) malloc(sizeof(struct WINDOW(_s))); // set internal parameters q->len = _n; // nominal window size q->m = liquid_msb_index(_n); // effectively floor(log2(len))+1 q->n = 1<<(q->m); // 2^m q->mask = q->n - 1; // bit mask // number of elements to allocate to memory q->num_allocated = q->n + q->len - 1; // allocate memory q->v = (T*) malloc((q->num_allocated)*sizeof(T)); q->read_index = 0; // reset window WINDOW(_reset)(q); // return object return q; } // recreate window buffer object with new length // _q : old window object // _n : new window length WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n) { // TODO: only create new window if old is too small if (_n == _q->len) return _q; // create new window WINDOW() w = WINDOW(_create)(_n); // copy old values T* r; WINDOW(_read)(_q, &r); //memmove(q->v, ...); unsigned int i; if (_n > _q->len) { // new buffer is larger; push zeros, then old values for (i=0; i<(_n-_q->len); i++) WINDOW(_push)(w, 0); for (i=0; i<_q->len; i++) WINDOW(_push)(w, r[i]); } else { // new buffer is shorter; push latest old values for (i=(_q->len-_n); i<_q->len; i++) WINDOW(_push)(w, r[i]); } // destroy old window WINDOW(_destroy)(_q); return w; } // copy object WINDOW() WINDOW(_copy)(WINDOW() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("error: window%s_copy(), window object cannot be NULL", EXTENSION); // create object, copy memory, create new elements as needed WINDOW() q_copy = (WINDOW()) malloc(sizeof(struct WINDOW(_s))); memmove(q_copy, q_orig, sizeof(struct WINDOW(_s))); // allocate and copy full memory array q_copy->v = (T*) liquid_malloc_copy(q_copy->v, q_copy->num_allocated, sizeof(T)); // return new object return q_copy; } // destroy window object, freeing all internally memory int WINDOW(_destroy)(WINDOW() _q) { // free internal memory array free(_q->v); // free main object memory free(_q); return LIQUID_OK; } // print window object to stdout int WINDOW(_print)(WINDOW() _q) { printf("window [%u elements] :\n", _q->len); unsigned int i; T * r; WINDOW(_read)(_q, &r); for (i=0; i<_q->len; i++) { printf("%4u", i); BUFFER_PRINT_VALUE(r[i]); printf("\n"); } return LIQUID_OK; } // print window object to stdout (with extra information) int WINDOW(_debug_print)(WINDOW() _q) { printf("window [%u elements] :\n", _q->len); unsigned int i; for (i=0; i<_q->len; i++) { // print read index pointer if (i==_q->read_index) printf(""); // print window value BUFFER_PRINT_LINE(_q,i) printf("\n"); } printf("----------------------------------\n"); // print excess window memory for (i=_q->len; i<_q->num_allocated; i++) { BUFFER_PRINT_LINE(_q,i) printf("\n"); } return LIQUID_OK; } // reset window object (initialize to zeros) int WINDOW(_reset)(WINDOW() _q) { // reset read index _q->read_index = 0; // clear all allocated memory memset(_q->v, 0, (_q->num_allocated)*sizeof(T)); return LIQUID_OK; } // read window buffer contents // _q : window object // _v : output pointer (set to internal array) int WINDOW(_read)(WINDOW() _q, T ** _v) { // return pointer to buffer *_v = _q->v + _q->read_index; return LIQUID_OK; } // index single element in buffer at a particular index // _q : window object // _i : index of element to read // _v : output value pointer int WINDOW(_index)(WINDOW() _q, unsigned int _i, T * _v) { // validate input if (_i >= _q->len) return liquid_error(LIQUID_EIRANGE,"error: window_index(), index value out of range"); // return value at index *_v = _q->v[_q->read_index + _i]; return LIQUID_OK; } // push single element onto window buffer // _q : window object // _v : single input element int WINDOW(_push)(WINDOW() _q, T _v) { // increment index _q->read_index++; // wrap around pointer _q->read_index &= _q->mask; // if pointer wraps around, copy excess memory if (_q->read_index == 0) memmove(_q->v, _q->v + _q->n, (_q->len-1)*sizeof(T)); // append value to end of buffer _q->v[_q->read_index + _q->len - 1] = _v; return LIQUID_OK; } // write array of elements onto window buffer // _q : window object // _v : input array of values to write // _n : number of input values to write int WINDOW(_write)(WINDOW() _q, T * _v, unsigned int _n) { // TODO make this more efficient unsigned int i; for (i=0; i<_n; i++) WINDOW(_push)(_q, _v[i]); return LIQUID_OK; } liquid-dsp-1.7.0/src/buffer/tests/000077500000000000000000000000001474751757600170235ustar00rootroot00000000000000liquid-dsp-1.7.0/src/buffer/tests/buffer_window_autotest.c000066400000000000000000000123371474751757600237650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" void autotest_window_config_errors() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping window config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif CONTEND_EXPRESSION(windowcf_create(0)==NULL); CONTEND_EXPRESSION(windowf_create (0)==NULL); } void autotest_windowf() { float v[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; float *r; // reader pointer float x; // temporary value holder float test0[10] = {0,0,0,0,0,0,0,0,0,0}; float test1[10] = {0,0,0,0,0,0,1,1,1,1}; float test2[10] = {0,0,1,1,1,1,9,8,7,6}; float test3[10] = {1,1,9,8,7,6,3,3,3,3}; float test4[10] = {7,6,3,3,3,3,5,5,5,5}; float test5[6] = {3,3,5,5,5,5}; float test6[6] = {5,5,5,5,6,7}; float test7[10] = {0,0,0,0,5,5,5,5,6,7}; float test8[10] = {0,0,0,0,0,0,0,0,0,0}; // create window // 0 0 0 0 0 0 0 0 0 0 windowf w = windowf_create(10); windowf_read(w, &r); CONTEND_SAME_DATA(r,test0,10*sizeof(float)); // push 4 elements // 0 0 0 0 0 0 1 1 1 1 windowf_push(w, 1); windowf_push(w, 1); windowf_push(w, 1); windowf_push(w, 1); windowf_read(w, &r); CONTEND_SAME_DATA(r,test1,10*sizeof(float)); // push 4 more elements // 0 0 1 1 1 1 9 8 7 6 windowf_write(w, v, 4); windowf_read(w, &r); CONTEND_SAME_DATA(r,test2,10*sizeof(float)); // push 4 more elements // 1 1 9 8 7 6 3 3 3 3 windowf_push(w, 3); windowf_push(w, 3); windowf_push(w, 3); windowf_push(w, 3); windowf_read(w, &r); CONTEND_SAME_DATA(r,test3,10*sizeof(float)); // test indexing operation windowf_index(w, 0, &x); CONTEND_EQUALITY(x, 1); windowf_index(w, 1, &x); CONTEND_EQUALITY(x, 1); windowf_index(w, 2, &x); CONTEND_EQUALITY(x, 9); windowf_index(w, 3, &x); CONTEND_EQUALITY(x, 8); windowf_index(w, 4, &x); CONTEND_EQUALITY(x, 7); windowf_index(w, 5, &x); CONTEND_EQUALITY(x, 6); windowf_index(w, 6, &x); CONTEND_EQUALITY(x, 3); windowf_index(w, 7, &x); CONTEND_EQUALITY(x, 3); windowf_index(w, 8, &x); CONTEND_EQUALITY(x, 3); windowf_index(w, 9, &x); CONTEND_EQUALITY(x, 3); CONTEND_INEQUALITY( windowf_index(w,999, &x), LIQUID_OK); // out of range // push 4 more elements // 7 6 3 3 3 3 5 5 5 5 windowf_push(w, 5); windowf_push(w, 5); windowf_push(w, 5); windowf_push(w, 5); windowf_read(w, &r); CONTEND_SAME_DATA(r,test4,10*sizeof(float)); if (liquid_autotest_verbose) windowf_debug_print(w); // recreate window (truncate to last 6 elements) // 3 3 5 5 5 5 w = windowf_recreate(w,6); windowf_read(w, &r); CONTEND_SAME_DATA(r,test5,6*sizeof(float)); // push 2 more elements // 5 5 5 5 6 7 windowf_push(w, 6); windowf_push(w, 7); windowf_read(w, &r); CONTEND_SAME_DATA(r,test6,6*sizeof(float)); // recreate window (extend to 10 elements) // 0 0 0 0 5 5 5 5 6 7 w = windowf_recreate(w,10); windowf_read(w,&r); CONTEND_SAME_DATA(r,test7,10*sizeof(float)); // reset // 0 0 0 0 0 0 0 0 0 0 windowf_reset(w); windowf_read(w, &r); CONTEND_SAME_DATA(r,test8,10*sizeof(float)); windowf_destroy(w); } void autotest_window_copy() { // create window unsigned int wlen = 20; windowcf q0 = windowcf_create(wlen); // write some values unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // floating point void autotest_cbufferf() { // input array of values float v[] = {1, 2, 3, 4, 5, 6, 7, 8}; // output test arrays float test1[] = {1, 2, 3, 4}; float test2[] = {3, 4, 1, 2, 3, 4, 5, 6, 7, 8}; float test3[] = {3, 4, 5, 6, 7, 8}; float test4[] = {3, 4, 5, 6, 7, 8, 1, 2, 3}; float *r; // output read pointer unsigned int num_requested; // number of samples requested unsigned int num_read; // number of samples read // create new circular buffer with 10 elements cbufferf q = cbufferf_create(10); // cbuffer: { } CONTEND_TRUE( cbufferf_is_empty(q) ); // part 1: write 4 elements to the buffer cbufferf_write(q, v, 4); // cbuffer: {1 2 3 4} CONTEND_FALSE( cbufferf_is_empty(q) ); // part 2: try to read 4 elements num_requested = 4; cbufferf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,4); CONTEND_SAME_DATA(r,test1,4*sizeof(float)); // part 3: release two elements, write 8 more, read 10 cbufferf_release(q, 2); // cbuffer: {3 4} cbufferf_write(q, v, 8); // cbuffer: {3 4 1 2 3 4 5 6 7 8} num_requested = 10; cbufferf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,10); CONTEND_SAME_DATA(r,test2,10*sizeof(float)); // part 4: pop single element from buffer CONTEND_EQUALITY( cbufferf_size(q), 10 ); cbufferf_pop(q, r); // cbuffer: {4 1 2 3 4 5 6 7 8} CONTEND_EQUALITY( cbufferf_size(q), 9 ); CONTEND_EQUALITY( *r, 3.0f ); // part 5: release three elements, and try reading 10 cbufferf_release(q, 3); // cbuffer: {3 4 5 6 7 8} num_requested = 10; cbufferf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,6); CONTEND_SAME_DATA(r,test3,6*sizeof(float)); // part 6: test pushing multiple elements cbufferf_push(q, 1); cbufferf_push(q, 2); cbufferf_push(q, 3); // cbuffer: {3 4 5 6 7 8 1 2 3} num_requested = 10; cbufferf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,9); CONTEND_SAME_DATA(r,test4,9*sizeof(float)); // part 7: add one more element; buffer should be full CONTEND_FALSE( cbufferf_is_full(q) ); cbufferf_push(q, 1); // cbuffer: {3 4 5 6 7 8 1 2 3 1} CONTEND_TRUE( cbufferf_is_full(q) ); // memory leaks are evil cbufferf_destroy(q); } // complex float complexing point void autotest_cbuffercf() { // input array of values float complex v[] = {1.0 - 1.0 * _Complex_I, 2.0 + 2.0 * _Complex_I, 3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I, 5.0 - 5.0 * _Complex_I, 6.0 + 6.0 * _Complex_I, 7.0 - 7.0 * _Complex_I, 8.0 + 8.0 * _Complex_I}; // output test arrays float complex test1[] = {1.0 - 1.0 * _Complex_I, 2.0 + 2.0 * _Complex_I, 3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I}; float complex test2[] = {3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I, 1.0 - 1.0 * _Complex_I, 2.0 + 2.0 * _Complex_I, 3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I, 5.0 - 5.0 * _Complex_I, 6.0 + 6.0 * _Complex_I, 7.0 - 7.0 * _Complex_I, 8.0 + 8.0 * _Complex_I}; float complex test3[] = {3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I, 5.0 - 5.0 * _Complex_I, 6.0 + 6.0 * _Complex_I, 7.0 - 7.0 * _Complex_I, 8.0 + 8.0 * _Complex_I}; float complex test4[] = {3.0 - 3.0 * _Complex_I, 4.0 + 4.0 * _Complex_I, 5.0 - 5.0 * _Complex_I, 6.0 + 6.0 * _Complex_I, 7.0 - 7.0 * _Complex_I, 8.0 + 8.0 * _Complex_I, 1.0 - 1.0 * _Complex_I, 2.0 + 2.0 * _Complex_I, 3.0 - 3.0 * _Complex_I}; float complex *r; // output read pointer unsigned int num_requested; // number of samples requested unsigned int num_read; // number of samples read // create new circular buffer with 10 elements cbuffercf q = cbuffercf_create(10); // cbuffer: { } CONTEND_TRUE( cbuffercf_is_empty(q) ); // part 1: write 4 elements to the buffer cbuffercf_write(q, v, 4); // cbuffer: {1 2 3 4} CONTEND_FALSE( cbuffercf_is_empty(q) ); // part 2: try to read 4 elements num_requested = 4; cbuffercf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,4); CONTEND_SAME_DATA(r,test1,4*sizeof(float complex)); // part 3: release two elements, write 8 more, read 10 cbuffercf_release(q, 2); // cbuffer: {3 4} cbuffercf_write(q, v, 8); // cbuffer: {3 4 1 2 3 4 5 6 7 8} num_requested = 10; cbuffercf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,10); CONTEND_SAME_DATA(r,test2,10*sizeof(float complex)); // part 4: pop single element from buffer CONTEND_EQUALITY( cbuffercf_size(q), 10 ); cbuffercf_pop(q, r); // cbuffer: {4 1 2 3 4 5 6 7 8} CONTEND_EQUALITY( cbuffercf_size(q), 9 ); CONTEND_EQUALITY( crealf(*r), 3.0f ); CONTEND_EQUALITY( cimagf(*r), -3.0f ); // part 5: release three elements, and try reading 10 cbuffercf_release(q, 3); // cbuffer: {3 4 5 6 7 8} num_requested = 10; cbuffercf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,6); CONTEND_SAME_DATA(r,test3,6*sizeof(float complex)); // part 6: test pushing multiple elements cbuffercf_push(q, 1.0 - 1.0 * _Complex_I); cbuffercf_push(q, 2.0 + 2.0 * _Complex_I); cbuffercf_push(q, 3.0 - 3.0 * _Complex_I); // cbuffer: {3 4 5 6 7 8 1 2 3} num_requested = 10; cbuffercf_read(q, num_requested, &r, &num_read); CONTEND_EQUALITY(num_read,9); CONTEND_SAME_DATA(r,test4,9*sizeof(float complex)); // part 7: add one more element; buffer should be full CONTEND_FALSE( cbuffercf_is_full(q) ); cbuffercf_push(q, 1.0 - 1.0 * _Complex_I); // cbuffer: {3 4 5 6 7 8 1 2 3 1} CONTEND_TRUE( cbuffercf_is_full(q) ); // memory leaks are evil cbuffercf_destroy(q); } // test general flow void autotest_cbufferf_flow() { // options unsigned int max_size = 48; // maximum number of elements in buffer unsigned int max_read = 17; // maximum number of elements to read unsigned int num_elements = 1200; // total number of elements for run // flag to indicate if test was successful int success = 1; // temporary buffer to write samples before sending to cbuffer float write_buffer[max_size]; // create new circular buffer cbufferf q = cbufferf_create_max(max_size, max_read); // unsigned i; unsigned write_id = 0; // running total number of values written unsigned read_id = 0; // running total number of values read // continue running until while (1) { // write some values unsigned int num_available_to_write = cbufferf_space_available(q); // write samples if space is available if (num_available_to_write > 0) { // number of elements to write unsigned int num_to_write = (rand() % num_available_to_write) + 1; // generate samples to write for (i=0; i 0) { // number of elements to read unsigned int num_to_read = rand() % num_available_to_read; // read samples float *r; // output read pointer unsigned int num_read; // number of samples read cbufferf_read(q, num_to_read, &r, &num_read); // compare results for (i=0; i= num_elements) break; } // ensure test was successful CONTEND_EXPRESSION(success == 1); // destroy object cbufferf_destroy(q); } // test invalid configurations, etc. void autotest_cbufferf_config() { // options unsigned int max_size = 48; // maximum number of elements in buffer unsigned int max_read = 17; // maximum number of elements to read float value; // create new circular buffer cbufferf q = cbufferf_create_max(max_size, max_read); // ensure test was successful CONTEND_EQUALITY(cbufferf_max_size(q), max_size); CONTEND_EQUALITY(cbufferf_max_read(q), max_read); // fill buffer with zeros while (cbufferf_space_available(q)) CONTEND_EQUALITY(cbufferf_push(q,0), LIQUID_OK); // ensure no errors with printing CONTEND_EQUALITY(cbufferf_print(q), LIQUID_OK); // buffer full; cannot write more CONTEND_INEQUALITY(cbufferf_push(q,0), LIQUID_OK); // reset cbufferf_reset(q); // buffer empty; cannot pop element or release any values CONTEND_INEQUALITY(cbufferf_pop (q,&value), LIQUID_OK); CONTEND_INEQUALITY(cbufferf_release(q,1), LIQUID_OK); // destroy object cbufferf_destroy(q); } // test copy void autotest_cbuffer_copy() { // create base object unsigned int wlen = 20; cbuffercf q0 = cbuffercf_create(wlen); // write some values unsigned int i; for (i=0; i #include #include #include // portable structured channel object struct CHANNEL(_s) { // additive white Gauss noise int enabled_awgn; // AWGN enabled? T gamma; // channel gain T nstd; // noise standard deviation float noise_floor; // noise floor density [dB] float snr; // signal-to-noise ratio [dB] // carrier offset int enabled_carrier; // carrier offset enabled? float dphi; // channel gain float phi; // noise standard deviation NCO() nco; // oscillator // multi-path channel int enabled_multipath; // enable multi-path channel filter? FIRFILT() channel_filter; // multi-path channel filter object TC * h; // multi-path channel filter coefficients unsigned int h_len; // multi-path channel filter length // shadowing channel int enabled_shadowing; // enable shadowing? IIRFILT() shadowing_filter; // shadowing filter object float shadowing_std; // shadowing standard deviation float shadowing_fd; // shadowing Doppler frequency }; // create structured channel object with default parameters CHANNEL() CHANNEL(_create)(void) { CHANNEL() q = (CHANNEL()) malloc(sizeof(struct CHANNEL(_s))); // initialize all options as off q->enabled_awgn = 0; q->enabled_carrier = 0; q->enabled_multipath = 0; q->enabled_shadowing = 0; // create internal objects q->nco = NCO(_create)(LIQUID_VCO); q->h_len = 1; q->h = (TC*) malloc(q->h_len*sizeof(TC)); q->h[0] = 1.0f; q->channel_filter = FIRFILT(_create)(q->h, q->h_len); q->shadowing_filter = NULL; // return object return q; } // copy object CHANNEL() CHANNEL(_copy)(CHANNEL() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("channel_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters CHANNEL() q_copy = (CHANNEL()) malloc(sizeof(struct CHANNEL(_s))); memmove(q_copy, q_orig, sizeof(struct CHANNEL(_s))); // copy nco q_copy->nco = NCO(_copy)(q_orig->nco); // copy channel filter q_copy->h = (TC*) malloc(q_copy->h_len*sizeof(TC)); memmove(q_copy->h, q_orig->h, q_copy->h_len*sizeof(TC)); q_copy->channel_filter = FIRFILT(_copy)(q_orig->channel_filter); // copying shadowing filter if (q_orig->shadowing_filter != NULL) q_copy->shadowing_filter = IIRFILT(_copy)(q_orig->shadowing_filter); return q_copy; } // destroy channel object int CHANNEL(_destroy)(CHANNEL() _q) { // destroy internal objects NCO(_destroy)(_q->nco); FIRFILT(_destroy)(_q->channel_filter); if (_q->shadowing_filter != NULL) IIRFILT(_destroy)(_q->shadowing_filter); free(_q->h); // free main object memory free(_q); return LIQUID_OK; } // print channel object int CHANNEL(_print)(CHANNEL() _q) { printf("channel\n"); if (_q->enabled_awgn) printf(" AWGN: SNR=%.3f dB, gamma=%.3f, std=%.6f\n", _q->snr, _q->gamma, _q->nstd); if (_q->enabled_carrier) printf(" carrier: dphi=%.3f, phi=%.3f\n", _q->dphi, _q->phi); if (_q->enabled_multipath) printf(" multipath: h_len=%u\n", _q->h_len); if (_q->enabled_shadowing) printf(" shadowing: std=%.3fdB, fd=%.3f\n", _q->shadowing_std, _q->shadowing_fd); return LIQUID_OK; } // apply additive white Gausss noise impairment // _q : channel object // _noise_floor : noise floor power spectral density // _snr : signal-to-noise ratio [dB] int CHANNEL(_add_awgn)(CHANNEL() _q, float _noise_floor, float _snr) { // enable module _q->enabled_awgn = 1; // _q->noise_floor = _noise_floor; _q->snr = _snr; // set values appropriately _q->nstd = powf(10.0f, _noise_floor/20.0f); _q->gamma = powf(10.0f, (_q->snr+_q->noise_floor)/20.0f); return LIQUID_OK; } // apply carrier offset impairment // _q : channel object // _frequency : carrier frequency offse [radians/sample // _phase : carrier phase offset [radians] int CHANNEL(_add_carrier_offset)(CHANNEL() _q, float _frequency, float _phase) { // enable module _q->enabled_carrier = 1; // carrier frequency/phase offsets _q->dphi = _frequency; _q->phi = _phase; // set values appropriately NCO(_set_frequency)(_q->nco, _q->dphi); NCO(_set_phase) (_q->nco, _q->phi); return LIQUID_OK; } // apply multi-path channel impairment // _q : channel object // _h : channel coefficients (NULL for random) // _h_len : number of channel coefficients int CHANNEL(_add_multipath)(CHANNEL() _q, TC * _h, unsigned int _h_len) { if (_h_len == 0) return liquid_error(LIQUID_EIMODE,"channel_%s_add_multipath(), filter length is zero (ignoring)", EXTENSION_FULL); if (_h_len > 1000) return liquid_error(LIQUID_EIMODE,"channel_%s_add_multipath(), filter length exceeds maximum", EXTENSION_FULL); // enable module _q->enabled_multipath = 1; // set values appropriately // TODO: test for types other than float complex if (_q->h_len != _h_len) _q->h = (TC*) realloc(_q->h, _h_len*sizeof(TC)); // update length _q->h_len = _h_len; // copy coefficients internally if (_h == NULL) { // generate random coefficients using m-sequence generator // TODO: support types other than float _q->h[0] = 1.0f; unsigned int i; msequence ms = msequence_create_default(14); for (i=1; i<_q->h_len; i++) { float vi = msequence_generate_symbol(ms, 8) / 256.0f - 0.5f; float vq = msequence_generate_symbol(ms, 8) / 256.0f - 0.5f; _q->h[i] = (vi + _Complex_I*vq) * 0.5f; } msequence_destroy(ms); } else { // copy coefficients internally memmove(_q->h, _h, _q->h_len*sizeof(TC)); } // re-create channel filter _q->channel_filter = FIRFILT(_recreate)(_q->channel_filter, _q->h, _q->h_len); return LIQUID_OK; } // apply slowly-varying shadowing impairment // _q : channel object // _sigma : std. deviation for log-normal shadowing // _fd : Doppler frequency, _fd in (0,0.5) int CHANNEL(_add_shadowing)(CHANNEL() _q, float _sigma, float _fd) { if (_q->enabled_shadowing) return liquid_error(LIQUID_EIMODE,"channel_%s_add_shadowing(), shadowing already enabled", EXTENSION_FULL); if (_sigma <= 0) return liquid_error(LIQUID_EIMODE,"channel_%s_add_shadowing(), standard deviation less than or equal to zero", EXTENSION_FULL); if (_fd <= 0 || _fd >= 0.5) return liquid_error(LIQUID_EIMODE,"channel_%s_add_shadowing(), Doppler frequency must be in (0,0.5)", EXTENSION_FULL); // enable module _q->enabled_shadowing = 1; // TODO: set values appropriately _q->shadowing_std = _sigma; _q->shadowing_fd = _fd; // re-create channel filter // TODO: adjust gain //_q->shadowing_filter = IIRFILT(_create_lowpass)(11, _q->shadowing_fd); float alpha = _q->shadowing_fd; float a[2] = {1.0f, alpha-1.0f}; float b[2] = {alpha, 0}; _q->shadowing_filter = IIRFILT(_create)(b,2,a,2); return LIQUID_OK; } // apply channel impairments on single input sample // _q : channel object // _x : input sample // _y : output sample pointer int CHANNEL(_execute)(CHANNEL() _q, TI _x, TO * _y) { float complex r; // apply filter if (_q->enabled_multipath) { FIRFILT(_push)( _q->channel_filter, _x); FIRFILT(_execute)(_q->channel_filter, &r); } else { r = _x; } // apply shadowing if enabled if (_q->enabled_shadowing) { // TODO: use type-specific value other than float float g = 0; IIRFILT(_execute)(_q->shadowing_filter, randnf()*_q->shadowing_std, &g); g /= _q->shadowing_fd * 6.9f; g = powf(10.0f, g/20.0f); r *= g; } // apply carrier if enabled if (_q->enabled_carrier) { NCO(_mix_up)(_q->nco, r, &r); NCO(_step) (_q->nco); } // apply AWGN if enabled if (_q->enabled_awgn) { r *= _q->gamma; r += _q->nstd * ( randnf() + _Complex_I*randnf() ) * M_SQRT1_2; } // set output value *_y = r; return LIQUID_OK; } // apply channel impairments on single input sample // _q : channel object // _x : input array [size: _n x 1] // _n : input array length // _y : output array [size: _n x 1] int CHANNEL(_execute_block)(CHANNEL() _q, TI * _x, unsigned int _n, TO * _y) { // apply channel effects on each input sample // TODO: apply in blocks unsigned int i; for (i=0; i<_n; i++) CHANNEL(_execute)(_q, _x[i], &_y[i]); return LIQUID_OK; } liquid-dsp-1.7.0/src/channel/src/channel_cccf.c000066400000000000000000000041131474751757600213400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point channel // #include #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "cccf" #define CHANNEL(name) LIQUID_CONCAT(channel_cccf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define FIRFILT(name) LIQUID_CONCAT(firfilt_cccf,name) #define IIRFILT(name) LIQUID_CONCAT(iirfilt_rrrf,name) #define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define RESAMP(name) LIQUID_CONCAT(resamp_crcf,name) #define TVMPCH(name) LIQUID_CONCAT(tvmpch_cccf,name) #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define TO float complex // output type #define TC float complex // coefficients type #define TI float complex // input type #define T float // primitive type #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) // prototypes #include "channel.proto.c" #include "tvmpch.proto.c" liquid-dsp-1.7.0/src/channel/src/tvmpch.proto.c000066400000000000000000000154511474751757600214240ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // tvmpch : finite impulse response (FIR) filter // #include #include #include // tvmpch object structure struct TVMPCH(_s) { TC * h; // filter coefficients array [size; h_len x 1] unsigned int h_len; // filter length // use window object for internal buffer WINDOW() w; // float std; float alpha; float beta; }; // create time-varying multi-path channel emulator object // _n : number of coefficients, _n > 0 // _std : standard deviation // _tau : coherence time TVMPCH() TVMPCH(_create)(unsigned int _n, float _std, float _tau) { // validate input if (_n < 1) return liquid_error_config("tvmpch_%s_create(), filter length must be greater than one", EXTENSION_FULL); if (_std < 0.0f) return liquid_error_config("tvmpch_%s_create(), standard deviation must be positive", EXTENSION_FULL); if (_tau < 0.0f || _tau > 1.0f) return liquid_error_config("tvmpch_%s_create(), coherence time must be in [0,1]", EXTENSION_FULL); // create filter object and initialize TVMPCH() q = (TVMPCH()) malloc(sizeof(struct TVMPCH(_s))); q->h_len = _n; q->h = (TC *) malloc((q->h_len)*sizeof(TC)); q->beta = _tau; q->std = 2.0f * _std / sqrtf(q->beta); q->alpha = 1.0f - q->beta; // time-reverse coefficients unsigned int i; q->h[q->h_len-1] = 1.0f; for (i=0; ih_len-1; i++) q->h[i] = 0.0f; // create window (internal buffer) q->w = WINDOW(_create)(q->h_len); // reset filter state (clear buffer) TVMPCH(_reset)(q); // return q; } // copy object TVMPCH() TVMPCH(_copy)(TVMPCH() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("tvmpch_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters TVMPCH() q_copy = (TVMPCH()) malloc(sizeof(struct TVMPCH(_s))); memmove(q_copy, q_orig, sizeof(struct TVMPCH(_s))); // copy channel filter coefficients q_copy->h = (TC*) malloc(q_copy->h_len*sizeof(TC)); memmove(q_copy->h, q_orig->h, q_copy->h_len*sizeof(TC)); // copying window object q_copy->w = WINDOW(_copy)(q_orig->w); return q_copy; } // destroy tvmpch object int TVMPCH(_destroy)(TVMPCH() _q) { WINDOW(_destroy)(_q->w); free(_q->h); free(_q); return LIQUID_OK; } // reset internal state of filter object int TVMPCH(_reset)(TVMPCH() _q) { WINDOW(_reset)(_q->w); return LIQUID_OK; } // print filter object internals (taps, buffer) int TVMPCH(_print)(TVMPCH() _q) { printf("tvmpch_%s:\n", EXTENSION_FULL); unsigned int i; unsigned int n = _q->h_len; for (i=0; ih_len-1; i++) _q->h[i] = _q->alpha*_q->h[i] + _q->beta*(randnf() + _Complex_I*randnf()) * _q->std * M_SQRT1_2; // push sample into window buffer WINDOW(_push)(_q->w, _x); return LIQUID_OK; } // compute output sample (dot product between internal // filter coefficients and internal buffer) // _q : filter object // _y : output sample pointer int TVMPCH(_execute)(TVMPCH() _q, TO * _y) { // read buffer (retrieve pointer to aligned memory array) TI *r; WINDOW(_read)(_q->w, &r); // execute dot product DOTPROD(_run4)(r, _q->h, _q->h_len, _y); return LIQUID_OK; } // run on single sample int TVMPCH(_execute_one)(TVMPCH() _q, TI _x, TO * _y) { TVMPCH(_push)(_q, _x); return TVMPCH(_execute)(_q, _y); } // execute the filter on a block of input samples; the // input and output buffers may be the same // _q : filter object // _x : pointer to input array [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array [size: _n x 1] int TVMPCH(_execute_block)(TVMPCH() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // push sample into filter TVMPCH(_push)(_q, _x[i]); // compute output sample TVMPCH(_execute)(_q, &_y[i]); } return LIQUID_OK; } #if 0 // get filter length unsigned int TVMPCH(_get_length)(TVMPCH() _q) { return _q->h_len; } // compute complex frequency response // _q : filter object // _fc : frequency // _H : output frequency response int TVMPCH(_freqresponse)(TVMPCH() _q, float _fc, float complex * _H) { unsigned int i; float complex H = 0.0f; // compute dot product between coefficients and exp{ 2 pi fc {0..n-1} } for (i=0; i<_q->h_len; i++) H += _q->h[i] * cexpf(_Complex_I*2*M_PI*_fc*i); // apply scaling H *= _q->scale; // set return value *_H = H; return LIQUID_OK; } // compute group delay in samples // _q : filter object // _fc : frequency float TVMPCH(_groupdelay)(TVMPCH() _q, float _fc) { // copy coefficients to be in correct order float h[_q->h_len]; unsigned int i; unsigned int n = _q->h_len; for (i=0; ih[n-i-1]); return fir_group_delay(h, n, _fc); } #endif liquid-dsp-1.7.0/src/channel/tests/000077500000000000000000000000001474751757600171625ustar00rootroot00000000000000liquid-dsp-1.7.0/src/channel/tests/channel_copy_autotest.c000066400000000000000000000044661474751757600237320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // test filter copy operation #include "autotest/autotest.h" #include "liquid.h" // NOTE: this will never pass since the random sources are different; need to // implement random number generator first void xautotest_channel_copy() { // create default channel object and set properties channel_cccf q0 = channel_cccf_create(); channel_cccf_add_awgn (q0, -100, 20); channel_cccf_add_carrier_offset(q0, 1e-5f, 1.2f); channel_cccf_add_multipath (q0, NULL, 21); channel_cccf_add_shadowing (q0, 1.0f, 0.1f); channel_cccf_print(q0); // run samples through original object unsigned int i; float complex x, y0, y1; for (i=0; i<120; i++) { x = randnf() + _Complex_I*randnf(); channel_cccf_execute(q0, x, &y0); } // copy filter channel_cccf q1 = channel_cccf_copy(q0); // continue running through both objects for (i=0; i<120; i++) { // run objects in parallel x = randnf() + _Complex_I*randnf(); channel_cccf_execute(q0, x, &y0); channel_cccf_execute(q1, x, &y1); CONTEND_EQUALITY(y0, y1); } // destroy filter objects channel_cccf_destroy(q0); channel_cccf_destroy(q1); } liquid-dsp-1.7.0/src/channel/tests/tvmpch_copy_autotest.c000066400000000000000000000041321474751757600236110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // test filter copy operation #include "autotest/autotest.h" #include "liquid.h" // NOTE: this will never pass since the random sources are different; need to // implement random number generator first void xautotest_tvmpch_copy() { // create default channel object and set properties tvmpch_cccf q0 = tvmpch_cccf_create(31, 0.1f, 0.05f); // run samples through original object unsigned int i; float complex x, y0, y1; for (i=0; i<120; i++) { x = randnf() + _Complex_I*randnf(); tvmpch_cccf_execute_one(q0, x, &y0); } // copy filter tvmpch_cccf q1 = tvmpch_cccf_copy(q0); // continue running through both objects for (i=0; i<120; i++) { // run objects in parallel x = randnf() + _Complex_I*randnf(); tvmpch_cccf_execute_one(q0, x, &y0); tvmpch_cccf_execute_one(q1, x, &y1); CONTEND_EQUALITY(y0, y1); } // destroy filter objects tvmpch_cccf_destroy(q0); tvmpch_cccf_destroy(q1); } liquid-dsp-1.7.0/src/dotprod/000077500000000000000000000000001474751757600160635ustar00rootroot00000000000000liquid-dsp-1.7.0/src/dotprod/bench/000077500000000000000000000000001474751757600171425ustar00rootroot00000000000000liquid-dsp-1.7.0/src/dotprod/bench/dotprod_cccf_benchmark.c000066400000000000000000000055711474751757600237610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void dotprod_cccf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations = *_num_iterations * 20 / _n; if (*_num_iterations < 1) *_num_iterations = 1; float complex x[_n]; float complex h[_n]; float complex y[8]; unsigned int i; for (i=0; i<_n; i++) { x[i] = randnf() + _Complex_I*randnf(); h[i] = randnf() + _Complex_I*randnf(); } // create dotprod structure; dotprod_cccf dp = dotprod_cccf_create(h,_n); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { dotprod_cccf_execute(dp, x, &y[0]); dotprod_cccf_execute(dp, x, &y[1]); dotprod_cccf_execute(dp, x, &y[2]); dotprod_cccf_execute(dp, x, &y[3]); dotprod_cccf_execute(dp, x, &y[4]); dotprod_cccf_execute(dp, x, &y[5]); dotprod_cccf_execute(dp, x, &y[6]); dotprod_cccf_execute(dp, x, &y[7]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 8; // clean up objects dotprod_cccf_destroy(dp); } #define DOTPROD_CCCF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { dotprod_cccf_bench(_start, _finish, _num_iterations, N); } void benchmark_dotprod_cccf_4 DOTPROD_CCCF_BENCHMARK_API(4) void benchmark_dotprod_cccf_16 DOTPROD_CCCF_BENCHMARK_API(16) void benchmark_dotprod_cccf_64 DOTPROD_CCCF_BENCHMARK_API(64) void benchmark_dotprod_cccf_256 DOTPROD_CCCF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/dotprod/bench/dotprod_crcf_benchmark.c000066400000000000000000000055331474751757600237760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void dotprod_crcf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations = *_num_iterations * 20 / _n; if (*_num_iterations < 1) *_num_iterations = 1; float complex x[_n]; float h[_n]; float complex y[8]; unsigned int i; for (i=0; i<_n; i++) { x[i] = randnf() + _Complex_I*randnf(); h[i] = randnf(); } // create dotprod structure; dotprod_crcf dp = dotprod_crcf_create(h,_n); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { dotprod_crcf_execute(dp, x, &y[0]); dotprod_crcf_execute(dp, x, &y[1]); dotprod_crcf_execute(dp, x, &y[2]); dotprod_crcf_execute(dp, x, &y[3]); dotprod_crcf_execute(dp, x, &y[4]); dotprod_crcf_execute(dp, x, &y[5]); dotprod_crcf_execute(dp, x, &y[6]); dotprod_crcf_execute(dp, x, &y[7]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 8; // clean up objects dotprod_crcf_destroy(dp); } #define DOTPROD_CRCF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { dotprod_crcf_bench(_start, _finish, _num_iterations, N); } void benchmark_dotprod_crcf_4 DOTPROD_CRCF_BENCHMARK_API(4) void benchmark_dotprod_crcf_16 DOTPROD_CRCF_BENCHMARK_API(16) void benchmark_dotprod_crcf_64 DOTPROD_CRCF_BENCHMARK_API(64) void benchmark_dotprod_crcf_256 DOTPROD_CRCF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/dotprod/bench/dotprod_rrrf_benchmark.c000066400000000000000000000051261474751757600240320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void dotprod_rrrf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations = *_num_iterations * 20 / _n; if (*_num_iterations < 1) *_num_iterations = 1; float x[_n], h[_n], y; unsigned int i; for (i=0; i<_n; i++) { x[i] = 1.0f; h[i] = 1.0f; } // create dotprod structure; dotprod_rrrf dp = dotprod_rrrf_create(h,_n); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { dotprod_rrrf_execute(dp,x,&y); dotprod_rrrf_execute(dp,x,&y); dotprod_rrrf_execute(dp,x,&y); dotprod_rrrf_execute(dp,x,&y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // clean up objects dotprod_rrrf_destroy(dp); } #define DOTPROD_RRRF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { dotprod_rrrf_bench(_start, _finish, _num_iterations, N); } void benchmark_dotprod_rrrf_4 DOTPROD_RRRF_BENCHMARK_API(4) void benchmark_dotprod_rrrf_16 DOTPROD_RRRF_BENCHMARK_API(16) void benchmark_dotprod_rrrf_64 DOTPROD_RRRF_BENCHMARK_API(64) void benchmark_dotprod_rrrf_256 DOTPROD_RRRF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/dotprod/bench/sumsqcf_benchmark.c000066400000000000000000000047271474751757600230130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void sumsqcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations = *_num_iterations * 10 / _n; if (*_num_iterations < 1) *_num_iterations = 1; float complex x[_n]; float complex y = 0.0f; unsigned int long i; for (i=0; i<_n; i++) x[i] = 0.2f + 0.2f*_Complex_I; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { y += liquid_sumsqcf(x, _n); y -= liquid_sumsqcf(x, _n); y += liquid_sumsqcf(x, _n); y -= liquid_sumsqcf(x, _n); // change input x[i%_n] = y; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define SUMSQCF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { sumsqcf_bench(_start, _finish, _num_iterations, N); } void benchmark_sumsqcf_4 SUMSQCF_BENCHMARK_API(4) void benchmark_sumsqcf_16 SUMSQCF_BENCHMARK_API(16) void benchmark_sumsqcf_64 SUMSQCF_BENCHMARK_API(64) void benchmark_sumsqcf_256 SUMSQCF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/dotprod/bench/sumsqf_benchmark.c000066400000000000000000000046601474751757600226440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void sumsqf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations = *_num_iterations * 20 / _n; if (*_num_iterations < 1) *_num_iterations = 1; float x[_n]; float y = 0.0f; unsigned int long i; for (i=0; i<_n; i++) x[i] = 1.0f; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { y += liquid_sumsqf(x, _n); y -= liquid_sumsqf(x, _n); y += liquid_sumsqf(x, _n); y -= liquid_sumsqf(x, _n); // change input x[i%_n] = y; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define SUMSQF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { sumsqf_bench(_start, _finish, _num_iterations, N); } void benchmark_sumsqf_4 SUMSQF_BENCHMARK_API(4) void benchmark_sumsqf_16 SUMSQF_BENCHMARK_API(16) void benchmark_sumsqf_64 SUMSQF_BENCHMARK_API(64) void benchmark_sumsqf_256 SUMSQF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/dotprod/src/000077500000000000000000000000001474751757600166525ustar00rootroot00000000000000liquid-dsp-1.7.0/src/dotprod/src/dotprod.proto.c000066400000000000000000000147411474751757600216420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Generic dot product // #include #include #include // portable structured dot product object struct DOTPROD(_s) { TC * h; // coefficients array unsigned int n; // length }; // basic dot product // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int DOTPROD(_run)(TC * _h, TI * _x, unsigned int _n, TO * _y) { // initialize accumulator TO r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; // return result *_y = r; return LIQUID_OK; } // basic dotproduct, unrolling loop // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int DOTPROD(_run4)(TC * _h, TI * _x, unsigned int _n, TO * _y) { // initialize accumulator TO r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients q->h = (TC*) malloc((q->n)*sizeof(TC)); // move coefficients memmove(q->h, _h, (q->n)*sizeof(TC)); // return object return q; } // create vector dot product object with time-reversed coefficients // _h : coefficients array [size: 1 x _n] // _n : dot product length DOTPROD() DOTPROD(_create_rev)(TC * _h, unsigned int _n) { DOTPROD() q = (DOTPROD()) malloc(sizeof(struct DOTPROD(_s))); q->n = _n; // allocate memory for coefficients q->h = (TC*) malloc((q->n)*sizeof(TC)); // copy coefficients in time-reversed order unsigned int i; for (i=0; i<_n; i++) q->h[i] = _h[_n-i-1]; // return object return q; } // re-create dot product object // _q : old dot dot product object // _h : new coefficients [size: 1 x _n] // _n : new dot product size DOTPROD() DOTPROD(_recreate)(DOTPROD() _q, TC * _h, unsigned int _n) { // check to see if length has changed if (_q->n != _n) { // set new length _q->n = _n; // re-allocate memory _q->h = (TC*) realloc(_q->h, (_q->n)*sizeof(TC)); } // move new coefficients memmove(_q->h, _h, (_q->n)*sizeof(TC)); // return re-structured object return _q; } // re-create dot product object with coefficients in reverse order // _q : old dot dot product object // _h : time-reversed new coefficients [size: 1 x _n] // _n : new dot product size DOTPROD() DOTPROD(_recreate_rev)(DOTPROD() _q, TC * _h, unsigned int _n) { // check to see if length has changed if (_q->n != _n) { // set new length _q->n = _n; // re-allocate memory _q->h = (TC*) realloc(_q->h, (_q->n)*sizeof(TC)); } // copy coefficients in time-reversed order unsigned int i; for (i=0; i<_n; i++) _q->h[i] = _h[_n-i-1]; // return re-structured object return _q; } // copy object DOTPROD() DOTPROD(_copy)(DOTPROD() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_%s_copy(), window object cannot be NULL", "xxxt"); // create new base object and copy parameters DOTPROD() q_copy = (DOTPROD()) malloc(sizeof(struct DOTPROD(_s))); q_copy->n = q_orig->n; // allocate memory and copy coefficients q_copy->h = (TC*) malloc((q_copy->n)*sizeof(TC)); memmove(q_copy->h, q_orig->h, (q_copy->n)*sizeof(TC)); // return new object return q_copy; } // destroy dot product object int DOTPROD(_destroy)(DOTPROD() _q) { free(_q->h); // free coefficients memory free(_q); // free main object memory return LIQUID_OK; } // print dot product object int DOTPROD(_print)(DOTPROD() _q) { printf("dotprod [portable, %u coefficients]:\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) { #if TC_COMPLEX==0 printf(" %4u: %12.8f\n", i, _q->h[i]); #else printf(" %4u: %12.8f + j*%12.8f\n", i, crealf(_q->h[i]), cimagf(_q->h[i])); #endif } return LIQUID_OK; } // execute structured dot product // _q : dot product object // _x : input array [size: 1 x _n] // _y : output dot product int DOTPROD(_execute)(DOTPROD() _q, TI * _x, TO * _y) { // run basic dot product with unrolled loops DOTPROD(_run4)(_q->h, _x, _q->n, _y); return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_cccf.avx.c000066400000000000000000000304231474751757600222460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2025 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX) // #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CCCF_AVX 0 // forward declaration of internal methods int dotprod_cccf_execute_avx(dotprod_cccf _q, float complex * _x, float complex * _y); int dotprod_cccf_execute_avx4(dotprod_cccf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_cccf_run(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_cccf_run4(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 32-byte aligned q->hi = (float*) _mm_malloc( 2*q->n*sizeof(float), 32 ); q->hq = (float*) _mm_malloc( 2*q->n*sizeof(float), 32 ); // set coefficients, repeated // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->hi[2*i+0] = crealf(_h[k]); q->hi[2*i+1] = crealf(_h[k]); q->hq[2*i+0] = cimagf(_h[k]); q->hq[2*i+1] = cimagf(_h[k]); } // return object return q; } dotprod_cccf dotprod_cccf_create(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 0); } dotprod_cccf dotprod_cccf_create_rev(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create_rev(_h,_n); } dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_cccf_copy().avx, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 32-byte aligned (repeated) q_copy->hi = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 32 ); q_copy->hq = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 32 ); // copy coefficients array (repeated) // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_cccf_destroy(dotprod_cccf _q) { _mm_free(_q->hi); _mm_free(_q->hq); free(_q); return LIQUID_OK; } int dotprod_cccf_print(dotprod_cccf _q) { printf("dotprod_cccf [avx, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); return LIQUID_OK; } // execute structured dot product // _q : dotprod object // _x : input array // _y : output sample int dotprod_cccf_execute(dotprod_cccf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 64) { return dotprod_cccf_execute_avx(_q, _x, _y); } return dotprod_cccf_execute_avx4(_q, _x, _y); } // use AVX extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // // mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag, x[2].real, x[2].imag, x[3].real, x[3].imag } // mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real, h[2].real, h[2].real, h[3].real, h[3].real } // mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag, h[2].imag, h[2].imag, h[3].imag, h[3].imag } // // mm_y0 = mm_x * mm_hi // = { x[0].real * h[0].real, // x[0].imag * h[0].real, // x[1].real * h[1].real, // x[1].imag * h[1].real, // x[2].real * h[2].real, // x[2].imag * h[2].real, // x[3].real * h[3].real, // x[3].imag * h[3].real }; // // mm_y1 = mm_x * mm_hq // = { x[0].real * h[0].imag, // x[0].imag * h[0].imag, // x[1].real * h[1].imag, // x[1].imag * h[1].imag, // x[2].real * h[2].imag, // x[2].imag * h[2].imag, // x[3].real * h[3].imag, // x[3].imag * h[3].imag }; // int dotprod_cccf_execute_avx(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // temporary buffers __m256 v; // input vector __m256 hi; // coefficients vector (real) __m256 hq; // coefficients vector (imag) __m256 ci; // output multiplication (v * hi) __m256 cq; // output multiplication (v * hq) // aligned output array float w[8] __attribute__((aligned(32))) = {0,0,0,0,0,0,0,0}; __m256 s; // dot product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) unsigned int t = (n >> 3) << 3; // unsigned int i; for (i=0; ihi[i]); hq = _mm256_load_ps(&_q->hq[i]); // compute parallel multiplications ci = _mm256_mul_ps(v, hi); cq = _mm256_mul_ps(v, hq); // shuffle values cq = _mm256_shuffle_ps( cq, cq, _MM_SHUFFLE(2,3,0,1) ); // combine using addsub_ps() s = _mm256_addsub_ps( ci, cq ); // accumulate sum = _mm256_add_ps(sum, s); } // unload packed array _mm256_store_ps(w, sum); // add in-phase and quadrature components w[0] += w[2] + w[4] + w[6]; // I w[1] += w[3] + w[5] + w[7]; // Q //float complex total = *((float complex*)w); float complex total = w[0] + w[1] * _Complex_I; // cleanup for (i=t/2; i<_q->n; i++) total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); // set return value *_y = total; return LIQUID_OK; } // use AVX extensions int dotprod_cccf_execute_avx4(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m256 v0, v1, v2, v3; // input vectors __m256 hi0, hi1, hi2, hi3; // coefficients vectors (real) __m256 hq0, hq1, hq2, hq3; // coefficients vectors (imag) __m256 ci0, ci1, ci2, ci3; // output multiplications (v * hi) __m256 cq0, cq1, cq2, cq3; // output multiplications (v * hq) // load zeros into sum registers __m256 sumi = _mm256_setzero_ps(); __m256 sumq = _mm256_setzero_ps(); // r = 8*floor(n/32) unsigned int r = (n >> 5) << 3; // unsigned int i; for (i=0; ihi[4*i+0]); hi1 = _mm256_load_ps(&_q->hi[4*i+8]); hi2 = _mm256_load_ps(&_q->hi[4*i+16]); hi3 = _mm256_load_ps(&_q->hi[4*i+24]); // load real coefficients into registers (aligned) hq0 = _mm256_load_ps(&_q->hq[4*i+0]); hq1 = _mm256_load_ps(&_q->hq[4*i+8]); hq2 = _mm256_load_ps(&_q->hq[4*i+16]); hq3 = _mm256_load_ps(&_q->hq[4*i+24]); // compute parallel multiplications (real) ci0 = _mm256_mul_ps(v0, hi0); ci1 = _mm256_mul_ps(v1, hi1); ci2 = _mm256_mul_ps(v2, hi2); ci3 = _mm256_mul_ps(v3, hi3); // compute parallel multiplications (imag) cq0 = _mm256_mul_ps(v0, hq0); cq1 = _mm256_mul_ps(v1, hq1); cq2 = _mm256_mul_ps(v2, hq2); cq3 = _mm256_mul_ps(v3, hq3); // accumulate sumi = _mm256_add_ps(sumi, ci0); sumq = _mm256_add_ps(sumq, cq0); sumi = _mm256_add_ps(sumi, ci1); sumq = _mm256_add_ps(sumq, cq1); sumi = _mm256_add_ps(sumi, ci2); sumq = _mm256_add_ps(sumq, cq2); sumi = _mm256_add_ps(sumi, ci3); sumq = _mm256_add_ps(sumq, cq3); } // shuffle values sumq = _mm256_shuffle_ps( sumq, sumq, _MM_SHUFFLE(2,3,0,1) ); // unload float wi[8] __attribute__((aligned(32))); float wq[8] __attribute__((aligned(32))); _mm256_store_ps(wi, sumi); _mm256_store_ps(wq, sumq); // fold down (add/sub) float complex total = ((wi[0] - wq[0]) + (wi[2] - wq[2]) + (wi[4] - wq[4]) + (wi[6] - wq[6])) + ((wi[1] + wq[1]) + (wi[3] + wq[3]) + (wi[5] + wq[5]) + (wi[7] + wq[7])) * _Complex_I; // cleanup (note: n _must_ be even) // TODO : clean this method up for (i=2*r; i<_q->n; i++) { total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); } // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_cccf.avx512f.c000066400000000000000000000305761474751757600226550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX512-F) // #include #include #include #include "liquid.internal.h" // include proper SIMD extensions for x86 platforms #include // AVX #define DEBUG_DOTPROD_CCCF_AVX 0 // forward declaration of internal methods int dotprod_cccf_execute_avx512f(dotprod_cccf _q, float complex * _x, float complex * _y); int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_cccf_run(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_cccf_run4(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 64-byte aligned q->hi = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); q->hq = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); // set coefficients, repeated // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->hi[2*i+0] = crealf(_h[k]); q->hi[2*i+1] = crealf(_h[k]); q->hq[2*i+0] = cimagf(_h[k]); q->hq[2*i+1] = cimagf(_h[k]); } // return object return q; } dotprod_cccf dotprod_cccf_create(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 0); } dotprod_cccf dotprod_cccf_create_rev(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create_rev(_h,_n); } dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_cccf_copy().avx512f, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 64-byte aligned (repeated) q_copy->hi = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); q_copy->hq = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); // copy coefficients array (repeated) // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_cccf_destroy(dotprod_cccf _q) { _mm_free(_q->hi); _mm_free(_q->hq); free(_q); return LIQUID_OK; } int dotprod_cccf_print(dotprod_cccf _q) { printf("dotprod_cccf [avx512f, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); return LIQUID_OK; } // execute structured dot product // _q : dotprod object // _x : input array // _y : output sample int dotprod_cccf_execute(dotprod_cccf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 128) { return dotprod_cccf_execute_avx512f(_q, _x, _y); } return dotprod_cccf_execute_avx512f4(_q, _x, _y); } // use AVX512-F extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // // mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag, x[2].real, x[2].imag, x[3].real, x[3].imag } // mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real, h[2].real, h[2].real, h[3].real, h[3].real } // mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag, h[2].imag, h[2].imag, h[3].imag, h[3].imag } // // mm_y0 = mm_x * mm_hi // = { x[0].real * h[0].real, // x[0].imag * h[0].real, // x[1].real * h[1].real, // x[1].imag * h[1].real, // x[2].real * h[2].real, // x[2].imag * h[2].real, // x[3].real * h[3].real, // x[3].imag * h[3].real }; // // mm_y1 = mm_x * mm_hq // = { x[0].real * h[0].imag, // x[0].imag * h[0].imag, // x[1].real * h[1].imag, // x[1].imag * h[1].imag, // x[2].real * h[2].imag, // x[2].imag * h[2].imag, // x[3].real * h[3].imag, // x[3].imag * h[3].imag }; // int dotprod_cccf_execute_avx512f(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // temporary buffers __m512 v; // input vector __m512 hi; // coefficients vector (real) __m512 hq; // coefficients vector (imag) __m512 ci; // output multiplication (v * hi) __m512 cq; // output multiplication (v * hq) __m512 s; // dot product __m512 sum = _mm512_setzero_ps(); // load zeros into sum register __m512 one = _mm512_set1_ps(1.0f); // load ones into register // t = 16*(floor(_n/16)) unsigned int t = (n >> 4) << 4; // unsigned int i; for (i=0; ihi[i]); hq = _mm512_load_ps(&_q->hq[i]); // compute parallel multiplications ci = _mm512_mul_ps(v, hi); cq = _mm512_mul_ps(v, hq); // shuffle values cq = _mm512_shuffle_ps( cq, cq, _MM_SHUFFLE(2,3,0,1) ); // combine using addsub_ps() s = _mm512_fmaddsub_ps( ci, one, cq ); // accumulate sum = _mm512_add_ps(sum, s); } // output array float w[2]; // fold down I/Q components into single value w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); //float complex total = *((float complex*)w); float complex total = w[0] + w[1] * _Complex_I; // cleanup for (i=t/2; i<_q->n; i++) total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); // set return value *_y = total; return LIQUID_OK; } // use AVX512-F extensions int dotprod_cccf_execute_avx512f4(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m512 v0, v1, v2, v3; // input vectors __m512 hi0, hi1, hi2, hi3; // coefficients vectors (real) __m512 hq0, hq1, hq2, hq3; // coefficients vectors (imag) __m512 ci0, ci1, ci2, ci3; // output multiplications (v * hi) __m512 cq0, cq1, cq2, cq3; // output multiplications (v * hq) // load zeros into sum registers __m512 sumi = _mm512_setzero_ps(); __m512 sumq = _mm512_setzero_ps(); __m512 one = _mm512_set1_ps(1.0f); // load ones into register // r = 16*floor(n/64) unsigned int r = (n >> 6) << 4; // unsigned int i; for (i=0; ihi[4*i+0]); hi1 = _mm512_load_ps(&_q->hi[4*i+16]); hi2 = _mm512_load_ps(&_q->hi[4*i+32]); hi3 = _mm512_load_ps(&_q->hi[4*i+48]); // load real coefficients into registers (aligned) hq0 = _mm512_load_ps(&_q->hq[4*i+0]); hq1 = _mm512_load_ps(&_q->hq[4*i+16]); hq2 = _mm512_load_ps(&_q->hq[4*i+32]); hq3 = _mm512_load_ps(&_q->hq[4*i+48]); // compute parallel multiplications (real) ci0 = _mm512_mul_ps(v0, hi0); ci1 = _mm512_mul_ps(v1, hi1); ci2 = _mm512_mul_ps(v2, hi2); ci3 = _mm512_mul_ps(v3, hi3); // compute parallel multiplications (imag) cq0 = _mm512_mul_ps(v0, hq0); cq1 = _mm512_mul_ps(v1, hq1); cq2 = _mm512_mul_ps(v2, hq2); cq3 = _mm512_mul_ps(v3, hq3); // accumulate sumi = _mm512_add_ps(sumi, ci0); sumq = _mm512_add_ps(sumq, cq0); sumi = _mm512_add_ps(sumi, ci1); sumq = _mm512_add_ps(sumq, cq1); sumi = _mm512_add_ps(sumi, ci2); sumq = _mm512_add_ps(sumq, cq2); sumi = _mm512_add_ps(sumi, ci3); sumq = _mm512_add_ps(sumq, cq3); } // shuffle values sumq = _mm512_shuffle_ps( sumq, sumq, _MM_SHUFFLE(2,3,0,1) ); // combine using addsub_ps() sumi = _mm512_fmaddsub_ps( sumi, one, sumq ); // output array float w[2]; // fold down I/Q components into single value w[0] = _mm512_mask_reduce_add_ps(0x5555, sumi); w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sumi); float complex total = w[0] + w[1] * _Complex_I; // cleanup (note: n _must_ be even) // TODO : clean this method up for (i=2*r; i<_q->n; i++) { total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); } // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_cccf.c000066400000000000000000000027371474751757600214600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point dot product // #include #include "liquid.internal.h" #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define TO float complex #define TC float complex #define TI float complex #define TO_COMPLEX 1 #define TC_COMPLEX 1 #define TI_COMPLEX 1 #include "dotprod.proto.c" liquid-dsp-1.7.0/src/dotprod/src/dotprod_cccf.neon.c000066400000000000000000000271531474751757600224150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (ARM Neon) // #include #include #include #include "liquid.internal.h" // include proper SIMD extensions for ARM Neon #include #define DEBUG_DOTPROD_CCCF_NEON 0 // forward declaration of internal methods int dotprod_cccf_execute_neon(dotprod_cccf _q, float complex * _x, float complex * _y); int dotprod_cccf_execute_neon4(dotprod_cccf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_cccf_run(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_cccf_run4(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients q->hi = (float*) malloc( 2*q->n*sizeof(float) ); q->hq = (float*) malloc( 2*q->n*sizeof(float) ); // set coefficients, repeated // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->hi[2*i+0] = crealf(_h[k]); q->hi[2*i+1] = crealf(_h[k]); q->hq[2*i+0] = cimagf(_h[k]); q->hq[2*i+1] = cimagf(_h[k]); } // return object return q; } dotprod_cccf dotprod_cccf_create(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h,_n,0); } dotprod_cccf dotprod_cccf_create_rev(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h,_n,1); } // re-create the structured dotprod object dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create(_h,_n); } // re-create the structured dotprod object, reversing coefficients dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create_rev(_h,_n); } dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_cccf_copy().neon, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients (repeated) q_copy->hi = (float*) malloc( 2*q_copy->n*sizeof(float) ); q_copy->hq = (float*) malloc( 2*q_copy->n*sizeof(float) ); // copy coefficients array (repeated) // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_cccf_destroy(dotprod_cccf _q) { // free coefficients arrays free(_q->hi); free(_q->hq); // free main memory free(_q); return LIQUID_OK; } int dotprod_cccf_print(dotprod_cccf _q) { printf("dotprod_cccf [arm-neon, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); return LIQUID_OK; } // execute structured dot product // _q : dotprod object // _x : input array // _y : output sample int dotprod_cccf_execute(dotprod_cccf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 32) { return dotprod_cccf_execute_neon(_q, _x, _y); } return dotprod_cccf_execute_neon4(_q, _x, _y); } // use ARM Neon extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // // mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag } // mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real } // mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag } // // mm_y0 = mm_x * mm_hi // = { x[0].real * h[0].real, // x[0].imag * h[0].real, // x[1].real * h[1].real, // x[1].imag * h[1].real }; // // mm_y1 = mm_x * mm_hq // = { x[0].real * h[0].imag, // x[0].imag * h[0].imag, // x[1].real * h[1].imag, // x[1].imag * h[1].imag }; // int dotprod_cccf_execute_neon(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // temporary buffers float32x4_t v; // input vector float32x4_t hi; // coefficients vector (real) float32x4_t hq; // coefficients vector (imag) float32x4_t ci; // output multiplication (v * hi) float32x4_t cq; // output multiplication (v * hq) // output accumulators float zeros[4] = {0,0,0,0}; float32x4_t sumi = vld1q_f32(zeros); float32x4_t sumq = vld1q_f32(zeros); // t = 4*(floor(_n/4)) unsigned int t = (n >> 2) << 2; // unsigned int i; for (i=0; ihi[i]); hq = vld1q_f32(&_q->hq[i]); // compute parallel multiplications ci = vmulq_f32(v, hi); cq = vmulq_f32(v, hq); // parallel addition sumi = vaddq_f32(sumi, ci); sumq = vaddq_f32(sumq, cq); } // unload and combine float wi[4]; float wq[4]; vst1q_f32(wi, sumi); vst1q_f32(wq, sumq); // fold down (add/sub) float complex total = ((wi[0] - wq[1]) + (wi[2] - wq[3])) + ((wi[1] + wq[0]) + (wi[3] + wq[2])) * _Complex_I; // cleanup for (i=t/2; i<_q->n; i++) total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); // set return value *_y = total; return LIQUID_OK; } // use ARM Neon extensions (unrolled loop) // NOTE: unrolling doesn't show any appreciable performance difference int dotprod_cccf_execute_neon4(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... float32x4_t v0, v1, v2, v3; // input vectors float32x4_t hi0, hi1, hi2, hi3; // coefficients vectors (real) float32x4_t hq0, hq1, hq2, hq3; // coefficients vectors (imag) float32x4_t ci0, ci1, ci2, ci3; // output multiplications (v * hi) float32x4_t cq0, cq1, cq2, cq3; // output multiplications (v * hq) // load zeros into sum registers float zeros[4] = {0,0,0,0}; float32x4_t sumi = vld1q_f32(zeros); float32x4_t sumq = vld1q_f32(zeros); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; // unsigned int i; for (i=0; ihi[4*i+0]); hi1 = vld1q_f32(&_q->hi[4*i+4]); hi2 = vld1q_f32(&_q->hi[4*i+8]); hi3 = vld1q_f32(&_q->hi[4*i+12]); // load real coefficients into registers (aligned) hq0 = vld1q_f32(&_q->hq[4*i+0]); hq1 = vld1q_f32(&_q->hq[4*i+4]); hq2 = vld1q_f32(&_q->hq[4*i+8]); hq3 = vld1q_f32(&_q->hq[4*i+12]); // compute parallel multiplications (real) ci0 = vmulq_f32(v0, hi0); ci1 = vmulq_f32(v1, hi1); ci2 = vmulq_f32(v2, hi2); ci3 = vmulq_f32(v3, hi3); // compute parallel multiplications (imag) cq0 = vmulq_f32(v0, hq0); cq1 = vmulq_f32(v1, hq1); cq2 = vmulq_f32(v2, hq2); cq3 = vmulq_f32(v3, hq3); // accumulate sumi = vaddq_f32(sumi, ci0); sumq = vaddq_f32(sumq, cq0); sumi = vaddq_f32(sumi, ci1); sumq = vaddq_f32(sumq, cq1); sumi = vaddq_f32(sumi, ci2); sumq = vaddq_f32(sumq, cq2); sumi = vaddq_f32(sumi, ci3); sumq = vaddq_f32(sumq, cq3); } // unload float wi[4]; float wq[4]; vst1q_f32(wi, sumi); vst1q_f32(wq, sumq); // fold down (add/sub) float complex total = ((wi[0] - wq[1]) + (wi[2] - wq[3])) + ((wi[1] + wq[0]) + (wi[3] + wq[2])) * _Complex_I; // cleanup (note: n _must_ be even) // TODO : clean this method up for (i=2*r; i<_q->n; i++) { total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); } // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_cccf.sse.c000066400000000000000000000301421474751757600222400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (SSE) // #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CCCF_sse 0 // forward declaration of internal methods int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y); int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_cccf_run(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_cccf_run4(float complex * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 16-byte aligned q->hi = (float*) _mm_malloc( 2*q->n*sizeof(float), 16 ); q->hq = (float*) _mm_malloc( 2*q->n*sizeof(float), 16 ); // set coefficients, repeated // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->hi[2*i+0] = crealf(_h[k]); q->hi[2*i+1] = crealf(_h[k]); q->hq[2*i+0] = cimagf(_h[k]); q->hq[2*i+1] = cimagf(_h[k]); } // return object return q; } dotprod_cccf dotprod_cccf_create(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 0); } dotprod_cccf dotprod_cccf_create_rev(float complex * _h, unsigned int _n) { return dotprod_cccf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_cccf dotprod_cccf_recreate(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_cccf dotprod_cccf_recreate_rev(dotprod_cccf _q, float complex * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_cccf_destroy(_q); return dotprod_cccf_create_rev(_h,_n); } dotprod_cccf dotprod_cccf_copy(dotprod_cccf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_cccf_copy().sse, object cannot be NULL"); dotprod_cccf q_copy = (dotprod_cccf)malloc(sizeof(struct dotprod_cccf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 16-byte aligned (repeated) q_copy->hi = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 16 ); q_copy->hq = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 16 ); // copy coefficients array (repeated) // hi = { crealf(_h[0]), crealf(_h[0]), ... crealf(_h[n-1]), crealf(_h[n-1])} // hq = { cimagf(_h[0]), cimagf(_h[0]), ... cimagf(_h[n-1]), cimagf(_h[n-1])} memmove(q_copy->hi, q_orig->hi, 2*q_orig->n*sizeof(float)); memmove(q_copy->hq, q_orig->hq, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_cccf_destroy(dotprod_cccf _q) { _mm_free(_q->hi); _mm_free(_q->hq); free(_q); return LIQUID_OK; } int dotprod_cccf_print(dotprod_cccf _q) { printf("dotprod_cccf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f +j%12.9f\n", i, _q->hi[i], _q->hq[i]); return LIQUID_OK; } // execute structured dot product // _q : dotprod object // _x : input array // _y : output sample int dotprod_cccf_execute(dotprod_cccf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 32) { return dotprod_cccf_execute_sse(_q, _x, _y); } return dotprod_cccf_execute_sse4(_q, _x, _y); } // use SSE extensions // // (a + jb)(c + jd) = (ac - bd) + j(ad + bc) // // mm_x = { x[0].real, x[0].imag, x[1].real, x[1].imag } // mm_hi = { h[0].real, h[0].real, h[1].real, h[1].real } // mm_hq = { h[0].imag, h[0].imag, h[1].imag, h[1].imag } // // mm_y0 = mm_x * mm_hi // = { x[0].real * h[0].real, // x[0].imag * h[0].real, // x[1].real * h[1].real, // x[1].imag * h[1].real }; // // mm_y1 = mm_x * mm_hq // = { x[0].real * h[0].imag, // x[0].imag * h[0].imag, // x[1].real * h[1].imag, // x[1].imag * h[1].imag }; // int dotprod_cccf_execute_sse(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // temporary buffers __m128 v; // input vector __m128 hi; // coefficients vector (real) __m128 hq; // coefficients vector (imag) __m128 ci; // output multiplication (v * hi) __m128 cq; // output multiplication (v * hq) // aligned output array float w[4] __attribute__((aligned(16))) = {0,0,0,0}; #if HAVE_SSE3 // SSE3 __m128 s; // dot product __m128 sum = _mm_setzero_ps(); // load zeros into sum register #else // no SSE3 float wi[4] __attribute__((aligned(16))); float wq[4] __attribute__((aligned(16))); #endif // t = 4*(floor(_n/4)) unsigned int t = (n >> 2) << 2; // unsigned int i; for (i=0; ihi[i]); hq = _mm_load_ps(&_q->hq[i]); // compute parallel multiplications ci = _mm_mul_ps(v, hi); cq = _mm_mul_ps(v, hq); // shuffle values cq = _mm_shuffle_ps( cq, cq, _MM_SHUFFLE(2,3,0,1) ); #if HAVE_SSE3 // SSE3: combine using addsub_ps() s = _mm_addsub_ps( ci, cq ); // accumulate sum = _mm_add_ps(sum, s); #else // no SSE3: combine using slow method // FIXME: implement slow method // unload values _mm_store_ps(wi, ci); _mm_store_ps(wq, cq); // accumulate w[0] += wi[0] - wq[0]; w[1] += wi[1] + wq[1]; w[2] += wi[2] - wq[2]; w[3] += wi[3] + wq[3]; #endif } #if HAVE_SSE3 // unload packed array _mm_store_ps(w, sum); #endif // add in-phase and quadrature components w[0] += w[2]; // I w[1] += w[3]; // Q //float complex total = *((float complex*)w); float complex total = w[0] + w[1] * _Complex_I; // cleanup for (i=t/2; i<_q->n; i++) total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); // set return value *_y = total; return LIQUID_OK; } // use SSE extensions int dotprod_cccf_execute_sse4(dotprod_cccf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m128 v0, v1, v2, v3; // input vectors __m128 hi0, hi1, hi2, hi3; // coefficients vectors (real) __m128 hq0, hq1, hq2, hq3; // coefficients vectors (imag) __m128 ci0, ci1, ci2, ci3; // output multiplications (v * hi) __m128 cq0, cq1, cq2, cq3; // output multiplications (v * hq) // load zeros into sum registers __m128 sumi = _mm_setzero_ps(); __m128 sumq = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; // unsigned int i; for (i=0; ihi[4*i+0]); hi1 = _mm_load_ps(&_q->hi[4*i+4]); hi2 = _mm_load_ps(&_q->hi[4*i+8]); hi3 = _mm_load_ps(&_q->hi[4*i+12]); // load real coefficients into registers (aligned) hq0 = _mm_load_ps(&_q->hq[4*i+0]); hq1 = _mm_load_ps(&_q->hq[4*i+4]); hq2 = _mm_load_ps(&_q->hq[4*i+8]); hq3 = _mm_load_ps(&_q->hq[4*i+12]); // compute parallel multiplications (real) ci0 = _mm_mul_ps(v0, hi0); ci1 = _mm_mul_ps(v1, hi1); ci2 = _mm_mul_ps(v2, hi2); ci3 = _mm_mul_ps(v3, hi3); // compute parallel multiplications (imag) cq0 = _mm_mul_ps(v0, hq0); cq1 = _mm_mul_ps(v1, hq1); cq2 = _mm_mul_ps(v2, hq2); cq3 = _mm_mul_ps(v3, hq3); // accumulate sumi = _mm_add_ps(sumi, ci0); sumq = _mm_add_ps(sumq, cq0); sumi = _mm_add_ps(sumi, ci1); sumq = _mm_add_ps(sumq, cq1); sumi = _mm_add_ps(sumi, ci2); sumq = _mm_add_ps(sumq, cq2); sumi = _mm_add_ps(sumi, ci3); sumq = _mm_add_ps(sumq, cq3); } // shuffle values sumq = _mm_shuffle_ps( sumq, sumq, _MM_SHUFFLE(2,3,0,1) ); // unload float wi[4] __attribute__((aligned(16))); float wq[4] __attribute__((aligned(16))); _mm_store_ps(wi, sumi); _mm_store_ps(wq, sumq); // fold down (add/sub) float complex total = ((wi[0] - wq[0]) + (wi[2] - wq[2])) + ((wi[1] + wq[1]) + (wi[3] + wq[3])) * _Complex_I; // cleanup (note: n _must_ be even) // TODO : clean this method up for (i=2*r; i<_q->n; i++) { total += _x[i] * ( _q->hi[2*i] + _q->hq[2*i]*_Complex_I ); } // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.av.c000066400000000000000000000160621474751757600221000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point dot product (altivec velocity engine) // #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CRCF_AV 0 // basic dot product // basic dot product // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int dotprod_crcf_run(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product, unrolling loop // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int dotprod_crcf_run4(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // create 4 copies of the input coefficients (one for each // data alignment). For example: _h[4] = {1,2,3,4,5,6} // q->h[0] = {1,1,2,2,3,3,4,4,5,5,6,6} // q->h[1] = {. 1,1,2,2,3,3,4,4,5,5,6,6} // q->h[2] = {. . 1,1,2,2,3,3,4,4,5,5,6,6} // q->h[3] = {. . . 1,1,2,2,3,3,4,4,5,5,6,6} // NOTE: double allocation size; coefficients are real, but // need to be multiplied by real and complex components // of input. unsigned int i,j; for (i=0; i<4; i++) { q->h[i] = calloc(1+(2*q->n+i-1)/4,2*sizeof(vector float)); for (j=0; jn; j++) { q->h[i][2*j+0+i] = _h[_rev ? q->n-j-1 : j]; q->h[i][2*j+1+i] = _h[_rev ? q->n-j-1 : j]; } } return q; } dotprod_crcf dotprod_crcf_create(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h,_n,0); } dotprod_crcf dotprod_crcf_create_rev(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h,_n,1); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create(_h,_n); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create_rev(_h,_n); } // destroy the structured dotprod object int dotprod_crcf_destroy(dotprod_crcf _q) { // clean up coefficients arrays unsigned int i; for (i=0; i<4; i++) free(_q->h[i]); // free allocated object memory free(_q); return LIQUID_OK; } // print the dotprod object int dotprod_crcf_print(dotprod_crcf _q) { printf("dotprod_crcf [altivec, %u coefficients]:\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[0][2*i]); return LIQUID_OK; } // exectue vectorized structured inner dot product int dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _r) { int al; // input data alignment vector float *ar,*d; vector float s0,s1,s2,s3; union { vector float v; float w[4];} s; unsigned int nblocks; ar = (vector float*)( (int)_x & ~15); al = ((int)_x & 15)/sizeof(float); d = (vector float*)_q->h[al]; // number of blocks doubles because of complex type nblocks = (2*_q->n + al - 1)/4 + 1; // split into four vectors each with four 32-bit // partial sums. Effectively each loop iteration // operates on 16 input samples at a time. s0 = s1 = s2 = s3 = (vector float)(0); while (nblocks >= 4) { s0 = vec_madd(ar[nblocks-1],d[nblocks-1],s0); s1 = vec_madd(ar[nblocks-2],d[nblocks-2],s1); s2 = vec_madd(ar[nblocks-3],d[nblocks-3],s2); s3 = vec_madd(ar[nblocks-4],d[nblocks-4],s3); nblocks -= 4; } // fold the resulting partial sums into vector s0 s0 = vec_add(s0,s1); // s0 = s0+s1 s2 = vec_add(s2,s3); // s2 = s2+s3 s0 = vec_add(s0,s2); // s0 = s0+s2 // finish partial summing operations while (nblocks-- > 0) s0 = vec_madd(ar[nblocks],d[nblocks],s0); // move the result into the union s (effetively, // this loads the four 32-bit values in s0 into // the array w). s.v = vec_add(s0,(vector float)(0)); // sum the resulting array //*_r = s.w[0] + s.w[1] + s.w[2] + s.w[3]; *_r = (s.w[0] + s.w[2]) + (s.w[1] + s.w[3]) * _Complex_I; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.avx.c000066400000000000000000000220451474751757600222660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2025 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX) // #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CRCF_AVX 0 // forward declaration of internal methods int dotprod_crcf_execute_avx(dotprod_crcf _q, float complex * _x, float complex * _y); int dotprod_crcf_execute_avx4(dotprod_crcf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_crcf_run(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_crcf_run4(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 32-byte aligned q->h = (float*) _mm_malloc( 2*q->n*sizeof(float), 32 ); // set coefficients, repeated // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->h[2*i+0] = _h[k]; q->h[2*i+1] = _h[k]; } // return object return q; } dotprod_crcf dotprod_crcf_create(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 0); } dotprod_crcf dotprod_crcf_create_rev(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create_rev(_h,_n); } dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_crcf_copy().avx, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 32-byte aligned (repeated) q_copy->h = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 32 ); // copy coefficients array (repeated) // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_crcf_destroy(dotprod_crcf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) printf("dotprod_crcf [avx, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); return LIQUID_OK; } // int dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 64) { return dotprod_crcf_execute_avx(_q, _x, _y); } return dotprod_crcf_execute_avx4(_q, _x, _y); } // use AVX extensions int dotprod_crcf_execute_avx(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m256 v; // input vector __m256 h; // coefficients vector __m256 s; // dot product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) unsigned int t = (n >> 3) << 3; // unsigned int i; for (i=0; ih[i]); // compute multiplication s = _mm256_mul_ps(v, h); // accumulate sum = _mm256_add_ps(sum, s); } // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array _mm256_store_ps(w, sum); // add in-phase and quadrature components w[0] += w[2] + w[4] + w[6]; w[1] += w[3] + w[5] + w[7]; // cleanup (note: n _must_ be even) for (; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + _Complex_I*w[1]; return LIQUID_OK; } // use AVX extensions int dotprod_crcf_execute_avx4(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m256 v0, v1, v2, v3; // input vectors __m256 h0, h1, h2, h3; // coefficients vectors __m256 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers __m256 sum = _mm256_setzero_ps(); // r = 8*floor(n/32) unsigned int r = (n >> 5) << 3; // unsigned int i; for (i=0; ih[4*i+0]); h1 = _mm256_load_ps(&_q->h[4*i+8]); h2 = _mm256_load_ps(&_q->h[4*i+16]); h3 = _mm256_load_ps(&_q->h[4*i+24]); // compute multiplication s0 = _mm256_mul_ps(v0, h0); s1 = _mm256_mul_ps(v1, h1); s2 = _mm256_mul_ps(v2, h2); s3 = _mm256_mul_ps(v3, h3); // parallel addition sum = _mm256_add_ps( sum, s0 ); sum = _mm256_add_ps( sum, s1 ); sum = _mm256_add_ps( sum, s2 ); sum = _mm256_add_ps( sum, s3 ); } // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array and perform manual sum _mm256_store_ps(w, sum); w[0] += w[2] + w[4] + w[6]; w[1] += w[3] + w[5] + w[7]; // cleanup (note: n _must_ be even) for (i=4*r; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + w[1]*_Complex_I; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.avx512f.c000066400000000000000000000220221474751757600226570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX512-F) // #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CRCF_AVX 0 // forward declaration of internal methods int dotprod_crcf_execute_avx512f(dotprod_crcf _q, float complex * _x, float complex * _y); int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_crcf_run(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_crcf_run4(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 64-byte aligned q->h = (float*) _mm_malloc( 2*q->n*sizeof(float), 64 ); // set coefficients, repeated // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->h[2*i+0] = _h[k]; q->h[2*i+1] = _h[k]; } // return object return q; } dotprod_crcf dotprod_crcf_create(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 0); } dotprod_crcf dotprod_crcf_create_rev(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create_rev(_h,_n); } dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_crcf_copy().avx512f, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 64-byte aligned (repeated) q_copy->h = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 64 ); // copy coefficients array (repeated) // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_crcf_destroy(dotprod_crcf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) printf("dotprod_crcf [avx512f, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); return LIQUID_OK; } // int dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 128) { return dotprod_crcf_execute_avx512f(_q, _x, _y); } return dotprod_crcf_execute_avx512f4(_q, _x, _y); } // use AVX512-F extensions int dotprod_crcf_execute_avx512f(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m512 v; // input vector __m512 h; // coefficients vector __m512 s; // dot product __m512 sum = _mm512_setzero_ps(); // load zeros into sum register // t = 16*(floor(_n/16)) unsigned int t = (n >> 4) << 4; // unsigned int i; for (i=0; ih[i]); // compute multiplication s = _mm512_mul_ps(v, h); // accumulate sum = _mm512_add_ps(sum, s); } // output array float w[2]; // fold down I/Q components into single value w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); // cleanup (note: n _must_ be even) for (; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + _Complex_I*w[1]; return LIQUID_OK; } // use AVX512-F extensions int dotprod_crcf_execute_avx512f4(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m512 v0, v1, v2, v3; // input vectors __m512 h0, h1, h2, h3; // coefficients vectors __m512 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers __m512 sum = _mm512_setzero_ps(); // r = 16*floor(n/64) unsigned int r = (n >> 6) << 4; // unsigned int i; for (i=0; ih[4*i+0]); h1 = _mm512_load_ps(&_q->h[4*i+16]); h2 = _mm512_load_ps(&_q->h[4*i+32]); h3 = _mm512_load_ps(&_q->h[4*i+48]); // compute multiplication s0 = _mm512_mul_ps(v0, h0); s1 = _mm512_mul_ps(v1, h1); s2 = _mm512_mul_ps(v2, h2); s3 = _mm512_mul_ps(v3, h3); // parallel addition sum = _mm512_add_ps( sum, s0 ); sum = _mm512_add_ps( sum, s1 ); sum = _mm512_add_ps( sum, s2 ); sum = _mm512_add_ps( sum, s3 ); } // output array float w[2]; // fold down I/Q components into single value w[0] = _mm512_mask_reduce_add_ps(0x5555, sum); w[1] = _mm512_mask_reduce_add_ps(0xAAAA, sum); // cleanup (note: n _must_ be even) for (i=4*r; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + w[1]*_Complex_I; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.c000066400000000000000000000027271474751757600214760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point dot product // #include #include "liquid.internal.h" #define DOTPROD(name) LIQUID_CONCAT(dotprod_crcf,name) #define TO float complex #define TC float #define TI float complex #define TO_COMPLEX 1 #define TC_COMPLEX 0 #define TI_COMPLEX 1 #include "dotprod.proto.c" liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.neon.c000066400000000000000000000225171474751757600224330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (ARM Neon) // #include #include #include #include #include "liquid.internal.h" // include proper SIMD extensions for ARM Neon #include #define DEBUG_DOTPROD_CRCF_NEON 0 // forward declaration of internal methods int dotprod_crcf_execute_neon(dotprod_crcf _q, float complex * _x, float complex * _y); int dotprod_crcf_execute_neon4(dotprod_crcf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) using neon extensions int dotprod_crcf_run(float * _h, float complex * _x, unsigned int _n, float complex * _y) { // initialize accumulator float complex r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; // return result *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_crcf_run4(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients (double size) q->h = (float*) malloc( 2*q->n*sizeof(float) ); // set coefficients, repeated // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->h[2*i+0] = _h[k]; q->h[2*i+1] = _h[k]; } // return object return q; } dotprod_crcf dotprod_crcf_create(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h,_n,0); } dotprod_crcf dotprod_crcf_create_rev(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h,_n,1); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create(_h,_n); } // re-create the structured dotprod object, reversing coefficients dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create_rev(_h,_n); } dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_crcf_copy().neon, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients (repeated) q_copy->h = (float*) malloc( 2*q_copy->n*sizeof(float) ); // copy coefficients array (repeated) // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_crcf_destroy(dotprod_crcf _q) { free(_q->h); free(_q); return LIQUID_OK; } int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) printf("dotprod_crcf [arm-neon, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); return LIQUID_OK; } // int dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 32) { return dotprod_crcf_execute_neon(_q, _x, _y); } return dotprod_crcf_execute_neon4(_q, _x, _y); } // use ARM Neon extensions int dotprod_crcf_execute_neon(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... float32x4_t v; // input vector float32x4_t h; // coefficients vector float32x4_t s; // dot product // load zeros into sum register float zeros[4] = {0,0,0,0}; float32x4_t sum = vld1q_f32(zeros); // t = 4*(floor(_n/4)) unsigned int t = (n >> 2) << 2; // unsigned int i; for (i=0; ih[i]); // compute multiplication s = vmulq_f32(h,v); // accumulate sum = vaddq_f32(sum, s); } // unload packed array float w[4]; vst1q_f32(w, sum); // add in-phase and quadrature components w[0] += w[2]; w[1] += w[3]; // cleanup (note: n _must_ be even) for (; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + _Complex_I*w[1]; return LIQUID_OK; } // use ARM Neon extensions int dotprod_crcf_execute_neon4(dotprod_crcf _q, float complex * _x, float complex * _y) { #if 1 // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... float32x4_t v0, v1, v2, v3; // input vectors float32x4_t h0, h1, h2, h3; // coefficients vectors float32x4_t s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers float zeros[4] = {0,0,0,0}; float32x4_t sum0 = vld1q_f32(zeros); float32x4_t sum1 = vld1q_f32(zeros); float32x4_t sum2 = vld1q_f32(zeros); float32x4_t sum3 = vld1q_f32(zeros); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; // unsigned int i; for (i=0; ih[4*i+0]); h1 = vld1q_f32(&_q->h[4*i+4]); h2 = vld1q_f32(&_q->h[4*i+8]); h3 = vld1q_f32(&_q->h[4*i+12]); // compute multiplication s0 = vmulq_f32(v0, h0); s1 = vmulq_f32(v1, h1); s2 = vmulq_f32(v2, h2); s3 = vmulq_f32(v3, h3); // parallel addition sum0 = vaddq_f32( sum0, s0 ); sum1 = vaddq_f32( sum1, s1 ); sum2 = vaddq_f32( sum2, s2 ); sum3 = vaddq_f32( sum3, s3 ); } // fold down into sum0 sum0 = vaddq_f32( sum0, sum1 ); sum2 = vaddq_f32( sum2, sum3 ); sum0 = vaddq_f32( sum0, sum2 ); // unload packed array float w[4]; vst1q_f32(w, sum0); // add in-phase and quadrature components w[0] += w[2]; w[1] += w[3]; // cleanup (note: n _must_ be even) for (i=4*r; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + w[1]*_Complex_I; #else dotprod_crcf_execute_neon(_q, _x, _y); #endif return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_crcf.sse.c000066400000000000000000000216731474751757600222700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (SSE) // #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_CRCF_SSE 0 // forward declaration of internal methods int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y); int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y); // basic dot product (ordinal calculation) int dotprod_crcf_run(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_crcf_run4(float * _h, float complex * _x, unsigned int _n, float complex * _y) { float complex r = 0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 16-byte aligned q->h = (float*) _mm_malloc( 2*q->n*sizeof(float), 16 ); // set coefficients, repeated // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} unsigned int i; for (i=0; in; i++) { unsigned int k = _rev ? q->n-i-1 : i; q->h[2*i+0] = _h[k]; q->h[2*i+1] = _h[k]; } // return object return q; } dotprod_crcf dotprod_crcf_create(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 0); } dotprod_crcf dotprod_crcf_create_rev(float * _h, unsigned int _n) { return dotprod_crcf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_crcf dotprod_crcf_recreate(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_crcf dotprod_crcf_recreate_rev(dotprod_crcf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_crcf_destroy(_q); return dotprod_crcf_create_rev(_h,_n); } dotprod_crcf dotprod_crcf_copy(dotprod_crcf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_crcf_copy().sse, object cannot be NULL"); dotprod_crcf q_copy = (dotprod_crcf)malloc(sizeof(struct dotprod_crcf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 16-byte aligned (repeated) q_copy->h = (float*) _mm_malloc( 2*q_copy->n*sizeof(float), 16 ); // copy coefficients array (repeated) // h = { _h[0], _h[0], _h[1], _h[1], ... _h[n-1], _h[n-1]} memmove(q_copy->h, q_orig->h, 2*q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_crcf_destroy(dotprod_crcf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_crcf_print(dotprod_crcf _q) { // print coefficients to screen, skipping odd entries (due // to repeated coefficients) printf("dotprod_crcf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[2*i]); return LIQUID_OK; } // int dotprod_crcf_execute(dotprod_crcf _q, float complex * _x, float complex * _y) { // switch based on size if (_q->n < 32) { return dotprod_crcf_execute_sse(_q, _x, _y); } return dotprod_crcf_execute_sse4(_q, _x, _y); } // use SSE extensions int dotprod_crcf_execute_sse(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m128 v; // input vector __m128 h; // coefficients vector __m128 s; // dot product __m128 sum = _mm_setzero_ps(); // load zeros into sum register // t = 4*(floor(_n/4)) unsigned int t = (n >> 2) << 2; // unsigned int i; for (i=0; ih[i]); // compute multiplication s = _mm_mul_ps(v, h); // accumulate sum = _mm_add_ps(sum, s); } // aligned output array float w[4] __attribute__((aligned(16))); // unload packed array _mm_store_ps(w, sum); // add in-phase and quadrature components w[0] += w[2]; w[1] += w[3]; // cleanup (note: n _must_ be even) for (; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + _Complex_I*w[1]; return LIQUID_OK; } // use SSE extensions int dotprod_crcf_execute_sse4(dotprod_crcf _q, float complex * _x, float complex * _y) { // type cast input as floating point array float * x = (float*) _x; // double effective length unsigned int n = 2*_q->n; // first cut: ... __m128 v0, v1, v2, v3; // input vectors __m128 h0, h1, h2, h3; // coefficients vectors __m128 s0, s1, s2, s3; // dot products [re, im, re, im] // load zeros into sum registers __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (n >> 4) << 2; // unsigned int i; for (i=0; ih[4*i+0]); h1 = _mm_load_ps(&_q->h[4*i+4]); h2 = _mm_load_ps(&_q->h[4*i+8]); h3 = _mm_load_ps(&_q->h[4*i+12]); // compute multiplication s0 = _mm_mul_ps(v0, h0); s1 = _mm_mul_ps(v1, h1); s2 = _mm_mul_ps(v2, h2); s3 = _mm_mul_ps(v3, h3); // parallel addition sum = _mm_add_ps( sum, s0 ); sum = _mm_add_ps( sum, s1 ); sum = _mm_add_ps( sum, s2 ); sum = _mm_add_ps( sum, s3 ); } // aligned output array float w[4] __attribute__((aligned(16))); // unload packed array and perform manual sum _mm_store_ps(w, sum); w[0] += w[2]; w[1] += w[3]; // cleanup (note: n _must_ be even) for (i=4*r; ih[i ]; w[1] += x[i+1] * _q->h[i+1]; } // set return value *_y = w[0] + w[1]*_Complex_I; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.av.c000066400000000000000000000151501474751757600221330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (altivec velocity engine) // #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_RRRF_AV 0 // basic dot product // basic dot product // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int dotprod_rrrf_run(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product, unrolling loop // _h : coefficients array [size: 1 x _n] // _x : input array [size: 1 x _n] // _n : input lengths // _y : output dot product int dotprod_rrrf_run4(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // create 4 copies of the input coefficients (one for each // data alignment). For example: _h[4] = {1,2,3,4,5,6} // q->h[0] = {1,2,3,4,5,6} // q->h[1] = {. 1,2,3,4,5,6} // q->h[2] = {. . 1,2,3,4,5,6} // q->h[3] = {. . . 1,2,3,4,5,6} unsigned int i,j; for (i=0; i<4; i++) { q->h[i] = calloc(1+(q->n+i-1)/4,sizeof(vector float)); for (j=0; jn; j++) e->h[i][j+i] = _h[_rev ? q->n-j-1 : j]; } return q; } dotprod_rrrf dotprod_rrrf_create(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h,_n,0); } dotprod_rrrf dotprod_rrrf_create_rev(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h,_n,1); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create(_h,_n); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create_rev(_h,_n); } // destroy the structured dotprod object int dotprod_rrrf_destroy(dotprod_rrrf _q) { // clean up coefficients arrays unsigned int i; for (i=0; i<4; i++) free(_q->h[i]); // free allocated object memory free(_q); return LIQUID_OK; } // print the dotprod object int dotprod_rrrf_print(dotprod_rrrf _q) { printf("dotprod_rrrf [altivec, %u coefficients]:\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf(" %3u : %12.9f\n", i, _q->h[0][i]); return LIQUID_OK; } // execute vectorized structured inner dot product int dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _r) { int al; // input data alignment vector float *ar,*d; vector float s0,s1,s2,s3; union { vector float v; float w[4];} s; unsigned int nblocks; ar = (vector float*)( (int)_x & ~15); al = ((int)_x & 15)/sizeof(float); d = (vector float*)_q->h[al]; nblocks = (_q->n + al - 1)/4 + 1; // split into four vectors each with four 32-bit // partial sums. Effectively each loop iteration // operates on 16 input samples at a time. s0 = s1 = s2 = s3 = (vector float)(0); while (nblocks >= 4) { s0 = vec_madd(ar[nblocks-1],d[nblocks-1],s0); s1 = vec_madd(ar[nblocks-2],d[nblocks-2],s1); s2 = vec_madd(ar[nblocks-3],d[nblocks-3],s2); s3 = vec_madd(ar[nblocks-4],d[nblocks-4],s3); nblocks -= 4; } // fold the resulting partial sums into vector s0 s0 = vec_add(s0,s1); // s0 = s0+s1 s2 = vec_add(s2,s3); // s2 = s2+s3 s0 = vec_add(s0,s2); // s0 = s0+s2 // finish partial summing operations while (nblocks-- > 0) s0 = vec_madd(ar[nblocks],d[nblocks],s0); // move the result into the union s (effetively, // this loads the four 32-bit values in s0 into // the array w). s.v = vec_add(s0,(vector float)(0)); // sum the resulting array *_r = s.w[0] + s.w[1] + s.w[2] + s.w[3]; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.avx.c000066400000000000000000000203411474751757600223210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2025 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX) // #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_RRRF_AVX 0 // internal methods int dotprod_rrrf_execute_avx(dotprod_rrrf _q, float * _x, float * _y); int dotprod_rrrf_execute_avxu(dotprod_rrrf _q, float * _x, float * _y); // basic dot product (ordinal calculation) int dotprod_rrrf_run(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_rrrf_run4(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 32-byte aligned q->h = (float*) _mm_malloc( q->n*sizeof(float), 32); // set coefficients unsigned int i; for (i=0; in; i++) q->h[i] = _h[_rev ? q->n-i-1 : i]; // return object return q; } dotprod_rrrf dotprod_rrrf_create(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 0); } dotprod_rrrf dotprod_rrrf_create_rev(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create_rev(_h,_n); } dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_rrrf_copy().avx, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 32-byte aligned q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 32 ); // copy coefficients array memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_rrrf_destroy(dotprod_rrrf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_rrrf_print(dotprod_rrrf _q) { printf("dotprod_rrrf [avx, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); return LIQUID_OK; } // int dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _y) { // switch based on size if (_q->n < 32) { return dotprod_rrrf_execute_avx(_q, _x, _y); } return dotprod_rrrf_execute_avxu(_q, _x, _y); } // use AVX extensions int dotprod_rrrf_execute_avx(dotprod_rrrf _q, float * _x, float * _y) { __m256 v; // input vector __m256 h; // coefficients vector __m256 s; // dot product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) unsigned int t = (_q->n >> 3) << 3; // unsigned int i; for (i=0; ih[i]); // compute dot product s = _mm256_mul_ps(v, h); // parallel addition sum = _mm256_add_ps( sum, s ); } // fold down into single value __m256 z = _mm256_setzero_ps(); sum = _mm256_hadd_ps(sum, z); sum = _mm256_hadd_ps(sum, z); // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array _mm256_store_ps(w, sum); float total = w[0] + w[4]; // cleanup for (; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } // use AVX extensions (unrolled) int dotprod_rrrf_execute_avxu(dotprod_rrrf _q, float * _x, float * _y) { __m256 v0, v1, v2, v3; __m256 h0, h1, h2, h3; __m256 s0, s1, s2, s3; __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/32)) unsigned int r = (_q->n >> 5) << 3; // unsigned int i; for (i=0; ih[4*i+ 0]); h1 = _mm256_load_ps(&_q->h[4*i+ 8]); h2 = _mm256_load_ps(&_q->h[4*i+16]); h3 = _mm256_load_ps(&_q->h[4*i+24]); // compute dot products s0 = _mm256_mul_ps(v0, h0); s1 = _mm256_mul_ps(v1, h1); s2 = _mm256_mul_ps(v2, h2); s3 = _mm256_mul_ps(v3, h3); // parallel addition sum = _mm256_add_ps( sum, s0 ); sum = _mm256_add_ps( sum, s1 ); sum = _mm256_add_ps( sum, s2 ); sum = _mm256_add_ps( sum, s3 ); } // fold down into single value __m256 z = _mm256_setzero_ps(); sum = _mm256_hadd_ps(sum, z); sum = _mm256_hadd_ps(sum, z); // aligned output array float w[8] __attribute__((aligned(32))); // unload packed array _mm256_store_ps(w, sum); float total = w[0] + w[4]; // cleanup for (i=4*r; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.avx512f.c000066400000000000000000000177331474751757600227320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (AVX512-F) // #include #include #include #include #include "liquid.internal.h" // include proper SIMD extensions for x86 platforms // NOTE: these pre-processor macros are defined in config.h #include // AVX #define DEBUG_DOTPROD_RRRF_AVX 0 // internal methods int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, float * _x, float * _y); int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, float * _x, float * _y); // basic dot product (ordinal calculation) int dotprod_rrrf_run(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_rrrf_run4(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 64-byte aligned q->h = (float*) _mm_malloc( q->n*sizeof(float), 64); // set coefficients unsigned int i; for (i=0; in; i++) q->h[i] = _h[_rev ? q->n-i-1 : i]; // return object return q; } dotprod_rrrf dotprod_rrrf_create(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 0); } dotprod_rrrf dotprod_rrrf_create_rev(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create_rev(_h,_n); } dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_rrrf_copy().avx512f, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 64-byte aligned q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 64 ); // copy coefficients array memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_rrrf_destroy(dotprod_rrrf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_rrrf_print(dotprod_rrrf _q) { printf("dotprod_rrrf [avx512f, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); return LIQUID_OK; } // int dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _y) { // switch based on size if (_q->n < 64) { return dotprod_rrrf_execute_avx512f(_q, _x, _y); } return dotprod_rrrf_execute_avx512fu(_q, _x, _y); } // use AVX512-F extensions int dotprod_rrrf_execute_avx512f(dotprod_rrrf _q, float * _x, float * _y) { __m512 v; // input vector __m512 h; // coefficients vector __m512 s; // dot product __m512 sum = _mm512_setzero_ps(); // load zeros into sum register // t = 16*(floor(_n/16)) unsigned int t = (_q->n >> 4) << 4; // unsigned int i; for (i=0; ih[i]); // compute dot product s = _mm512_mul_ps(v, h); // parallel addition sum = _mm512_add_ps( sum, s ); } // fold down into single value float total = _mm512_reduce_add_ps(sum); // cleanup for (; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } // use AVX512-F extensions (unrolled) int dotprod_rrrf_execute_avx512fu(dotprod_rrrf _q, float * _x, float * _y) { __m512 v0, v1, v2, v3; __m512 h0, h1, h2, h3; __m512 s0, s1, s2, s3; __m512 sum = _mm512_setzero_ps(); // load zeros into sum register // t = 16*(floor(_n/64)) unsigned int r = (_q->n >> 6) << 4; // unsigned int i; for (i=0; ih[4*i+ 0]); h1 = _mm512_load_ps(&_q->h[4*i+16]); h2 = _mm512_load_ps(&_q->h[4*i+32]); h3 = _mm512_load_ps(&_q->h[4*i+48]); // compute dot products s0 = _mm512_mul_ps(v0, h0); s1 = _mm512_mul_ps(v1, h1); s2 = _mm512_mul_ps(v2, h2); s3 = _mm512_mul_ps(v3, h3); // parallel addition sum = _mm512_add_ps( sum, s0 ); sum = _mm512_add_ps( sum, s1 ); sum = _mm512_add_ps( sum, s2 ); sum = _mm512_add_ps( sum, s3 ); } // fold down into single value float total = _mm512_reduce_add_ps(sum); // cleanup for (i=4*r; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.c000066400000000000000000000026521474751757600215310ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product // #include "liquid.internal.h" #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define TO float #define TC float #define TI float #define TO_COMPLEX 0 #define TC_COMPLEX 0 #define TI_COMPLEX 0 #include "dotprod.proto.c" liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.neon.c000066400000000000000000000164061474751757600224710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (ARM Neon) // #include #include #include #include #include "liquid.internal.h" // include proper SIMD extensions for ARM Neon #include #define DEBUG_DOTPROD_RRRF_NEON 0 // basic dot product (ordinal calculation) using neon extensions int dotprod_rrrf_run(float * _h, float * _x, unsigned int _n, float * _y) { float32x4_t v; // input vector float32x4_t h; // coefficients vector float32x4_t s; // dot product // load zeros into sum register float zeros[4] = {0,0,0,0}; float32x4_t sum = vld1q_f32(zeros); // t = 4*(floor(_n/4)) unsigned int t = (_n >> 2) << 2; // unsigned int i; for (i=0; i> 4) << 2; // unsigned int i; for (i=0; in = _n; // allocate memory for coefficients q->h = (float*) malloc( q->n*sizeof(float) ); // copy coefficients unsigned int i; for (i=0; in; i++) q->h[i] = _h[_rev ? q->n-i-1 : i]; // return object return q; } dotprod_rrrf dotprod_rrrf_create(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h,_n,0); } dotprod_rrrf dotprod_rrrf_create_rev(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h,_n,1); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create(_h,_n); } // re-create the structured dotprod object, reversing coefficients dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create_rev(_h,_n); } dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_rrrf_copy().neon, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients q_copy->h = (float*) malloc( q_copy->n*sizeof(float) ); // copy coefficients array memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); // return object return q_copy; } // destroy dotprod object, freeing internal memory int dotprod_rrrf_destroy(dotprod_rrrf _q) { free(_q->h); free(_q); return LIQUID_OK; } // print dotprod internal state int dotprod_rrrf_print(dotprod_rrrf _q) { printf("dotprod_rrrf [arm-neon, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); return LIQUID_OK; } // execute dot product on input vector int dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _y) { // switch based on size if (_q->n < 16) { return dotprod_rrrf_run(_q->h, _x, _q->n, _y); } return dotprod_rrrf_run4(_q->h, _x, _q->n, _y); } liquid-dsp-1.7.0/src/dotprod/src/dotprod_rrrf.sse.c000066400000000000000000000210331474751757600223140ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point dot product (SSE) // #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DOTPROD_RRRF_SSE 0 // internal methods int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y); int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y); // basic dot product (ordinal calculation) int dotprod_rrrf_run(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; unsigned int i; for (i=0; i<_n; i++) r += _h[i] * _x[i]; *_y = r; return LIQUID_OK; } // basic dot product (ordinal calculation) with loop unrolled int dotprod_rrrf_run4(float * _h, float * _x, unsigned int _n, float * _y) { float r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute dotprod in groups of 4 unsigned int i; for (i=0; in = _n; // allocate memory for coefficients, 16-byte aligned q->h = (float*) _mm_malloc( q->n*sizeof(float), 16); // set coefficients unsigned int i; for (i=0; in; i++) q->h[i] = _h[_rev ? q->n-i-1 : i]; // return object return q; } dotprod_rrrf dotprod_rrrf_create(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 0); } dotprod_rrrf dotprod_rrrf_create_rev(float * _h, unsigned int _n) { return dotprod_rrrf_create_opt(_h, _n, 1); } // re-create the structured dotprod object dotprod_rrrf dotprod_rrrf_recreate(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create(_h,_n); } // re-create the structured dotprod object, coefficients reversed dotprod_rrrf dotprod_rrrf_recreate_rev(dotprod_rrrf _q, float * _h, unsigned int _n) { // completely destroy and re-create dotprod object dotprod_rrrf_destroy(_q); return dotprod_rrrf_create_rev(_h,_n); } dotprod_rrrf dotprod_rrrf_copy(dotprod_rrrf q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dotprod_rrrf_copy().sse, object cannot be NULL"); dotprod_rrrf q_copy = (dotprod_rrrf)malloc(sizeof(struct dotprod_rrrf_s)); q_copy->n = q_orig->n; // allocate memory for coefficients, 16-byte aligned q_copy->h = (float*) _mm_malloc( q_copy->n*sizeof(float), 16 ); // copy coefficients array memmove(q_copy->h, q_orig->h, q_orig->n*sizeof(float)); // return object return q_copy; } int dotprod_rrrf_destroy(dotprod_rrrf _q) { _mm_free(_q->h); free(_q); return LIQUID_OK; } int dotprod_rrrf_print(dotprod_rrrf _q) { printf("dotprod_rrrf [sse, %u coefficients]\n", _q->n); unsigned int i; for (i=0; i<_q->n; i++) printf("%3u : %12.9f\n", i, _q->h[i]); return LIQUID_OK; } // int dotprod_rrrf_execute(dotprod_rrrf _q, float * _x, float * _y) { // switch based on size if (_q->n < 16) { return dotprod_rrrf_execute_sse(_q, _x, _y); } return dotprod_rrrf_execute_sse4(_q, _x, _y); } // use SSE extensions int dotprod_rrrf_execute_sse(dotprod_rrrf _q, float * _x, float * _y) { // first cut: ... __m128 v; // input vector __m128 h; // coefficients vector __m128 s; // dot product __m128 sum = _mm_setzero_ps(); // load zeros into sum register // t = 4*(floor(_n/4)) unsigned int t = (_q->n >> 2) << 2; // unsigned int i; for (i=0; ih[i]); // compute multiplication s = _mm_mul_ps(v, h); // parallel addition sum = _mm_add_ps( sum, s ); } // aligned output array float w[4] __attribute__((aligned(16))); #if HAVE_SSE3 // fold down into single value __m128 z = _mm_setzero_ps(); sum = _mm_hadd_ps(sum, z); sum = _mm_hadd_ps(sum, z); // unload single (lower value) _mm_store_ss(w, sum); float total = w[0]; #else // unload packed array _mm_store_ps(w, sum); float total = w[0] + w[1] + w[2] + w[3]; #endif // cleanup for (; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } // use SSE extensions, unrolled loop int dotprod_rrrf_execute_sse4(dotprod_rrrf _q, float * _x, float * _y) { // first cut: ... __m128 v0, v1, v2, v3; __m128 h0, h1, h2, h3; __m128 s0, s1, s2, s3; // load zeros into sum registers __m128 sum = _mm_setzero_ps(); // r = 4*floor(n/16) unsigned int r = (_q->n >> 4) << 2; // unsigned int i; for (i=0; ih[4*i+0]); h1 = _mm_load_ps(&_q->h[4*i+4]); h2 = _mm_load_ps(&_q->h[4*i+8]); h3 = _mm_load_ps(&_q->h[4*i+12]); // compute multiplication s0 = _mm_mul_ps(v0, h0); s1 = _mm_mul_ps(v1, h1); s2 = _mm_mul_ps(v2, h2); s3 = _mm_mul_ps(v3, h3); // parallel addition sum = _mm_add_ps( sum, s0 ); sum = _mm_add_ps( sum, s1 ); sum = _mm_add_ps( sum, s2 ); sum = _mm_add_ps( sum, s3 ); } // aligned output array float w[4] __attribute__((aligned(16))); #if HAVE_SSE3 // SSE3: fold down to single value using _mm_hadd_ps() __m128 z = _mm_setzero_ps(); sum = _mm_hadd_ps(sum, z); sum = _mm_hadd_ps(sum, z); // unload single (lower value) _mm_store_ss(w, sum); float total = w[0]; #else // SSE2 and below: unload packed array and perform manual sum _mm_store_ps(w, sum); float total = w[0] + w[1] + w[2] + w[3]; #endif // cleanup // TODO : use intrinsics here as well for (i=4*r; i<_q->n; i++) total += _x[i] * _q->h[i]; // set return value *_y = total; return LIQUID_OK; } liquid-dsp-1.7.0/src/dotprod/src/sumsq.avx.c000066400000000000000000000106321474751757600207650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2025 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sumsq.avx.c : floating-point sum of squares (AVX) // #include #include #include #include #include "liquid.internal.h" // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length float liquid_sumsqf_avx(float * _v, unsigned int _n) { // first cut: ... __m256 v; // input vector __m256 s; // product __m256 sum = _mm256_setzero_ps(); // load zeros into sum register // t = 8*(floor(_n/8)) unsigned int t = (_n >> 3) << 3; // unsigned int i; for (i=0; i> 5) << 3; // unsigned int i; for (i=0; i #include #include #include "liquid.internal.h" // include proper SIMD extensions for x86 platforms #include // AVX // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length float liquid_sumsqf_avx(float * _v, unsigned int _n) { // first cut: ... __m512 v; // input vector __m512 s; // product __m512 sum = _mm512_setzero_ps(); // load zeros into sum register // t = 16*(floor(_n/16)) unsigned int t = (_n >> 4) << 4; // unsigned int i; for (i=0; i> 6) << 4; // unsigned int i; for (i=0; i #include #include #include "liquid.internal.h" // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length float liquid_sumsqf(float * _v, unsigned int _n) { // initialize accumulator float r=0; // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // run computation in groups of 4 unsigned int i; for (i=0; i #include #include #include #include "liquid.internal.h" // sum squares, basic loop // _v : input array [size: 1 x _n] // _n : input length float liquid_sumsqf_sse(float * _v, unsigned int _n) { // first cut: ... __m128 v; // input vector __m128 s; // dot product __m128 sum = _mm_setzero_ps(); // load zeros into sum register // t = 4*(floor(_n/4)) unsigned int t = (_n >> 2) << 2; // unsigned int i; for (i=0; i> 4) << 2; // unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: basic dot product // void autotest_dotprod_rrrf_basic() { float tol = 1e-6; // error tolerance float y; // return value float h[16] = { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1}; float x0[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; float test0 = 0; dotprod_rrrf_run(h,x0,16,&y); CONTEND_DELTA(y, test0, tol); dotprod_rrrf_run4(h,x0,16,&y); CONTEND_DELTA(y, test0, tol); float x1[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; float test1 = 0; dotprod_rrrf_run(h,x1,16,&y); CONTEND_DELTA(y, test1, tol); dotprod_rrrf_run4(h,x1,16,&y); CONTEND_DELTA(y, test1, tol); float x2[16] = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}; float test2 = -8; dotprod_rrrf_run(h,x2,16,&y); CONTEND_DELTA(y, test2, tol); dotprod_rrrf_run4(h,x2,16,&y); CONTEND_DELTA(y, test2, tol); float x3[16] = {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}; float test3 = 8; dotprod_rrrf_run(h,x3,16,&y); CONTEND_DELTA(y, test3, tol); dotprod_rrrf_run4(h,x3,16,&y); CONTEND_DELTA(y, test3, tol); float test4 = 16; dotprod_rrrf_run(h,h,16,&y); CONTEND_DELTA(y, test4, tol); dotprod_rrrf_run4(h,h,16,&y); CONTEND_DELTA(y, test4, tol); } // // AUTOTEST: uneven dot product // void autotest_dotprod_rrrf_uneven() { float tol = 1e-6; float y; float h[16] = { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1}; float x[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; float test1 = 1; dotprod_rrrf_run(h,x,1,&y); CONTEND_DELTA(y, test1, tol); float test2 = 0; dotprod_rrrf_run(h,x,2,&y); CONTEND_DELTA(y, test2, tol); float test3 = 1; dotprod_rrrf_run(h,x,3,&y); CONTEND_DELTA(y, test3, tol); float test11 = 1; dotprod_rrrf_run(h,x,11,&y); CONTEND_DELTA(y, test11, tol); float test13 = 1; dotprod_rrrf_run(h,x,13,&y); CONTEND_DELTA(y, test13, tol); float test15 = 1; dotprod_rrrf_run(h,x,15,&y); CONTEND_DELTA(y, test15, tol); } // // AUTOTEST: structured dot product // void autotest_dotprod_rrrf_struct() { float tol = 1e-6; float y; float h[16] = { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1}; // create object dotprod_rrrf dp = dotprod_rrrf_create(h,16); float x0[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; float test0 = 0; dotprod_rrrf_execute(dp,x0,&y); CONTEND_DELTA(y, test0, tol); float x1[16] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; float test1 = 0; dotprod_rrrf_execute(dp,x1,&y); CONTEND_DELTA(y, test1, tol); float x2[16] = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}; float test2 = -8; dotprod_rrrf_execute(dp,x2,&y); CONTEND_DELTA(y, test2, tol); float *x3 = h; float test3 = 16; dotprod_rrrf_execute(dp,x3,&y); CONTEND_DELTA(y, test3, tol); // clean-up dotprod_rrrf_destroy(dp); } // // AUTOTEST: structured dot product with floating-point data // void autotest_dotprod_rrrf_struct_align() { float h[16] = { -0.050565, -0.952580, 0.274320, 1.232400, 1.268200, 0.565770, 0.800830, 0.923970, 0.517060, -0.530340, -0.378550, -1.127100, 1.123100, -1.006000, -1.483800, -0.062007 }; float x[16] = { -0.384280, -0.812030, 0.156930, 1.919500, 0.564580, -0.123610, -0.138640, 0.004984, -1.100200, -0.497620, 0.089977, -1.745500, 0.463640, 0.592100, 1.150000, -1.225400 }; float test = 3.66411513609863; float tol = 1e-3f; float y; // create dotprod object dotprod_rrrf dp = dotprod_rrrf_create(h,16); // test data misalignment conditions float x_buffer[20]; float * x_hat; unsigned int i; for (i=0; i<4; i++) { // set pointer to array aligned with counter x_hat = &x_buffer[i]; // copy input data to buffer memmove(x_hat, x, 16*sizeof(float)); // execute dotprod dotprod_rrrf_execute(dp,x_hat,&y); CONTEND_DELTA(y,test,tol); } // destroy dotprod object dotprod_rrrf_destroy(dp); } // // AUTOTEST: dot product with floating-point data // void autotest_dotprod_rrrf_rand01() { float h[16] = { -0.050565, -0.952580, 0.274320, 1.232400, 1.268200, 0.565770, 0.800830, 0.923970, 0.517060, -0.530340, -0.378550, -1.127100, 1.123100, -1.006000, -1.483800, -0.062007 }; float x[16] = { -0.384280, -0.812030, 0.156930, 1.919500, 0.564580, -0.123610, -0.138640, 0.004984, -1.100200, -0.497620, 0.089977, -1.745500, 0.463640, 0.592100, 1.150000, -1.225400 }; float test = 3.66411513609863; float tol = 1e-3f; float y; dotprod_rrrf_run(h,x,16,&y); CONTEND_DELTA(y,test,tol); } // // AUTOTEST: dot product with floating-point data // void autotest_dotprod_rrrf_rand02() { float h[16] = { 2.595300, 1.243600, -0.818550, -1.439800, 0.055795, -1.476000, 0.445900, 0.325460, -3.451200, 0.058528, -0.246990, 0.476290, -0.598780, -0.885250, 0.464660, -0.610140 }; float x[16] = { -0.917010, -1.278200, -0.533190, 2.309200, 0.592980, 0.964820, 0.183220, -0.082864, 0.057171, -1.186500, -0.738260, 0.356960, -0.144000, -1.435200, -0.893420, 1.657800 }; float test = -8.17832326680587; float test_rev = 4.56839328512000; float tol = 1e-3f; float y; dotprod_rrrf_run(h,x,16,&y); CONTEND_DELTA(y,test,tol); // create object dotprod_rrrf q = dotprod_rrrf_create(h,16); dotprod_rrrf_execute(q,x,&y); CONTEND_DELTA(y,test,tol); // test running in reverse q = dotprod_rrrf_recreate_rev(q,h,16); dotprod_rrrf_execute(q,x,&y); CONTEND_DELTA(y,test_rev,tol); // create original again q = dotprod_rrrf_recreate(q,h,16); dotprod_rrrf_execute(q,x,&y); CONTEND_DELTA(y,test,tol); // clean it up dotprod_rrrf_destroy(q); } // // AUTOTEST: structured dot product, odd lengths // void autotest_dotprod_rrrf_struct_lengths() { float tol = 2e-6; float y; float x[35] = { 0.03117498, -1.54311769, -0.58759073, -0.73882202, 0.86592259, -0.26669417, -0.70153724, -1.24555787, -1.09272288, -1.41984975, -1.40299260, 0.95861481, -0.67361246, 2.05305710, 1.26576873, -0.77474848, -0.93143252, -1.05724660, 0.21455006, 1.07554168, -0.46703810, 0.68878404, -1.11900266, -0.52016966, 0.61400744, -0.46506142, -0.16801031, 0.48237303, 0.51286055, -0.57239385, -0.64462740, -0.75596668, 1.95612355, -0.47917908, 0.52384983, }; float h[35] = { -0.12380948, 0.88417134, 2.27373797, -2.61506417, 0.35022002, 0.07481393, 0.52984228, -0.65542307, -2.14893606, 0.62466395, 0.07330391, -1.28014856, 0.16347776, 0.21238151, 0.05462232, -0.60290942, -1.27658956, 3.05114996, 1.34789601, -1.22098592, 1.70899633, -0.41002037, 3.08009931, -1.39895771, -0.50875066, 0.25817865, 1.08668549, 0.05494174, -1.05337166, 1.26772604, 1.00369204, -0.55129338, 1.01828299, 0.76014664, -0.15605569, }; float v32 = -7.99577847f; float v33 = -6.00389114f; float v34 = -6.36813751f; float v35 = -6.44988725f; // dotprod_rrrf dp; // n = 32 dp = dotprod_rrrf_create(h,32); dotprod_rrrf_execute(dp, x, &y); CONTEND_DELTA(y, v32, tol); dotprod_rrrf_destroy(dp); if (liquid_autotest_verbose) printf(" dotprod-rrrf-32 : %12.8f (expected %12.8f)\n", y, v32); // n = 33 dp = dotprod_rrrf_create(h,33); dotprod_rrrf_execute(dp, x, &y); CONTEND_DELTA(y, v33, tol); dotprod_rrrf_destroy(dp); if (liquid_autotest_verbose) printf(" dotprod-rrrf-33 : %12.8f (expected %12.8f)\n", y, v33); // n = 34 dp = dotprod_rrrf_create(h,34); dotprod_rrrf_execute(dp, x, &y); CONTEND_DELTA(y, v34, tol); dotprod_rrrf_destroy(dp); if (liquid_autotest_verbose) printf(" dotprod-rrrf-34 : %12.8f (expected %12.8f)\n", y, v34); // n = 35 dp = dotprod_rrrf_create(h,35); dotprod_rrrf_execute(dp, x, &y); CONTEND_DELTA(y, v35, tol); dotprod_rrrf_destroy(dp); if (liquid_autotest_verbose) printf(" dotprod-rrrf-35 : %12.8f (expected %12.8f)\n", y, v35); } // // AUTOTEST: compare structured result to ordinal computation // // helper function (compare structured object to ordinal computation) void runtest_dotprod_rrrf(unsigned int _n) { float tol = 1e-4; float h[_n]; float x[_n]; // generate random coefficients unsigned int i; for (i=0; i<_n; i++) { h[i] = randnf(); x[i] = randnf(); } // compute expected value (ordinal computation) float y_test=0; for (i=0; i<_n; i++) y_test += h[i] * x[i]; // create and run dot product object float y_struct; dotprod_rrrf dp; dp = dotprod_rrrf_create(h,_n); dotprod_rrrf_execute(dp, x, &y_struct); dotprod_rrrf_destroy(dp); // run unstructured float y_run, y_run4; dotprod_rrrf_run (h,x,_n,&y_run ); dotprod_rrrf_run4(h,x,_n,&y_run4); // print results if (liquid_autotest_verbose) { printf(" dotprod-rrrf-%-4u(struct) : %12.8f (expected %12.8f)\n", _n, y_struct, y_test); printf(" dotprod-rrrf-%-4u(run ) : %12.8f (expected %12.8f)\n", _n, y_run, y_test); printf(" dotprod-rrrf-%-4u(run4 ) : %12.8f (expected %12.8f)\n", _n, y_run4, y_test); } // validate result (structured object) CONTEND_DELTA(y_struct, y_test, tol); // validate result (unstructured, run) CONTEND_DELTA(y_run, y_test, tol); // validate result (unstructured, run4) CONTEND_DELTA(y_run4, y_test, tol); } // compare structured object to ordinal computation void autotest_dotprod_rrrf_struct_vs_ordinal() { // run many, many tests unsigned int i; for (i=1; i<=512; i++) runtest_dotprod_rrrf(i); } liquid-dsp-1.7.0/src/dotprod/tests/sumsqcf_autotest.c000066400000000000000000000126641474751757600230130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // test data float complex sumsqcf_test_x3[3]; float sumsqcf_test_y3; float complex sumsqcf_test_x4[4]; float sumsqcf_test_y4; float complex sumsqcf_test_x7[7]; float sumsqcf_test_y7; float complex sumsqcf_test_x8[8]; float sumsqcf_test_y8; float complex sumsqcf_test_x15[15]; float sumsqcf_test_y15; float complex sumsqcf_test_x16[16]; float sumsqcf_test_y16; // helper function void sumsqcf_runtest(float complex * _x, unsigned int _n, float _y) { float tol = 1e-6; // error tolerance // run test float y = liquid_sumsqcf(_x, _n); CONTEND_DELTA( y, _y, tol ); } // // AUTOTESTS : run test with pre-determined data sets // void autotest_sumsqcf_3() { sumsqcf_runtest( sumsqcf_test_x3, 3, sumsqcf_test_y3 ); } void autotest_sumsqcf_4() { sumsqcf_runtest( sumsqcf_test_x4, 4, sumsqcf_test_y4 ); } void autotest_sumsqcf_7() { sumsqcf_runtest( sumsqcf_test_x7, 7, sumsqcf_test_y7 ); } void autotest_sumsqcf_8() { sumsqcf_runtest( sumsqcf_test_x8, 8, sumsqcf_test_y8 ); } void autotest_sumsqcf_15() { sumsqcf_runtest( sumsqcf_test_x15, 15, sumsqcf_test_y15 ); } void autotest_sumsqcf_16() { sumsqcf_runtest( sumsqcf_test_x16, 16, sumsqcf_test_y16 ); } float complex sumsqcf_test_x3[3] = { -0.143606511525 + -0.137405158308*_Complex_I, -0.155077565599 + -0.128712786230*_Complex_I, 0.259257309730 + -0.354313982924*_Complex_I}; float sumsqcf_test_y3 = 0.272871791516851; float complex sumsqcf_test_x4[4] = { -0.027688113439 + 0.014257850202*_Complex_I, 0.135913101830 + -0.193497844930*_Complex_I, -0.184688262513 + -0.018367564232*_Complex_I, 0.033677897260 + -0.365996497668*_Complex_I}; float sumsqcf_test_y4 = 0.226418463954813; float complex sumsqcf_test_x7[7] = { -0.052790293375 + 0.173778162166*_Complex_I, 0.026113336498 + -0.228399854303*_Complex_I, 0.060259677552 + -0.064704230326*_Complex_I, -0.085637350173 + -0.140391580928*_Complex_I, 0.137662823620 + -0.049602389650*_Complex_I, 0.081078554377 + 0.103320097893*_Complex_I, -0.140068020211 + -0.028552894932*_Complex_I}; float sumsqcf_test_y7 = 0.179790025178960; float complex sumsqcf_test_x8[8] = { -0.114842287937 + -0.044108491804*_Complex_I, -0.027032488500 + -0.098073597323*_Complex_I, -0.248865158871 + -0.058431293594*_Complex_I, 0.152349654138 + 0.011146740847*_Complex_I, 0.100890388238 + 0.037191727983*_Complex_I, -0.173317554621 + -0.287191794305*_Complex_I, 0.159045702603 + -0.097006888823*_Complex_I, -0.048463564653 + -0.123659611524*_Complex_I}; float sumsqcf_test_y8 = 0.290592731534459; float complex sumsqcf_test_x15[15] = { -0.233166865552 + -0.325575589001*_Complex_I, -0.062157314569 + -0.052675113778*_Complex_I, -0.184924733094 + -0.037448582846*_Complex_I, -0.019336799407 + -0.146627815330*_Complex_I, 0.014671587594 + -0.040490423681*_Complex_I, -0.070920638099 + 0.353056761369*_Complex_I, 0.342121380549 + 0.016365636789*_Complex_I, 0.407809024847 + -0.067677610212*_Complex_I, 0.166345037028 + -0.070618449000*_Complex_I, -0.151572833379 + -0.241061531174*_Complex_I, -0.295395183108 + 0.107933512849*_Complex_I, 0.214887288420 + 0.158211288996*_Complex_I, 0.089528110626 + 0.534731503540*_Complex_I, -0.387245894254 + 0.127860010582*_Complex_I, -0.123711595377 + 0.212526707755*_Complex_I}; float sumsqcf_test_y15 = 1.44880523546855; float complex sumsqcf_test_x16[16] = { -0.065168142317 + 0.069453199546*_Complex_I, 0.175268433034 + -0.227486860237*_Complex_I, -0.190532229460 + 0.079975095234*_Complex_I, 0.119309235855 + -0.238114343006*_Complex_I, 0.125737810036 + 0.045214179459*_Complex_I, -0.197170380197 + -0.159688600627*_Complex_I, 0.075166226059 + 0.148949236785*_Complex_I, -0.290229918639 + 0.019293769432*_Complex_I, -0.145299853755 + -0.083512058709*_Complex_I, -0.256618190275 + -0.450932031739*_Complex_I, -0.169487127499 + 0.187004249967*_Complex_I, 0.203885942759 + 0.121347578873*_Complex_I, -0.176280563451 + -0.304717971490*_Complex_I, 0.240587060249 + -0.055540407201*_Complex_I, 0.022889112723 + 0.027170265053*_Complex_I, 0.265769617236 + -0.023686695049*_Complex_I}; float sumsqcf_test_y16 = 1.07446555417927; liquid-dsp-1.7.0/src/dotprod/tests/sumsqf_autotest.c000066400000000000000000000077531474751757600226530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // test data float sumsqf_test_x3[3]; float sumsqf_test_y3; float sumsqf_test_x4[4]; float sumsqf_test_y4; float sumsqf_test_x7[7]; float sumsqf_test_y7; float sumsqf_test_x8[8]; float sumsqf_test_y8; float sumsqf_test_x15[15]; float sumsqf_test_y15; float sumsqf_test_x16[16]; float sumsqf_test_y16; // helper function void sumsqf_runtest(float * _x, unsigned int _n, float _y) { float tol = 1e-6; // error tolerance // run test float y = liquid_sumsqf(_x, _n); CONTEND_DELTA( y, _y, tol ); } // // AUTOTESTS : run test with pre-determined data sets // void autotest_sumsqf_3() { sumsqf_runtest( sumsqf_test_x3, 3, sumsqf_test_y3 ); } void autotest_sumsqf_4() { sumsqf_runtest( sumsqf_test_x4, 4, sumsqf_test_y4 ); } void autotest_sumsqf_7() { sumsqf_runtest( sumsqf_test_x7, 7, sumsqf_test_y7 ); } void autotest_sumsqf_8() { sumsqf_runtest( sumsqf_test_x8, 8, sumsqf_test_y8 ); } void autotest_sumsqf_15() { sumsqf_runtest( sumsqf_test_x15, 15, sumsqf_test_y15 ); } void autotest_sumsqf_16() { sumsqf_runtest( sumsqf_test_x16, 16, sumsqf_test_y16 ); } float sumsqf_test_x3[3] = { -0.4546496371984978f, 0.4451201395218938f, 0.0138788690209525f}; float sumsqf_test_y3 = 0.405030854218017; float sumsqf_test_x4[4] = { 0.1322698385026883f, -0.0569081631536912f, -0.3244384492417431f, -0.2872733941910143f}; float sumsqf_test_y4 = 0.208520159567467; float sumsqf_test_x7[7] = { -0.221079351597278f, -0.227902662215897f, 0.382941891419158f, 0.246800053933030f, -0.190152017725480f, 0.395758452636014f, 0.211220685416265f}; float sumsqf_test_y7 = 0.545767182598435; float sumsqf_test_x8[8] = { -0.3405090291337944f, 0.5568858414046379f, -0.0870643704340343f, 0.1724369367547939f, -0.7379946538182081f, -0.3514326419380984f, 0.2782541955998314f, 0.4354875172406391f}; float sumsqf_test_y8 = 1.39859872696022; float sumsqf_test_x15[15] = { -0.4630291295549499f, -0.2776019612369674f, -0.4933486186123937f, -0.0850997992116534f, 0.0117036410972943f, 0.0215560948199280f, 0.1203298759952301f, 0.5866344749815807f, 0.3791165816771581f, -0.4070288299889871f, -0.4971431800502791f, -0.2142770391709351f, 0.3330589842198580f, -0.0150675851612766f, -0.3947266044391958f}; float sumsqf_test_y15 = 1.77074683901981f; float sumsqf_test_x16[16] = { -0.2975264216819841f, 0.5642827287388987f, -0.7956166087428503f, -0.1931368701566655f, -0.0287212417958668f, 0.3697266870899014f, 0.0791822603183984f, 0.1668276194302965f, 0.2048176237333448f, -0.0617609549162579f, 0.5317006403634014f, -0.3964290790294236f, 0.5404940967800361f, 0.1755457122664283f, 0.1585602895144933f, 0.0791731424937176f}; float sumsqf_test_y16 = 2.08885480396333f; liquid-dsp-1.7.0/src/equalization/000077500000000000000000000000001474751757600171155ustar00rootroot00000000000000liquid-dsp-1.7.0/src/equalization/bench/000077500000000000000000000000001474751757600201745ustar00rootroot00000000000000liquid-dsp-1.7.0/src/equalization/bench/eqlms_cccf_benchmark.c000066400000000000000000000061331474751757600244540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "liquid.h" #define EQLMS_CCCF_TRAIN_BENCH_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { eqlms_cccf_train_bench(_start, _finish, _num_iterations, N); } // Helper function to keep code base small void eqlms_cccf_train_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _h_len) { // scale number of iterations appropriately // log(cycles/trial) ~ 5.63 + 0.767*log(_h_len) *_num_iterations *= 3200; *_num_iterations /= (unsigned int) expf(5.63f + 0.767f*logf(_h_len)); *_num_iterations = (*_num_iterations < 4) ? 4 : *_num_iterations; eqlms_cccf eq = eqlms_cccf_create(NULL,_h_len); unsigned long int i; // set up initial arrays to 'randomize' inputs/outputs float complex y[11]; for (i=0; i<11; i++) y[i] = randnf() + _Complex_I*randnf(); float complex d[13]; for (i=0; i<13; i++) d[i] = randnf() + _Complex_I*randnf(); unsigned int iy=0; unsigned int id=0; float complex z; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { eqlms_cccf_push(eq, y[iy]); // push input into equalizer eqlms_cccf_execute(eq, &z); // compute equalizer output eqlms_cccf_step(eq, d[id], z); // step equalizer internals // update counters iy = (iy+1)%11; id = (id+1)%13; } getrusage(RUSAGE_SELF, _finish); eqlms_cccf_destroy(eq); } // void benchmark_eqlms_cccf_n4 EQLMS_CCCF_TRAIN_BENCH_API(4) void benchmark_eqlms_cccf_n8 EQLMS_CCCF_TRAIN_BENCH_API(8) void benchmark_eqlms_cccf_n16 EQLMS_CCCF_TRAIN_BENCH_API(16) void benchmark_eqlms_cccf_n32 EQLMS_CCCF_TRAIN_BENCH_API(32) void benchmark_eqlms_cccf_n64 EQLMS_CCCF_TRAIN_BENCH_API(64) liquid-dsp-1.7.0/src/equalization/bench/eqrls_cccf_benchmark.c000066400000000000000000000061311474751757600244570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "liquid.h" #define EQRLS_CCCF_TRAIN_BENCH_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { eqrls_cccf_train_bench(_start, _finish, _num_iterations, N); } // Helper function to keep code base small void eqrls_cccf_train_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _h_len) { // scale number of iterations appropriately // log(cycles/trial) ~ 5.57 + 2.74*log(_h_len) *_num_iterations *= 2400; *_num_iterations /= (unsigned int) expf(5.57f + 2.64f*logf(_h_len)); *_num_iterations = (*_num_iterations < 4) ? 4 : *_num_iterations; eqrls_cccf eq = eqrls_cccf_create(NULL,_h_len); unsigned long int i; // set up initial arrays to 'randomize' inputs/outputs float complex y[11]; for (i=0; i<11; i++) y[i] = randnf() + _Complex_I*randnf(); float complex d[13]; for (i=0; i<13; i++) d[i] = randnf() + _Complex_I*randnf(); unsigned int iy=0; unsigned int id=0; float complex z; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { eqrls_cccf_push(eq, y[iy]); // push input into equalizer eqrls_cccf_execute(eq, &z); // compute equalizer output eqrls_cccf_step(eq, d[id], z); // step equalizer internals // update counters iy = (iy+1)%11; id = (id+1)%13; } getrusage(RUSAGE_SELF, _finish); eqrls_cccf_destroy(eq); } // void benchmark_eqrls_cccf_n4 EQRLS_CCCF_TRAIN_BENCH_API(4) void benchmark_eqrls_cccf_n8 EQRLS_CCCF_TRAIN_BENCH_API(8) void benchmark_eqrls_cccf_n16 EQRLS_CCCF_TRAIN_BENCH_API(16) void benchmark_eqrls_cccf_n32 EQRLS_CCCF_TRAIN_BENCH_API(32) void benchmark_eqrls_cccf_n64 EQRLS_CCCF_TRAIN_BENCH_API(64) liquid-dsp-1.7.0/src/equalization/src/000077500000000000000000000000001474751757600177045ustar00rootroot00000000000000liquid-dsp-1.7.0/src/equalization/src/eqlms.proto.c000066400000000000000000000362551474751757600223460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Least mean-squares (LMS) equalizer // #include #include #include #include //#define DEBUG struct EQLMS(_s) { unsigned int h_len; // filter length float mu; // LMS step size // internal matrices T * h0; // initial coefficients T * w0; // weights [px1] T * w1; // weights [px1] unsigned int count; // input sample count int buf_full; // input buffer full flag WINDOW() buffer; // input buffer wdelayf x2; // buffer of |x|^2 values float x2_sum; // sum{ |x|^2 } }; // update sum{|x|^2} int EQLMS(_update_sumsq)(EQLMS() _q, T _x); // create least mean-squares (LMS) equalizer object // _h : initial coefficients [size: _h_len x 1], default if NULL // _p : equalizer length (number of taps) EQLMS() EQLMS(_create)(T * _h, unsigned int _h_len) { EQLMS() q = (EQLMS()) malloc(sizeof(struct EQLMS(_s))); // set filter order, other params q->h_len = _h_len; q->mu = 0.5f; q->h0 = (T*) malloc((q->h_len)*sizeof(T)); q->w0 = (T*) malloc((q->h_len)*sizeof(T)); q->w1 = (T*) malloc((q->h_len)*sizeof(T)); q->buffer = WINDOW(_create)(q->h_len); q->x2 = wdelayf_create(q->h_len); // copy coefficients (if not NULL) unsigned int i; if (_h == NULL) { // initial coefficients with 1 at center for (i=0; ih_len; i++) q->h0[i] = (i==q->h_len/2) ? 1.0 : 0.0; } else { // copy user-defined initial coefficients for (i=0; ih_len; i++) q->h0[i] = conj(_h[q->h_len-i-1]); } // reset equalizer object EQLMS(_reset)(q); // return main object return q; } // create square-root Nyquist interpolator // _type : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples/symbol _k > 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 // _dt : fractional sample delay, 0 <= _dt < 1 EQLMS() EQLMS(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, float _dt) { // validate input if (_k < 2) return liquid_error_config("eqlms_%s_create_rnyquist(), samples/symbol must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("eqlms_%s_create_rnyquist(), filter delay must be greater than 0", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("eqlms_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); if (_dt < -1.0f || _dt > 1.0f) return liquid_error_config("eqlms_%s_create_rnyquist(), filter fractional sample delay must be in [-1,1]", EXTENSION_FULL); // generate square-root Nyquist filter unsigned int h_len = 2*_k*_m + 1; float h[h_len]; liquid_firdes_prototype(_type,_k,_m,_beta,_dt,h); // copy coefficients to type-specific array (e.g. float complex) // and scale by samples/symbol unsigned int i; T hc[h_len]; for (i=0; i 0.5f) return liquid_error_config("eqlms_%s_create_rnyquist(), filter cutoff must be in (0,0.5]", EXTENSION_FULL); // generate low-pass filter prototype float h[_h_len]; liquid_firdes_kaiser(_h_len, _fc, 40.0f, 0.0f, h); // copy coefficients to type-specific array (e.g. float complex), scaling by bandwidth unsigned int i; T hc[_h_len]; for (i=0; i<_h_len; i++) hc[i] = h[i] * 2 * _fc; // return equalizer object return EQLMS(_create)(hc, _h_len); } // create least mean-squares (LMS) equalizer object // _q : old equalization object // _h : initial coefficients [size: _h_len x 1], default if NULL // _p : equalizer length (number of taps) EQLMS() EQLMS(_recreate)(EQLMS() _q, T * _h, unsigned int _h_len) { // only destroy when length differs if (_q->h_len != _h_len) { EQLMS(_destroy)(_q); return EQLMS(_create)(_h,_h_len); } // filter is same length; copy user-defined initial coefficients unsigned int i; for (i=0; i<_q->h_len; i++) _q->h0[i] = conj(_h[_q->h_len-i-1]); // reset equalizer object and return EQLMS(_reset)(_q); return _q; } // copy object EQLMS() EQLMS(_copy)(EQLMS() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters EQLMS() q_copy = (EQLMS()) malloc(sizeof(struct EQLMS(_s))); memmove(q_copy, q_orig, sizeof(struct EQLMS(_s))); // create and copy buffers q_copy->h0 = (T*) malloc((q_copy->h_len)*sizeof(T)); q_copy->w0 = (T*) malloc((q_copy->h_len)*sizeof(T)); q_copy->w1 = (T*) malloc((q_copy->h_len)*sizeof(T)); memmove(q_copy->h0, q_orig->h0, q_copy->h_len*sizeof(T)); memmove(q_copy->w0, q_orig->w0, q_copy->h_len*sizeof(T)); memmove(q_copy->w1, q_orig->w1, q_copy->h_len*sizeof(T)); // copy window and buffer objects q_copy->buffer = WINDOW(_copy)(q_orig->buffer); q_copy->x2 = wdelayf_copy (q_orig->x2); return q_copy; } // destroy eqlms object int EQLMS(_destroy)(EQLMS() _q) { free(_q->h0); free(_q->w0); free(_q->w1); WINDOW(_destroy)(_q->buffer); wdelayf_destroy(_q->x2); free(_q); return LIQUID_OK; } // reset equalizer int EQLMS(_reset)(EQLMS() _q) { // copy default coefficients memmove(_q->w0, _q->h0, (_q->h_len)*sizeof(T)); WINDOW(_reset)(_q->buffer); wdelayf_reset(_q->x2); // reset input count _q->count = 0; _q->buf_full = 0; // reset squared magnitude sum _q->x2_sum = 0; return LIQUID_OK; } // print eqlms object internals int EQLMS(_print)(EQLMS() _q) { printf("\n", EXTENSION_FULL, _q->h_len, _q->mu); return LIQUID_OK; } // get learning rate of equalizer float EQLMS(_get_bw)(EQLMS() _q) { return _q->mu; } // set learning rate of equalizer // _q : equalizer object // _mu : LMS learning rate (should be near 0), 0 < _mu < 1 int EQLMS(_set_bw)(EQLMS() _q, float _mu) { if (_mu < 0.0f) return liquid_error(LIQUID_EICONFIG,"eqlms_%s_set_bw(), learning rate cannot be less than zero", EXTENSION_FULL); _q->mu = _mu; return LIQUID_OK; } // Get length of equalizer object (number of internal coefficients) unsigned int EQLMS(_get_length)(EQLMS() _q) { return _q->h_len; } // Get pointer to coefficients array const T * EQLMS(_get_coefficients)(EQLMS() _q) { return (const T*)(_q->w0); } // DEPRECATED: Get equalizer's internal coefficients void EQLMS(_get_weights)(EQLMS() _q, T * _w) { // copy output weight vector unsigned int i; for (i=0; i<_q->h_len; i++) _w[i] = conj(_q->w0[_q->h_len-i-1]); } // Copy internal coefficients to external buffer int EQLMS(_copy_coefficients)(EQLMS() _q, T * _w) { // copy output weight vector unsigned int i; for (i=0; i<_q->h_len; i++) _w[i] = conj(_q->w0[_q->h_len-i-1]); return LIQUID_OK; } // push sample into equalizer internal buffer // _q : equalizer object // _x : received sample int EQLMS(_push)(EQLMS() _q, T _x) { // push value into buffer WINDOW(_push)(_q->buffer, _x); // update sum{|x|^2} EQLMS(_update_sumsq)(_q, _x); // increment count _q->count++; return LIQUID_OK; } // push sample into equalizer internal buffer as block // _q : equalizer object // _x : input sample array // _n : input sample array length int EQLMS(_push_block)(EQLMS() _q, T * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) EQLMS(_push)(_q, _x[i]); return LIQUID_OK; } // execute internal dot product // _q : equalizer object // _y : output sample int EQLMS(_execute)(EQLMS() _q, T * _y) { T y = 0; // temporary accumulator T * r; // read buffer WINDOW(_read)(_q->buffer, &r); // compute conjugate vector dot product //DOTPROD(_run)(_q->w0, r, _q->h_len, &y); unsigned int i; for (i=0; i<_q->h_len; i++) { T sum = conj(_q->w0[i])*r[i]; y += sum; } // set output *_y = y; return LIQUID_OK; } // execute equalizer ase decimator // _q : equalizer object // _x : input sample array [size: _k x 1] // _y : output sample // _k : down-sampling rate int EQLMS(_decim_execute)(EQLMS() _q, T * _x, T * _y, unsigned int _k) { if (_k == 0) return liquid_error(LIQUID_EICONFIG,"eqlms_%s_decim_execute(), down-sampling rate 'k' must be greater than 0", EXTENSION_FULL); // push input sample and compute output EQLMS(_push)(_q, _x[0]); EQLMS(_execute)(_q, _y); // push remaining samples return EQLMS(_push_block)(_q, _x+1, _k-1); } // execute equalizer with block of samples using constant // modulus algorithm, operating on a decimation rate of _k // samples. // _q : equalizer object // _k : down-sampling rate // _x : input sample array [size: _n x 1] // _n : input sample array length // _y : output sample array [size: _n x 1] int EQLMS(_execute_block)(EQLMS() _q, unsigned int _k, T * _x, unsigned int _n, T * _y) { if (_k == 0) return liquid_error(LIQUID_EICONFIG,"eqlms_%s_execute_block(), down-sampling rate 'k' must be greater than 0", EXTENSION_FULL); unsigned int i; T d_hat; for (i=0; i<_n; i++) { // push input sample EQLMS(_push)(_q, _x[i]); // compute output sample EQLMS(_execute)(_q, &d_hat); // store result in output _y[i] = d_hat; // decimate by _k if ( ((_q->count+_k-1) % _k) == 0 ) { // update equalizer independent of the signal: estimate error // assuming constant modulus signal EQLMS(_step_blind)(_q, d_hat); } } return LIQUID_OK; } // step through one cycle of equalizer training // _q : equalizer object // _d : desired output // _d_hat : filtered output int EQLMS(_step)(EQLMS() _q, T _d, T _d_hat) { // check count; only run step when buffer is full if (!_q->buf_full) { if (_q->count < _q->h_len) return LIQUID_OK; else _q->buf_full = 1; } unsigned int i; // compute error (a priori) T alpha = _d - _d_hat; // read buffer T * r; // read buffer WINDOW(_read)(_q->buffer, &r); // update weighting vector // w[n+1] = w[n] + mu*conj(d-d_hat)*x[n]/(x[n]' * conj(x[n])) for (i=0; i<_q->h_len; i++) _q->w1[i] = _q->w0[i] + (_q->mu)*conj(alpha)*r[i]/_q->x2_sum; #ifdef DEBUG printf("w0: \n"); for (i=0; i<_q->h_len; i++) { PRINTVAL(_q->w0[i]); printf("\n"); } printf("w1: \n"); for (i=0; i<_q->h_len; i++) { PRINTVAL(_q->w1[i]); printf("\n"); } #endif // copy old values memmove(_q->w0, _q->w1, _q->h_len*sizeof(T)); return LIQUID_OK; } // step through one cycle of equalizer training // _q : equalizer object // _d_hat : filtered output int EQLMS(_step_blind)(EQLMS() _q, T _d_hat) { // update equalizer using constant modulus method #if T_COMPLEX T d = _d_hat / cabsf(_d_hat); #else T d = _d_hat > 0 ? 1 : -1; #endif return EQLMS(_step)(_q, d, _d_hat); } // DEPRECATED: train equalizer object on group of samples // _q : equalizer object // _w : initial weights / output weights // _x : received sample vector // _d : desired output vector // _n : vector length int EQLMS(_train)(EQLMS() _q, T * _w, T * _x, T * _d, unsigned int _n) { unsigned int p=_q->h_len; if (_n < _q->h_len) { return liquid_error(LIQUID_EICONFIG,"eqlms_%s_train(), traning sequence less than filter order", EXTENSION_FULL); } unsigned int i; // reset equalizer state EQLMS(_reset)(_q); // copy initial weights into buffer for (i=0; iw0[i] = _w[p - i - 1]; T d_hat; for (i=0; i<_n; i++) { // push sample into internal buffer EQLMS(_push)(_q, _x[i]); // execute vector dot product EQLMS(_execute)(_q, &d_hat); // step through training cycle EQLMS(_step)(_q, _d[i], d_hat); } // copy output weight vector EQLMS(_get_weights)(_q, _w); return LIQUID_OK; } // // internal methods // // update sum{|x|^2} int EQLMS(_update_sumsq)(EQLMS() _q, T _x) { // update estimate of signal magnitude squared // |x[n-1]|^2 (input sample) float x2_n = crealf(_x * conjf(_x)); // |x[0] |^2 (oldest sample) float x2_0; // push newest sample wdelayf_push(_q->x2, x2_n); // read oldest sample wdelayf_read(_q->x2, &x2_0); // update sum( |x|^2 ) of last 'n' input samples _q->x2_sum = _q->x2_sum + x2_n - x2_0; return LIQUID_OK; } liquid-dsp-1.7.0/src/equalization/src/eqrls.proto.c000066400000000000000000000264701474751757600223510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Recursive least-squares (RLS) equalizer #include #include #include //#define DEBUG struct EQRLS(_s) { unsigned int p; // filter order float lambda; // RLS forgetting factor float delta; // RLS initialization factor // internal matrices T * h0; // initial coefficients T * w0, * w1; // weights [px1] T * P0, * P1; // recursion matrix [pxp] T * g; // gain vector [px1] // temporary matrices T * xP0; // [1xp] T zeta; // constant T * gxl; // [pxp] T * gxlP0; // [pxp] unsigned int n; // input counter WINDOW() buffer; // input buffer }; // create recursive least-squares (RLS) equalizer object // _h : initial coefficients [size: _p x 1], default if NULL // _p : equalizer length (number of taps) EQRLS() EQRLS(_create)(T * _h, unsigned int _p) { if (_p==0) return liquid_error_config("eqrls_%s_create(), equalier length must be greater than 0",EXTENSION_FULL); EQRLS() q = (EQRLS()) malloc(sizeof(struct EQRLS(_s))); // set filter order, other parameters q->p = _p; // filter order q->lambda = 0.99f; // learning rate q->delta = 0.1f; // initialization factor // allocate memory for matrices q->h0 = (T*) malloc((q->p)*sizeof(T)); q->w0 = (T*) malloc((q->p)*sizeof(T)); q->w1 = (T*) malloc((q->p)*sizeof(T)); q->P0 = (T*) malloc((q->p)*(q->p)*sizeof(T)); q->P1 = (T*) malloc((q->p)*(q->p)*sizeof(T)); q->g = (T*) malloc((q->p)*sizeof(T)); q->xP0 = (T*) malloc((q->p)*sizeof(T)); q->gxl = (T*) malloc((q->p)*(q->p)*sizeof(T)); q->gxlP0 = (T*) malloc((q->p)*(q->p)*sizeof(T)); q->buffer = WINDOW(_create)(q->p); // copy coefficients (if not NULL) if (_h == NULL) { // initial coefficients with delta at first index unsigned int i; for (i=0; ip; i++) q->h0[i] = (i==q->p-1) ? 1.0 : 0.0; } else { // copy user-defined initial coefficients memmove(q->h0, _h, (q->p)*sizeof(T)); } // reset equalizer EQRLS(_reset)(q); // return object return q; } // re-create recursive least-squares (RLS) equalizer object // _q : old equalizer object // _h : filter coefficients (NULL for {1,0,0...}) // _p : equalizer length (number of taps) EQRLS() EQRLS(_recreate)(EQRLS() _q, T * _h, unsigned int _p) { if (_q->p == _p) { // length hasn't changed; copy default coefficients // and return object unsigned int i; for (i=0; i<_q->p; i++) _q->h0[i] = _h[i]; return _q; } // completely destroy old equalizer object EQRLS(_destroy)(_q); // create new one and return return EQRLS(_create)(_h,_p); } // copy object EQRLS() EQRLS(_copy)(EQRLS() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters EQRLS() q_copy = (EQRLS()) malloc(sizeof(struct EQRLS(_s))); memmove(q_copy, q_orig, sizeof(struct EQRLS(_s))); // allocate and copy memory from original unsigned int p = q_copy->p; // filter order (for convenience) q_copy->h0 = (T*) liquid_malloc_copy(q_orig->h0, p, sizeof(T)); q_copy->w0 = (T*) liquid_malloc_copy(q_orig->w0, p, sizeof(T)); q_copy->w1 = (T*) liquid_malloc_copy(q_orig->w1, p, sizeof(T)); q_copy->P0 = (T*) liquid_malloc_copy(q_orig->P0, p*p, sizeof(T)); q_copy->P1 = (T*) liquid_malloc_copy(q_orig->P1, p*p, sizeof(T)); q_copy->g = (T*) liquid_malloc_copy(q_orig->g, p, sizeof(T)); q_copy->xP0 = (T*) liquid_malloc_copy(q_orig->xP0, p, sizeof(T)); q_copy->gxl = (T*) liquid_malloc_copy(q_orig->gxl, p*p, sizeof(T)); q_copy->gxlP0 = (T*) liquid_malloc_copy(q_orig->gxlP0,p*p, sizeof(T)); // copy window and buffer objects q_copy->buffer = WINDOW(_copy)(q_orig->buffer); return q_copy; } // destroy eqrls object int EQRLS(_destroy)(EQRLS() _q) { // free vectors and matrices free(_q->h0); free(_q->w0); free(_q->w1); free(_q->P0); free(_q->P1); free(_q->g); free(_q->xP0); free(_q->gxl); free(_q->gxlP0); // destroy window buffer WINDOW(_destroy)(_q->buffer); // free main object memory free(_q); return LIQUID_OK; } // print eqrls object internals int EQRLS(_print)(EQRLS() _q) { printf("\n", EXTENSION_FULL, _q->p, _q->lambda, _q->delta); return LIQUID_OK; } // reset equalizer int EQRLS(_reset)(EQRLS() _q) { // reset input counter _q->n = 0; unsigned int i, j; // initialize... for (i=0; i<_q->p; i++) { for (j=0; j<_q->p; j++) { if (i==j) _q->P0[(_q->p)*i + j] = 1 / (_q->delta); else _q->P0[(_q->p)*i + j] = 0; } } // copy default coefficients memmove(_q->w0, _q->h0, (_q->p)*sizeof(T)); // clear window object WINDOW(_reset)(_q->buffer); return LIQUID_OK; } // get learning rate of equalizer float EQRLS(_get_bw)(EQRLS() _q) { return _q->lambda; } // set learning rate of equalizer // _q : equalizer object // _lambda : RLS learning rate (should be close to 1.0), 0 < _lambda < 1 int EQRLS(_set_bw)(EQRLS() _q, float _lambda) { if (_lambda < 0.0f || _lambda > 1.0f) return liquid_error(LIQUID_EICONFIG,"eqrls_%s_set_bw(), learning rate must be in (0,1)", EXTENSION_FULL); // set internal value _q->lambda = _lambda; return LIQUID_OK; } // push sample into equalizer internal buffer // _q : equalizer object // _x : received sample int EQRLS(_push)(EQRLS() _q, T _x) { // push value into buffer WINDOW(_push)(_q->buffer, _x); return LIQUID_OK; } // execute internal dot product // _q : equalizer object // _y : output sample int EQRLS(_execute)(EQRLS() _q, T * _y) { // compute vector dot product T * r; // read buffer WINDOW(_read)(_q->buffer, &r); DOTPROD(_run)(_q->w0, r, _q->p, _y); return LIQUID_OK; } // execute cycle of equalizer, filtering output // _q : equalizer object // _x : received sample // _d : desired output // _d_hat : filtered output int EQRLS(_step)(EQRLS() _q, T _d, T _d_hat) { unsigned int i,r,c; unsigned int p=_q->p; // compute error (a priori) T alpha = _d - _d_hat; // read buffer T * x; WINDOW(_read)(_q->buffer, &x); // compute gain vector for (c=0; cxP0[c] = 0; for (r=0; rxP0[c] += x[r] * matrix_access(_q->P0,p,p,r,c); } } #ifdef DEBUG printf("x: "); for (i=0; ixP0[c]); printf("\n"); #endif // zeta = lambda + [x.']*[P0]*[conj(x)] _q->zeta = 0; for (c=0; cxP0[c] * conj(x[c]); _q->zeta += sum; } _q->zeta += _q->lambda; #ifdef DEBUG printf("zeta : "); PRINTVAL(_q->zeta); printf("\n"); #endif for (r=0; rg[r] = 0; for (c=0; cP0,p,p,r,c) * conj(x[c]); _q->g[r] += sum; } _q->g[r] /= _q->zeta; } #ifdef DEBUG printf("g: "); for (i=0; ig[i]); //printf("%6.3f ", _q->g[i]); printf("\n"); #endif // update recursion matrix for (r=0; rgxl,p,p,r,c) = _q->g[r] * x[c] / _q->lambda; } } // multiply two [pxp] matrices: gxlP0 = gxl * P0 MATRIX(_mul)(_q->gxl, p,p, _q->P0, p,p, _q->gxlP0,p,p); for (i=0; iP1[i] = _q->P0[i] / _q->lambda - _q->gxlP0[i]; // update weighting vector for (i=0; iw1[i] = _q->w0[i] + alpha*(_q->g[i]); #ifdef DEBUG printf("w0: \n"); for (i=0; iw0[i]); printf("\n"); } printf("w1: \n"); for (i=0; iw1[i]); printf("\n"); EQRLS(_print)(_q); } #endif // copy old values memmove(_q->w0, _q->w1, p*sizeof(T)); memmove(_q->P0, _q->P1, p*p*sizeof(T)); return LIQUID_OK; } // retrieve internal filter coefficients // _q : equalizer object // _w : weights [size: _p x 1] int EQRLS(_get_weights)(EQRLS() _q, T * _w) { // copy output weight vector, reversing order unsigned int i; for (i=0; i<_q->p; i++) _w[i] = _q->w1[_q->p-i-1]; return LIQUID_OK; } // train equalizer object // _q : equalizer object // _w : initial weights / output weights // _x : received sample vector // _d : desired output vector // _n : vector length int EQRLS(_train)(EQRLS() _q, T * _w, T * _x, T * _d, unsigned int _n) { unsigned int i; if (_n < _q->p) return liquid_error(LIQUID_EIVAL,"eqrls_%s_train(), traning sequence less than filter order",EXTENSION_FULL); // reset equalizer state EQRLS(_reset)(_q); // copy initial weights into buffer for (i=0; i<_q->p; i++) _q->w0[i] = _w[_q->p - i - 1]; T d_hat; for (i=0; i<_n; i++) { // push sample into internal buffer EQRLS(_push)(_q, _x[i]); // execute vector dot product EQRLS(_execute)(_q, &d_hat); // step through training cycle EQRLS(_step)(_q, _d[i], d_hat); } // copy output weight vector return EQRLS(_get_weights)(_q, _w); } liquid-dsp-1.7.0/src/equalization/src/equalizer_cccf.c000066400000000000000000000033671474751757600230400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point equalizers // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "cccf" #define EQLMS(name) LIQUID_CONCAT(eqlms_cccf,name) #define EQRLS(name) LIQUID_CONCAT(eqrls_cccf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define MATRIX(name) LIQUID_CONCAT(matrixcf,name) #define T_COMPLEX 1 #define T float complex #define PRINTVAL(V) printf("%5.2f+j%5.2f ", crealf(V), cimagf(V)); // prototypes #include "eqlms.proto.c" #include "eqrls.proto.c" liquid-dsp-1.7.0/src/equalization/src/equalizer_rrrf.c000066400000000000000000000033231474751757600231050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point equalizers // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "rrrf" #define EQLMS(name) LIQUID_CONCAT(eqlms_rrrf,name) #define EQRLS(name) LIQUID_CONCAT(eqrls_rrrf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define WINDOW(name) LIQUID_CONCAT(windowf,name) #define MATRIX(name) LIQUID_CONCAT(matrixf,name) #define T_COMPLEX 0 #define T float #define PRINTVAL(V) printf("%5.2f ", V); // prototypes #include "eqlms.proto.c" #include "eqrls.proto.c" liquid-dsp-1.7.0/src/equalization/tests/000077500000000000000000000000001474751757600202575ustar00rootroot00000000000000liquid-dsp-1.7.0/src/equalization/tests/eqlms_cccf_autotest.c000066400000000000000000000224561474751757600244630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // static channel filter, run equalization with various update strategies on modulated data void testbench_eqlms(unsigned int k, unsigned int m, float beta, int init, unsigned int p, float mu, unsigned int num_symbols, int update, int ms) { //float tol = 0.025f; // error tolerance unsigned int i; modemcf mod = modemcf_create(ms); firinterp_crcf interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,k,m,beta,0); // create fixed channel filter float complex h[5] = { 1.00f + 0.00f*_Complex_I, 0.00f + -0.01f*_Complex_I, -0.11f + 0.02f*_Complex_I, 0.02f + 0.01f*_Complex_I, -0.09f + -0.04f*_Complex_I }; firfilt_cccf fchannel = firfilt_cccf_create(h,5); // prototype low-pass filter float complex hp[2*k*p+1]; for (i=0; i<2*k*p+1; i++) hp[i] = sincf( (float)i/(float)k - p) * liquid_hamming(i,2*k*p+1) / k; // create and initialize equalizer eqlms_cccf eq; switch (init) { case 0: eq = eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER,k,p,beta,0); break; case 1: eq = eqlms_cccf_create_lowpass (2*k*p+1, 0.5f/(float)k); break; case 2: eq = eqlms_cccf_create (hp, 2*k*p+1); break; // external coefficients default:eq = eqlms_cccf_create (NULL, 2*k*p+1); break; // NULL puts 1 at center } eqlms_cccf_set_bw(eq, mu); // run equalization float complex buf[k]; // sample buffer float complex sym_in, sym_out; // modulated/recovered symbols wdelaycf buf_sym = wdelaycf_create(m+p);// symbol buffer to account for filter delays float rmse = 0.0f; // root mean-squared error for (i=0; i<2*num_symbols; i++) { // generate modulated input symbol unsigned int sym = modemcf_gen_rand_sym(mod); modemcf_modulate(mod, sym, &sym_in); wdelaycf_push(buf_sym, sym_in); // interpolate firinterp_crcf_execute(interp, sym_in, buf); // apply channel filter (in place) firfilt_cccf_execute_block(fchannel, buf, k, buf); // run through equalizing filter as decimator eqlms_cccf_decim_execute(eq, buf, &sym_out, k); // skip first m+p symbols if (i < m + p) continue; // read input symbol, delayed by m+p symbols wdelaycf_read(buf_sym, &sym_in); // update equalizer weights if (i < num_symbols) { float complex d_hat; unsigned int index; switch (update) { case 0: eqlms_cccf_step(eq, sym_in, sym_out); break; // perfect knowledge case 1: eqlms_cccf_step_blind(eq, sym_out); break; // CM case 2: // decision-directed modemcf_demodulate(mod, sym_out, &index); modemcf_get_demodulator_sample(mod, &d_hat); eqlms_cccf_step(eq, d_hat, sym_out); break; default:; } continue; } // observe error float error = cabsf(sym_in-sym_out); rmse += error * error; #if 0 if (liquid_autotest_verbose) { printf("%3u : x = {%12.8f,%12.8f}, y = {%12.8f,%12.8f}, error=%12.8f %s\n", i, crealf(sym_in ), cimagf(sym_in ), crealf(sym_out), cimagf(sym_out), error, error > tol ? "*" : ""); } //CONTEND_DELTA(error, 0.0f, tol); #endif } rmse = 10*log10f( rmse/num_symbols ); printf("rmse : %.3f dB\n", rmse); CONTEND_LESS_THAN(rmse, -20.0f); // clean up objects wdelaycf_destroy(buf_sym); firfilt_cccf_destroy(fchannel); firinterp_crcf_destroy(interp); eqlms_cccf_destroy(eq); modemcf_destroy(mod); } // test different update strategies: k,m,beta,init,p, mu, n,update,mod scheme void autotest_eqlms_00() { testbench_eqlms(2,7, 0.3, 0,7,0.3,800, 0,LIQUID_MODEM_QPSK); } void autotest_eqlms_01() { testbench_eqlms(2,7, 0.3, 0,7,0.3,800, 1,LIQUID_MODEM_QPSK); } void autotest_eqlms_02() { testbench_eqlms(2,7, 0.3, 0,7,0.3,800, 2,LIQUID_MODEM_QPSK); } // test different initialization methods: k,m,beta,init,p, mu, n,update,mod scheme void autotest_eqlms_03() { testbench_eqlms(2,7, 0.3, 0,7,0.3,800, 0,LIQUID_MODEM_QAM16); } void autotest_eqlms_04() { testbench_eqlms(2,7, 0.3, 1,7,0.3,800, 0,LIQUID_MODEM_QAM16); } void autotest_eqlms_05() { testbench_eqlms(2,7, 0.3, 2,7,0.3,800, 0,LIQUID_MODEM_QAM16); } void autotest_eqlms_06() { testbench_eqlms(2,7, 0.3, 3,6,0.3,800, 0,LIQUID_MODEM_QAM16); } // test different configurations: k,m,beta,init,p, mu, n,update,mod scheme void autotest_eqlms_07() { testbench_eqlms(2,9, 0.3, 0,7,0.3,800, 0,LIQUID_MODEM_QPSK); } void autotest_eqlms_08() { testbench_eqlms(2,7, 0.2, 0,9,0.3,800, 0,LIQUID_MODEM_QPSK); } void autotest_eqlms_09() { testbench_eqlms(2,7, 0.3, 0,3,0.3,800, 0,LIQUID_MODEM_QPSK); } void autotest_eqlms_10() { testbench_eqlms(2,7, 0.3, 0,7,0.5,800, 0,LIQUID_MODEM_ARB64VT); } void autotest_eqlms_11() { testbench_eqlms(2,7, 0.3, 0,7,0.1,800, 0,LIQUID_MODEM_QPSK); } //void xautotest_eqlms_12() { testbench_eqlms(4,7, 0.3, 0,7,0.7,800, 0,LIQUID_MODEM_QPSK); } void autotest_eqlms_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping eqlms config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check that object returns NULL for invalid configurations CONTEND_ISNULL(eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, 0, 12, 0.3f, 0.0f)); CONTEND_ISNULL(eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, 2, 0, 0.3f, 0.0f)); CONTEND_ISNULL(eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, 2, 12, 2.0f, 0.0f)); CONTEND_ISNULL(eqlms_cccf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, 2, 12, 0.3f,-2.0f)); CONTEND_ISNULL(eqlms_cccf_create_lowpass( 0, 0.1f)); CONTEND_ISNULL(eqlms_cccf_create_lowpass(13,-0.1f)); // create proper object and test other interfaces unsigned int i, k=2, m=3, h_len = 2*k*m+1; eqlms_cccf q = eqlms_cccf_create(NULL, h_len); CONTEND_EQUALITY(LIQUID_OK, eqlms_cccf_print(q)); // test getting/setting properties CONTEND_EQUALITY(eqlms_cccf_get_length(q), h_len); float mu = 0.1f; eqlms_cccf_set_bw(q, mu); CONTEND_EQUALITY(eqlms_cccf_get_bw(q), mu); CONTEND_INEQUALITY(LIQUID_OK, eqlms_cccf_set_bw(q, -1)); // other configurations CONTEND_INEQUALITY(LIQUID_OK, eqlms_cccf_decim_execute(q, NULL, NULL, 0)); // test getting weights float complex h[h_len]; eqlms_cccf_copy_coefficients(q, h); for (i=0; i #include #include #include #include "liquid.internal.h" #define CRC_BENCH_API(CRC,N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { crc_bench(_start, _finish, _num_iterations, CRC, N); } // Helper function to keep code base small void crc_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, crc_scheme _crc, unsigned int _n) { // normalize number of iterations if (_crc != LIQUID_CRC_CHECKSUM) *_num_iterations /= 100; if (*_num_iterations < 1) *_num_iterations = 1; unsigned long int i; // create arrays unsigned char msg[_n]; unsigned int key = 0; // initialize message for (i=0; i<_n; i++) msg[i] = rand() & 0xff; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { key ^= crc_generate_key(_crc, msg, _n); key ^= crc_generate_key(_crc, msg, _n); key ^= crc_generate_key(_crc, msg, _n); key ^= crc_generate_key(_crc, msg, _n); // randomize input msg[0] ^= key & 0xff; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } // // BENCHMARKS // void benchmark_crc_checksum_n256 CRC_BENCH_API(LIQUID_CRC_CHECKSUM, 256) void benchmark_crc_crc8_n256 CRC_BENCH_API(LIQUID_CRC_8, 256) void benchmark_crc_crc16_n256 CRC_BENCH_API(LIQUID_CRC_16, 256) void benchmark_crc_crc24_n256 CRC_BENCH_API(LIQUID_CRC_24, 256) void benchmark_crc_crc32_n256 CRC_BENCH_API(LIQUID_CRC_32, 256) liquid-dsp-1.7.0/src/fec/bench/fec_decode_benchmark.c000066400000000000000000000172231474751757600224470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" #define FEC_DECODE_BENCH_API(FS,N, OPT) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { fec_decode_bench(_start, _finish, _num_iterations, FS, N, OPT); } // Helper function to keep code base small void fec_decode_bench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED if ( _fs == LIQUID_FEC_CONV_V27 || _fs == LIQUID_FEC_CONV_V29 || _fs == LIQUID_FEC_CONV_V39 || _fs == LIQUID_FEC_CONV_V615 || _fs == LIQUID_FEC_CONV_V27P23 || _fs == LIQUID_FEC_CONV_V27P34 || _fs == LIQUID_FEC_CONV_V27P45 || _fs == LIQUID_FEC_CONV_V27P56 || _fs == LIQUID_FEC_CONV_V27P67 || _fs == LIQUID_FEC_CONV_V27P78 || _fs == LIQUID_FEC_CONV_V29P23 || _fs == LIQUID_FEC_CONV_V29P34 || _fs == LIQUID_FEC_CONV_V29P45 || _fs == LIQUID_FEC_CONV_V29P56 || _fs == LIQUID_FEC_CONV_V29P67 || _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; } #endif // normalize number of iterations *_num_iterations /= _n; switch (_fs) { case LIQUID_FEC_NONE: *_num_iterations *= 500; break; case LIQUID_FEC_REP3: *_num_iterations *= 200; break; case LIQUID_FEC_REP5: *_num_iterations *= 100; break; case LIQUID_FEC_HAMMING74: *_num_iterations *= 10; break; case LIQUID_FEC_HAMMING84: *_num_iterations *= 10; break; case LIQUID_FEC_HAMMING128: *_num_iterations *= 10; break; case LIQUID_FEC_SECDED2216: *_num_iterations *= 10; break; case LIQUID_FEC_SECDED3932: *_num_iterations *= 10; break; case LIQUID_FEC_SECDED7264: *_num_iterations *= 10; break; case LIQUID_FEC_GOLAY2412: *_num_iterations *= 2; break; case LIQUID_FEC_CONV_V27: *_num_iterations /= 5; break; case LIQUID_FEC_CONV_V29: *_num_iterations /= 10; break; case LIQUID_FEC_CONV_V39: *_num_iterations /= 100; break; case LIQUID_FEC_CONV_V615: *_num_iterations /= 200; break; case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: *_num_iterations /= 20; break; case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: *_num_iterations /= 50; break; case LIQUID_FEC_RS_M8: *_num_iterations *= 1; break; default:; } if (*_num_iterations < 1) *_num_iterations = 1; // generate fec object fec q = fec_create(_fs,_opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,_n); unsigned char msg[_n]; // original message unsigned char msg_enc[n_enc]; // decoded message unsigned char msg_dec[_n]; // decoded message // initialize message unsigned long int i; for (i=0; i<_n; i++) msg[i] = rand() & 0xff; // encode message fec_encode(q,_n,msg,msg_enc); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fec_decode(q,_n,msg_enc,msg_dec); fec_decode(q,_n,msg_enc,msg_dec); fec_decode(q,_n,msg_enc,msg_dec); fec_decode(q,_n,msg_enc,msg_dec); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // clean up objects fec_destroy(q); } // // BENCHMARKS // void benchmark_fec_dec_none_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_NONE, 64, NULL) void benchmark_fec_dec_rep3_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_REP3, 64, NULL) void benchmark_fec_dec_rep5_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_REP5, 64, NULL) void benchmark_fec_dec_hamming74_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_HAMMING74, 64, NULL) void benchmark_fec_dec_hamming84_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_HAMMING84, 64, NULL) void benchmark_fec_dec_hamming128_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_HAMMING128,64, NULL) // SEC-DED block codes void benchmark_fec_dec_secded2216_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_SECDED2216,64, NULL) void benchmark_fec_dec_secded3932_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_SECDED3932,64, NULL) void benchmark_fec_dec_secded7264_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_SECDED7264,64, NULL) void benchmark_fec_dec_golay2412_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_GOLAY2412, 64, NULL) void benchmark_fec_dec_conv27_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27, 64, NULL) void benchmark_fec_dec_conv29_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29, 64, NULL) void benchmark_fec_dec_conv39_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V39, 64, NULL) void benchmark_fec_dec_conv615_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V615, 64, NULL) void benchmark_fec_dec_conv27p23_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P23,64, NULL) void benchmark_fec_dec_conv27p34_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P34,64, NULL) void benchmark_fec_dec_conv27p45_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P45,64, NULL) void benchmark_fec_dec_conv27p56_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P56,64, NULL) void benchmark_fec_dec_conv27p67_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P67,64, NULL) void benchmark_fec_dec_conv27p78_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V27P78,64, NULL) void benchmark_fec_dec_conv29p23_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P23,64, NULL) void benchmark_fec_dec_conv29p34_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P34,64, NULL) void benchmark_fec_dec_conv29p45_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P45,64, NULL) void benchmark_fec_dec_conv29p56_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P56,64, NULL) void benchmark_fec_dec_conv29p67_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P67,64, NULL) void benchmark_fec_dec_conv29p78_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_CONV_V29P78,64, NULL) void benchmark_fec_dec_rs8_n64 FEC_DECODE_BENCH_API(LIQUID_FEC_RS_M8, 64, NULL) liquid-dsp-1.7.0/src/fec/bench/fec_encode_benchmark.c000066400000000000000000000147171474751757600224660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" #define FEC_ENCODE_BENCH_API(FS,N, OPT) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { fec_encode_bench(_start, _finish, _num_iterations, FS, N, OPT); } // Helper function to keep code base small void fec_encode_bench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED if ( _fs == LIQUID_FEC_CONV_V27 || _fs == LIQUID_FEC_CONV_V29 || _fs == LIQUID_FEC_CONV_V39 || _fs == LIQUID_FEC_CONV_V615 || _fs == LIQUID_FEC_CONV_V27P23 || _fs == LIQUID_FEC_CONV_V27P34 || _fs == LIQUID_FEC_CONV_V27P45 || _fs == LIQUID_FEC_CONV_V27P56 || _fs == LIQUID_FEC_CONV_V27P67 || _fs == LIQUID_FEC_CONV_V27P78 || _fs == LIQUID_FEC_CONV_V29P23 || _fs == LIQUID_FEC_CONV_V29P34 || _fs == LIQUID_FEC_CONV_V29P45 || _fs == LIQUID_FEC_CONV_V29P56 || _fs == LIQUID_FEC_CONV_V29P67 || _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; } #endif // normalize number of iterations *_num_iterations /= _n; switch (_fs) { case LIQUID_FEC_NONE: *_num_iterations *= 500; break; case LIQUID_FEC_REP3: *_num_iterations *= 200; break; case LIQUID_FEC_REP5: *_num_iterations *= 100; break; case LIQUID_FEC_HAMMING74: *_num_iterations *= 30; break; case LIQUID_FEC_HAMMING84: *_num_iterations *= 100; break; case LIQUID_FEC_HAMMING128: *_num_iterations *= 100; break; case LIQUID_FEC_SECDED2216: *_num_iterations *= 10; break; case LIQUID_FEC_SECDED3932: *_num_iterations *= 10; break; case LIQUID_FEC_SECDED7264: *_num_iterations *= 10; break; case LIQUID_FEC_GOLAY2412: *_num_iterations *= 2; break; case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: case LIQUID_FEC_RS_M8: *_num_iterations *= 1; break; default:; } if (*_num_iterations < 1) *_num_iterations = 1; // generate fec object fec q = fec_create(_fs,_opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,_n); unsigned char msg[_n]; // original message unsigned char msg_enc[n_enc]; // encoded message // initialize message unsigned long int i; for (i=0; i<_n; i++) { msg[i] = rand() & 0xff; } // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fec_encode(q,_n,msg,msg_enc); fec_encode(q,_n,msg,msg_enc); fec_encode(q,_n,msg,msg_enc); fec_encode(q,_n,msg,msg_enc); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // clean up objects fec_destroy(q); } // // BENCHMARKS // void benchmark_fec_enc_none_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_NONE, 64, NULL) void benchmark_fec_enc_rep3_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_REP3, 64, NULL) void benchmark_fec_enc_rep5_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_REP5, 64, NULL) void benchmark_fec_enc_hamming74_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_HAMMING74, 64, NULL) void benchmark_fec_enc_hamming84_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_HAMMING84, 64, NULL) void benchmark_fec_enc_hamming128_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_HAMMING128,64, NULL) // SEC-DED block codes void benchmark_fec_enc_secded2216_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_SECDED2216,64, NULL) void benchmark_fec_enc_secded3932_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_SECDED3932,64, NULL) void benchmark_fec_enc_secded7264_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_SECDED7264,64, NULL) void benchmark_fec_enc_golay2412_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_GOLAY2412, 64, NULL) void benchmark_fec_enc_conv27_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V27, 64, NULL) void benchmark_fec_enc_conv29_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V29, 64, NULL) void benchmark_fec_enc_conv39_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V39, 64, NULL) void benchmark_fec_enc_conv615_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V615, 64, NULL) void benchmark_fec_enc_conv27p23_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V27P23,64, NULL) void benchmark_fec_enc_conv27p34_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V27P34,64, NULL) void benchmark_fec_enc_conv27p45_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_CONV_V27P45,64, NULL) void benchmark_fec_enc_rs8_n64 FEC_ENCODE_BENCH_API(LIQUID_FEC_RS_M8, 64, NULL) liquid-dsp-1.7.0/src/fec/bench/fecsoft_decode_benchmark.c000066400000000000000000000174661474751757600233540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fecsoft_decode_benchmark.h // // Test soft decoding speeds of certain FEC codecs // #include #include #include #include #include "liquid.internal.h" #define FECSOFT_DECODE_BENCH_API(FS,N, OPT) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { fecsoft_decode_bench(_start, _finish, _num_iterations, FS, N, OPT); } // Helper function to keep code base small void fecsoft_decode_bench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED if ( _fs == LIQUID_FEC_CONV_V27 || _fs == LIQUID_FEC_CONV_V29 || _fs == LIQUID_FEC_CONV_V39 || _fs == LIQUID_FEC_CONV_V615 || _fs == LIQUID_FEC_CONV_V27P23 || _fs == LIQUID_FEC_CONV_V27P34 || _fs == LIQUID_FEC_CONV_V27P45 || _fs == LIQUID_FEC_CONV_V27P56 || _fs == LIQUID_FEC_CONV_V27P67 || _fs == LIQUID_FEC_CONV_V27P78 || _fs == LIQUID_FEC_CONV_V29P23 || _fs == LIQUID_FEC_CONV_V29P34 || _fs == LIQUID_FEC_CONV_V29P45 || _fs == LIQUID_FEC_CONV_V29P56 || _fs == LIQUID_FEC_CONV_V29P67 || _fs == LIQUID_FEC_CONV_V29P78 || _fs == LIQUID_FEC_RS_M8) { liquid_error(LIQUID_EUMODE,"convolutional, Reed-Solomon codes unavailable (install libfec)"); getrusage(RUSAGE_SELF, _start); memmove((void*)_finish,(void*)_start,sizeof(struct rusage)); return; } #endif // normalize number of iterations *_num_iterations /= _n; switch (_fs) { case LIQUID_FEC_NONE: *_num_iterations *= 50; break; case LIQUID_FEC_REP3: *_num_iterations *= 20; break; case LIQUID_FEC_REP5: *_num_iterations *= 10; break; case LIQUID_FEC_HAMMING74: *_num_iterations *= 1; break; case LIQUID_FEC_HAMMING84: *_num_iterations *= 1; break; case LIQUID_FEC_HAMMING128: *_num_iterations *= 1; break; case LIQUID_FEC_CONV_V27: *_num_iterations /= 5; break; case LIQUID_FEC_CONV_V29: *_num_iterations /= 50; break; case LIQUID_FEC_CONV_V39: *_num_iterations /= 50; break; case LIQUID_FEC_CONV_V615: *_num_iterations /= 800; break; case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: *_num_iterations /= 5; break; case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: *_num_iterations /= 50; break; case LIQUID_FEC_RS_M8: *_num_iterations *= 1; break; default:; } if (*_num_iterations < 1) *_num_iterations = 1; // generate fec object fec q = fec_create(_fs,_opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,_n); unsigned char msg[_n]; // original message unsigned char msg_enc[n_enc]; // encoded message unsigned char msg_soft[8*n_enc];// encoded message (soft bits) unsigned char msg_dec[_n]; // decoded message // initialize message unsigned long int i; for (i=0; i<_n; i++) msg[i] = rand() & 0xff; // encode message fec_encode(q,_n,msg,msg_enc); // expand to soft bits for (i=0; i #include #include #include "liquid.h" #define INTERLEAVER_BENCH_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { interleaver_bench(_start, _finish, _num_iterations, N); } // Helper function to keep code base small void interleaver_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // scale number of iterations by block size // iterations = 4: cycles/trial ~ exp( -0.883 + 0.708*log(_n) ) *_num_iterations /= 0.7f*expf( -0.883 + 0.708*logf(_n) ); // initialize interleaver interleaver q = interleaver_create(_n); interleaver_set_depth(q, 4); unsigned char x[_n]; unsigned char y[_n]; unsigned long int i; for (i=0; i<_n; i++) x[i] = rand() & 0xff; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { interleaver_encode(q, x, y); interleaver_encode(q, x, y); interleaver_encode(q, x, y); interleaver_encode(q, x, y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy interleaver object interleaver_destroy(q); } void benchmark_interleaver_8 INTERLEAVER_BENCH_API(8 ) void benchmark_interleaver_16 INTERLEAVER_BENCH_API(16 ) void benchmark_interleaver_32 INTERLEAVER_BENCH_API(32 ) void benchmark_interleaver_64 INTERLEAVER_BENCH_API(64 ) void benchmark_interleaver_128 INTERLEAVER_BENCH_API(128 ) void benchmark_interleaver_256 INTERLEAVER_BENCH_API(256 ) void benchmark_interleaver_512 INTERLEAVER_BENCH_API(512 ) void benchmark_interleaver_1024 INTERLEAVER_BENCH_API(1024 ) liquid-dsp-1.7.0/src/fec/bench/packetizer_decode_benchmark.c000066400000000000000000000100661474751757600240510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "liquid.internal.h" #define PACKETIZER_DECODE_BENCH_API(N, CRC, FEC0, FEC1) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { packetizer_decode_bench(_start, _finish, _num_iterations, N, CRC, FEC0, FEC1); } // Helper function to keep code base small void packetizer_decode_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n, crc_scheme _crc, fec_scheme _fec0, fec_scheme _fec1) { // unsigned int msg_dec_len = _n; unsigned int msg_enc_len = packetizer_compute_enc_msg_len(_n,_crc,_fec0,_fec1); // adjust number of iterations // k-cycles/trial ~ 221 + 1.6125*msg_dec_len; // TODO: adjust iterations based on encoder types *_num_iterations *= 1000; *_num_iterations /= 221 + 1.6125*msg_dec_len; unsigned char msg_rec[msg_enc_len]; unsigned char msg_dec[msg_dec_len]; // initialize data unsigned long int i; for (i=0; i #include #include #include #include #include "liquid.internal.h" #define SUMPRODUCT_BENCH_API(M) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { sumproduct_bench(_start, _finish, _num_iterations, M); } // generate half-rate LDPC generator and parity-check matrices void sumproduct_generate(unsigned int _m, unsigned char * _G, unsigned char * _H); // Helper function to keep code base small void sumproduct_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _m) { // normalize number of iterations // seconds/trial ~ exp{ -16.90 + 2.8815*log(_m) } float scale = expf(-17.42f + 2.9971*logf(_m)); *_num_iterations *= 1e-7 / scale; if (*_num_iterations < 1) *_num_iterations = 1; unsigned long int i; // derived values unsigned int _n = 2*_m; // create arrays unsigned char Gs[_m*_n]; // generator matrix [m x n] unsigned char Hs[_m*_n]; // parity check matrix [m x n] sumproduct_generate(_m, Gs, Hs); // generate sparse binary matrices smatrixb G = smatrixb_create_array(Gs, _n, _m); smatrixb H = smatrixb_create_array(Hs, _m, _n); // print matrices //printf("G:\n"); smatrixb_print_expanded(G); //printf("H:\n"); smatrixb_print_expanded(H); unsigned char x[_m]; // original message signal unsigned char c[_n]; // transmitted codeword float LLR[_n]; // log-likelihood ratio unsigned char c_hat[_n]; // estimated codeword // initialize message array for (i=0; i<_m; i++) x[i] = rand() % 2; // compute encoded message smatrixb_vmul(G, x, c); // print status //printf("x = ["); for (i=0; i<_m; i++) printf("%2u", x[i]); printf(" ];\n"); //printf("c = ["); for (i=0; i<_n; i++) printf("%2u", c[i]); printf(" ];\n"); // compute log-likelihood ratio (LLR) for (i=0; i<_n; i++) LLR[i] = (c[i] == 0 ? 1.0f : -1.0f) + 0.5*randnf(); // start trials getrusage(RUSAGE_SELF, _start); int parity_pass; for (i=0; i<(*_num_iterations); i++) { parity_pass = fec_sumproduct(_m, _n, H, LLR, c_hat, 1); LLR[i%_m] += parity_pass ? 1 : -1; parity_pass = fec_sumproduct(_m, _n, H, LLR, c_hat, 1); LLR[i%_m] += parity_pass ? 1 : -1; parity_pass = fec_sumproduct(_m, _n, H, LLR, c_hat, 1); LLR[i%_m] += parity_pass ? 1 : -1; parity_pass = fec_sumproduct(_m, _n, H, LLR, c_hat, 1); LLR[i%_m] += parity_pass ? 1 : -1; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } // // BENCHMARKS // void benchmark_sumproduct_m16 SUMPRODUCT_BENCH_API(16) void benchmark_sumproduct_m32 SUMPRODUCT_BENCH_API(32) void benchmark_sumproduct_m64 SUMPRODUCT_BENCH_API(64) void benchmark_sumproduct_m128 SUMPRODUCT_BENCH_API(128) // generate half-rate LDPC generator and parity-check matrices void sumproduct_generate(unsigned int _m, unsigned char * _G, unsigned char * _H) { unsigned int i; unsigned int j; // derived values unsigned int _n = 2*_m; // initial generator polynomial [1 x m] unsigned char p[_m]; // initialize generator polynomial (systematic) for (i=0; i<_m; i++) p[i] = 0; unsigned int t = 0; unsigned int k = 2; for (i=0; i<_m; i++) { t++; if (t == k) { t = 0; k *= 2; p[i] = 1; } } // initialize matrices for (i=0; i<_m; i++) { for (j=0; j<_m; j++) { // G = [I(m) P]^T _G[j*_m + i] = (i==j) ? 1 : 0; _G[j*_m + i + _m*_m] = p[(i+j)%_m]; // H = [P^T I(m)] _H[i*_n + j + _m] = (i==j) ? 1 : 0; _H[i*_n + j] = p[(i+j)%_m]; } } } liquid-dsp-1.7.0/src/fec/src/000077500000000000000000000000001474751757600157345ustar00rootroot00000000000000liquid-dsp-1.7.0/src/fec/src/c_ones_mod2.c000066400000000000000000000037251474751757600202760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // // unsigned char c_ones_mod2[] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; liquid-dsp-1.7.0/src/fec/src/crc.c000066400000000000000000000255361474751757600166620ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // cyclic redundancy check (and family) // #include #include #include #include "liquid.internal.h" #define CRC8_POLY 0x07 #define CRC16_POLY 0x8005 #define CRC24_POLY 0x5D6DCB #define CRC32_POLY 0x04C11DB7 unsigned int checksum_generate_key(unsigned char * _msg, unsigned int _msg_len); unsigned int crc8_generate_key(unsigned char * _msg, unsigned int _msg_len); unsigned int crc16_generate_key(unsigned char * _msg, unsigned int _msg_len); unsigned int crc24_generate_key(unsigned char * _msg, unsigned int _msg_len); unsigned int crc32_generate_key(unsigned char * _msg, unsigned int _msg_len); // object-independent methods const char * crc_scheme_str[LIQUID_CRC_NUM_SCHEMES][2] = { // short name, long name {"unknown", "unknown"}, {"none", "none"}, {"checksum", "checksum (8-bit)"}, {"crc8", "CRC (8-bit)"}, {"crc16", "CRC (16-bit)"}, {"crc24", "CRC (24-bit)"}, {"crc32", "CRC (32-bit)"} }; // Print compact list of existing and available crc schemes int liquid_print_crc_schemes() { unsigned int i; unsigned int len = 10; // print all available CRC schemes printf(" "); for (i=0; i 48 && i != LIQUID_CRC_NUM_SCHEMES-1) { len = 10; printf("\n "); } } printf("\n"); return LIQUID_OK; } crc_scheme liquid_getopt_str2crc(const char * _str) { // compare each string to short name unsigned int i; for (i=0; i> (len - i - 1)*8) & 0xff; return LIQUID_OK; } // validate message using error-detection key // _scheme : error-detection scheme // _msg : input data message, [size: _n x 1] // _n : input data message size // _key : error-detection key int crc_validate_message(crc_scheme _scheme, unsigned char * _msg, unsigned int _n, unsigned int _key) { if (_scheme == LIQUID_CRC_UNKNOWN) { liquid_error(LIQUID_EIMODE,"crc_validate_message(), cannot validate with CRC unknown type"); return 0; } else if (_scheme == LIQUID_CRC_NONE) { return 1; } return crc_generate_key(_scheme, _msg, _n) == _key; } // check message with key appended to end of array // _scheme : error-detection scheme (resulting in 'p' bytes) // _msg : input data message, [size: _n+p x 1] // _n : input data message size (excluding key at end) int crc_check_key(crc_scheme _scheme, unsigned char * _msg, unsigned int _n) { // get key size unsigned int len = crc_sizeof_key(_scheme); // extract key from end of message unsigned int key = 0; unsigned int i; for (i=0; i>1) ^ (poly & mask); } } return (~key8) & 0xff; } // // CRC-16 // // generate 16-bit cyclic redundancy check key. // // slow method, operates one bit at a time // algorithm from: http://www.hackersdelight.org/crc.pdf // // _msg : input data message [size: _n x 1] // _n : input data message size unsigned int crc16_generate_key(unsigned char *_msg, unsigned int _n) { unsigned int i, j, b, mask, key16=~0; unsigned int poly = liquid_reverse_uint16(CRC16_POLY); for (i=0; i<_n; i++) { b = _msg[i]; key16 ^= b; for (j=0; j<8; j++) { mask = -(key16 & 1); key16 = (key16>>1) ^ (poly & mask); } } return (~key16) & 0xffff; } // // CRC-24 // // generate 24-bit cyclic redundancy check key. // // slow method, operates one bit at a time // algorithm from: http://www.hackersdelight.org/crc.pdf // // _msg : input data message [size: _n x 1] // _n : input data message size unsigned int crc24_generate_key(unsigned char *_msg, unsigned int _n) { unsigned int i, j, b, mask, key24=~0; unsigned int poly = liquid_reverse_uint24(CRC24_POLY); for (i=0; i<_n; i++) { b = _msg[i]; key24 ^= b; for (j=0; j<8; j++) { mask = -(key24 & 1); key24 = (key24>>1) ^ (poly & mask); } } return (~key24) & 0xffffff; } // // CRC-32 // // generate 32-bit cyclic redundancy check key. // // slow method, operates one bit at a time // algorithm from: http://www.hackersdelight.org/crc.pdf // // _msg : input data message [size: _n x 1] // _n : input data message size unsigned int crc32_generate_key(unsigned char *_msg, unsigned int _n) { unsigned int i, j, b, mask, key32=~0; unsigned int poly = liquid_reverse_uint32(CRC32_POLY); for (i=0; i<_n; i++) { b = _msg[i]; key32 ^= b; for (j=0; j<8; j++) { mask = -(key32 & 1); key32 = (key32>>1) ^ (poly & mask); } } return (~key32) & 0xffffffff; } #if 0 int crc32_generate_key(unsigned char *_msg, unsigned int _n, unsigned char *_key) { unsigned int key32 = crc32_generate_key32(_msg,_n); _key[0] = (key32 & 0xFF000000) >> 24; _key[1] = (key32 & 0x00FF0000) >> 16; _key[2] = (key32 & 0x0000FF00) >> 8; _key[3] = (key32 & 0x000000FF); return LIQUID_OK; } #endif liquid-dsp-1.7.0/src/fec/src/fec.c000066400000000000000000000617211474751757600166440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // FEC (generic functions) // #include #include #include #include "liquid.internal.h" // object-independent methods const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2] = { // short name, long name {"unknown", "unknown"}, {"none", "none"}, {"rep3", "repeat(3)"}, {"rep5", "repeat(5)"}, {"h74", "Hamming(7,4)"}, {"h84", "Hamming(8,4)"}, {"h128", "Hamming(12,8)"}, {"g2412", "Golay(24,12)"}, {"secded2216", "SEC-DEC(22,16)"}, {"secded3932", "SEC-DEC(39,32)"}, {"secded7264", "SEC-DEC(72,64)"}, {"v27", "convolutional r1/2 K=7"}, {"v29", "convolutional r1/2 K=9"}, {"v39", "convolutional r1/3 K=9"}, {"v615", "convolutional r1/6 K=15"}, {"v27p23", "convolutional r2/3 K=7 (punctured)"}, {"v27p34", "convolutional r3/4 K=7 (punctured)"}, {"v27p45", "convolutional r4/5 K=7 (punctured)"}, {"v27p56", "convolutional r5/6 K=7 (punctured)"}, {"v27p67", "convolutional r6/7 K=7 (punctured)"}, {"v27p78", "convolutional r7/8 K=7 (punctured)"}, {"v29p23", "convolutional r2/3 K=9 (punctured)"}, {"v29p34", "convolutional r3/4 K=9 (punctured)"}, {"v29p45", "convolutional r4/5 K=9 (punctured)"}, {"v29p56", "convolutional r5/6 K=9 (punctured)"}, {"v29p67", "convolutional r6/7 K=9 (punctured)"}, {"v29p78", "convolutional r7/8 K=9 (punctured)"}, {"rs8", "Reed-Solomon, 223/255"} }; // Print compact list of existing and available fec schemes int liquid_print_fec_schemes() { unsigned int i; unsigned int len = 10; // print all available MOD schemes printf(" "); for (i=0; i 48 && i != LIQUID_FEC_NUM_SCHEMES-1) { len = 10; printf("\n "); } } printf("\n"); return LIQUID_OK; } fec_scheme liquid_getopt_str2fec(const char * _str) { // compare each string to short name unsigned int i; for (i=0; ischeme != _scheme) { // destroy old object and create new one fec_destroy(_q); _q = fec_create(_scheme,_opts); } // scheme hasn't changed; just return original object return _q; } // copy object fec fec_copy(fec q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("fec_copy(), object cannot be NULL"); // TODO: ensure state is retained return fec_create(q_orig->scheme, NULL); } // destroy fec object int fec_destroy(fec _q) { switch (_q->scheme) { case LIQUID_FEC_UNKNOWN: return liquid_error(LIQUID_EIMODE,"fec_destroy(), cannot destroy fec object of unknown type"); case LIQUID_FEC_NONE: return fec_pass_destroy(_q); case LIQUID_FEC_REP3: return fec_rep3_destroy(_q); case LIQUID_FEC_REP5: return fec_rep5_destroy(_q); case LIQUID_FEC_HAMMING74: return fec_hamming74_destroy(_q); case LIQUID_FEC_HAMMING84: return fec_hamming84_destroy(_q); case LIQUID_FEC_HAMMING128: return fec_hamming128_destroy(_q); case LIQUID_FEC_GOLAY2412: return fec_golay2412_destroy(_q); // SEC-DED codecs (single error correction, double error detection) case LIQUID_FEC_SECDED2216: return fec_secded2216_destroy(_q); case LIQUID_FEC_SECDED3932: return fec_secded3932_destroy(_q); case LIQUID_FEC_SECDED7264: return fec_secded7264_destroy(_q); // convolutional codes #if LIBFEC_ENABLED case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: return fec_conv_destroy(_q); // punctured case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: return fec_conv_punctured_destroy(_q); // Reed-Solomon codes case LIQUID_FEC_RS_M8: return fec_rs_destroy(_q); #else case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: return liquid_error(LIQUID_EUMODE,"fec_destroy(), convolutional codes unavailable (install libfec)"); case LIQUID_FEC_RS_M8: return liquid_error(LIQUID_EUMODE,"fec_destroy(), Reed-Solomon codes unavailable (install libfec)"); #endif default: return liquid_error(LIQUID_EUMODE,"fec_destroy(), unknown/unsupported scheme: %d\n", _q->scheme); } return liquid_error(LIQUID_EINT,"internal error"); } // print basic fec object internals int fec_print(fec _q) { printf("fec: %s [rate: %4.3f]\n", fec_scheme_str[_q->scheme][1], _q->rate); return LIQUID_OK; } // encode a block of data using a fec scheme // _q : fec object // _dec_msg_len : decoded message length // _msg_dec : decoded message // _msg_enc : encoded message int fec_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { // call internal encoding method return _q->encode_func(_q, _dec_msg_len, _msg_dec, _msg_enc); } // decode a block of data using a fec scheme // _q : fec object // _dec_msg_len : decoded message length // _msg_enc : encoded message // _msg_dec : decoded message int fec_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { // call internal decoding method return _q->decode_func(_q, _dec_msg_len, _msg_enc, _msg_dec); } // decode a block of data using a fec scheme // _q : fec object // _dec_msg_len : decoded message length // _msg_enc : encoded message // _msg_dec : decoded message int fec_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { if (_q->decode_soft_func != NULL) { // call internal decoding method return _q->decode_soft_func(_q, _dec_msg_len, _msg_enc, _msg_dec); } else { // pack bytes and use hard-decision decoding unsigned enc_msg_len = fec_get_enc_msg_length(_q->scheme, _dec_msg_len); unsigned char msg_enc_hard[enc_msg_len]; unsigned int i; for (i=0; i> 0) & 0x80; msg_enc_hard[i] |= (_msg_enc[8*i+1] >> 1) & 0x40; msg_enc_hard[i] |= (_msg_enc[8*i+2] >> 2) & 0x20; msg_enc_hard[i] |= (_msg_enc[8*i+3] >> 3) & 0x10; msg_enc_hard[i] |= (_msg_enc[8*i+4] >> 4) & 0x08; msg_enc_hard[i] |= (_msg_enc[8*i+5] >> 5) & 0x04; msg_enc_hard[i] |= (_msg_enc[8*i+6] >> 6) & 0x02; msg_enc_hard[i] |= (_msg_enc[8*i+7] >> 7) & 0x01; } // use hard-decoding method return fec_decode(_q, _dec_msg_len, msg_enc_hard, _msg_dec); } } liquid-dsp-1.7.0/src/fec/src/fec_conv.c000066400000000000000000000212341474751757600176640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // convolutional code (macros) // #include #include #include #include "liquid.internal.h" #define VERBOSE_FEC_CONV 0 #if LIBFEC_ENABLED #include "fec.h" fec fec_conv_create(fec_scheme _fs) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = _fs; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_conv_encode; q->decode_func = &fec_conv_decode_hard; // default to hard-decision decoding q->decode_soft_func = &fec_conv_decode_soft; switch (q->scheme) { case LIQUID_FEC_CONV_V27: fec_conv_init_v27(q); break; case LIQUID_FEC_CONV_V29: fec_conv_init_v29(q); break; case LIQUID_FEC_CONV_V39: fec_conv_init_v39(q); break; case LIQUID_FEC_CONV_V615: fec_conv_init_v615(q); break; default: return liquid_error_config("fec_conv_create(), invalid type"); } // convolutional-specific decoding q->num_dec_bytes = 0; q->enc_bits = NULL; q->vp = NULL; return q; } int fec_conv_destroy(fec _q) { // delete viterbi decoder if (_q->vp != NULL) _q->delete_viterbi(_q->vp); if (_q->enc_bits != NULL) free(_q->enc_bits); free(_q); return LIQUID_OK; } int fec_conv_encode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_dec, unsigned char *_msg_enc) { unsigned int i,j,r; // bookkeeping unsigned int sr=0; // convolutional shift register unsigned int n=0; // output bit counter unsigned char bit; unsigned char byte_in; unsigned char byte_out=0; for (i=0; i<_dec_msg_len; i++) { byte_in = _msg_dec[i]; // break byte into individual bits for (j=0; j<8; j++) { // shift bit starting with most significant bit = (byte_in >> (7-j)) & 0x01; sr = (sr << 1) | bit; // compute parity bits for each polynomial for (r=0; r<_q->R; r++) { byte_out = (byte_out<<1) | parity(sr & _q->poly[r]); _msg_enc[n/8] = byte_out; n++; } } } // tail bits for (i=0; i<(_q->K)-1; i++) { // shift register: push zeros sr = (sr << 1); // compute parity bits for each polynomial for (r=0; r<_q->R; r++) { byte_out = (byte_out<<1) | parity(sr & _q->poly[r]); _msg_enc[n/8] = byte_out; n++; } } // ensure even number of bytes while (n%8) { // shift zeros byte_out <<= 1; _msg_enc[n/8] = byte_out; n++; } assert(n == 8*fec_get_enc_msg_length(_q->scheme,_dec_msg_len)); return LIQUID_OK; } //unsigned int int fec_conv_decode_hard(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_enc, unsigned char *_msg_dec) { // re-allocate resources if necessary fec_conv_setlength(_q, _dec_msg_len); // unpack bytes unsigned int num_written; liquid_unpack_bytes(_msg_enc, // encoded message (bytes) _q->num_enc_bytes, // encoded message length (#bytes) _q->enc_bits, // encoded message (bits) _q->num_enc_bytes*8, // encoded message length (#bits) &num_written); #if VERBOSE_FEC_CONV unsigned int i; printf("msg encoded (bits):\n"); for (i=0; i<8*_q->num_enc_bytes; i++) { printf("%1u", _q->enc_bits[i]); if (((i+1)%8)==0) printf(" "); } printf("\n"); #endif // invoke hard-decision scaling unsigned int k; for (k=0; k<8*_q->num_enc_bytes; k++) _q->enc_bits[k] = _q->enc_bits[k] ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; // run internal decoder return fec_conv_decode(_q, _msg_dec); } //unsigned int int fec_conv_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_enc, unsigned char *_msg_dec) { // re-allocate resources if necessary fec_conv_setlength(_q, _dec_msg_len); // copy soft input bits unsigned int k; for (k=0; k<8*_q->num_enc_bytes; k++) _q->enc_bits[k] = _msg_enc[k]; // run internal decoder return fec_conv_decode(_q, _msg_dec); } //unsigned int int fec_conv_decode(fec _q, unsigned char * _msg_dec) { // run decoder _q->init_viterbi(_q->vp,0); _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1); _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0); #if VERBOSE_FEC_CONV for (i=0; i<_dec_msg_len; i++) printf("%.2x ", _msg_dec[i]); printf("\n"); #endif return LIQUID_OK; } int fec_conv_setlength(fec _q, unsigned int _dec_msg_len) { // re-allocate resources as necessary unsigned int num_dec_bytes = _dec_msg_len; // return if length has not changed if (num_dec_bytes == _q->num_dec_bytes) return LIQUID_OK; #if VERBOSE_FEC_CONV printf("(re)creating viterbi decoder, %u frame bytes\n", num_dec_bytes); #endif // reset number of framebits _q->num_dec_bytes = num_dec_bytes; _q->num_enc_bytes = fec_get_enc_msg_length(_q->scheme, _dec_msg_len); // delete old decoder if necessary if (_q->vp != NULL) _q->delete_viterbi(_q->vp); // re-create / re-allocate memory buffers _q->vp = _q->create_viterbi(8*_q->num_dec_bytes); //_q->set_viterbi_polynomial(_q->poly); _q->enc_bits = (unsigned char*) realloc(_q->enc_bits, _q->num_enc_bytes*8*sizeof(unsigned char)); return LIQUID_OK; } // // internal // int fec_conv_init_v27(fec _q) { _q->R=2; _q->K=7; _q->poly = fec_conv27_poly; _q->create_viterbi = create_viterbi27; //_q->set_viterbi_polynomial = set_viterbi27_polynomial; _q->init_viterbi = init_viterbi27; _q->update_viterbi_blk = update_viterbi27_blk; _q->chainback_viterbi = chainback_viterbi27; _q->delete_viterbi = delete_viterbi27; return LIQUID_OK; } int fec_conv_init_v29(fec _q) { _q->R=2; _q->K=9; _q->poly = fec_conv29_poly; _q->create_viterbi = create_viterbi29; //_q->set_viterbi_polynomial = set_viterbi29_polynomial; _q->init_viterbi = init_viterbi29; _q->update_viterbi_blk = update_viterbi29_blk; _q->chainback_viterbi = chainback_viterbi29; _q->delete_viterbi = delete_viterbi29; return LIQUID_OK; } int fec_conv_init_v39(fec _q) { _q->R=3; _q->K=9; _q->poly = fec_conv39_poly; _q->create_viterbi = create_viterbi39; //_q->set_viterbi_polynomial = set_viterbi39_polynomial; _q->init_viterbi = init_viterbi39; _q->update_viterbi_blk = update_viterbi39_blk; _q->chainback_viterbi = chainback_viterbi39; _q->delete_viterbi = delete_viterbi39; return LIQUID_OK; } int fec_conv_init_v615(fec _q) { _q->R=6; _q->K=15; _q->poly = fec_conv615_poly; _q->create_viterbi = create_viterbi615; //_q->set_viterbi_polynomial = set_viterbi615_polynomial; _q->init_viterbi = init_viterbi615; _q->update_viterbi_blk = update_viterbi615_blk; _q->chainback_viterbi = chainback_viterbi615; _q->delete_viterbi = delete_viterbi615; return LIQUID_OK; } #else // LIBFEC_ENABLED fec fec_conv_create(fec_scheme _fs) { return liquid_error_config("fec_conv_create(), libfec not installed"); } int fec_conv_destroy(fec _q) { return liquid_error(LIQUID_EUMODE,"fec_conv_destroy(), libfec not installed"); } #endif // LIBFEC_ENABLED liquid-dsp-1.7.0/src/fec/src/fec_conv_pmatrix.c000066400000000000000000000047631474751757600214400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "liquid.internal.h" // 2/3-rate K=7 punctured convolutional code int fec_conv27p23_matrix[4] = { 1, 1, 1, 0 }; // 3/4-rate K=7 punctured convolutional code int fec_conv27p34_matrix[6] = { 1, 1, 0, 1, 0, 1 }; // 4/5-rate K=7 punctured convolutional code int fec_conv27p45_matrix[8] = { 1, 1, 1, 1, 1, 0, 0, 0 }; // 5/6-rate K=7 punctured convolutional code int fec_conv27p56_matrix[10] = { 1, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; // 6/7-rate K=7 punctured convolutional code int fec_conv27p67_matrix[12] = { 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }; // 7/8-rate K=7 punctured convolutional code int fec_conv27p78_matrix[14] = { 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1 }; // 2/3-rate K=9 punctured convolutional code int fec_conv29p23_matrix[4] = { 1, 1, 1, 0 }; // 3/4-rate K=9 punctured convolutional code int fec_conv29p34_matrix[6] = { 1, 1, 1, 1, 0, 0 }; // 4/5-rate K=9 punctured convolutional code int fec_conv29p45_matrix[8] = { 1, 1, 0, 1, 1, 0, 1, 0 }; // 5/6-rate K=9 punctured convolutional code int fec_conv29p56_matrix[10] = { 1, 0, 1, 1, 0, 1, 1, 0, 0, 1 }; // 6/7-rate K=9 punctured convolutional code int fec_conv29p67_matrix[12] = { 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1 }; // 7/8-rate K=9 punctured convolutional code int fec_conv29p78_matrix[14] = { 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0 }; liquid-dsp-1.7.0/src/fec/src/fec_conv_poly.c000066400000000000000000000035411474751757600207300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // convolutional code polynomials // #include "liquid.internal.h" #if LIBFEC_ENABLED #include int fec_conv27_poly[2] = {V27POLYA, V27POLYB}; int fec_conv29_poly[2] = {V29POLYA, V29POLYB}; int fec_conv39_poly[3] = {V39POLYA, V39POLYB, V39POLYC}; int fec_conv615_poly[6] = {V615POLYA, V615POLYB, V615POLYC, V615POLYD, V615POLYE, V615POLYF}; #else int fec_conv27_poly[2] = {0,0}; int fec_conv29_poly[2] = {0,0}; int fec_conv39_poly[3] = {0,0,0}; int fec_conv615_poly[6] = {0,0,0,0,0,0}; #endif liquid-dsp-1.7.0/src/fec/src/fec_conv_punctured.c000066400000000000000000000333671474751757600217670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // convolutional code (macros) // #include #include #include #include "liquid.internal.h" #define VERBOSE_FEC_CONV_PUNCTURED 0 #if LIBFEC_ENABLED #include "fec.h" fec fec_conv_punctured_create(fec_scheme _fs) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = _fs; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_conv_punctured_encode; q->decode_func = &fec_conv_punctured_decode_hard; q->decode_soft_func = &fec_conv_punctured_decode_soft; switch (q->scheme) { case LIQUID_FEC_CONV_V27P23: fec_conv_init_v27p23(q); break; case LIQUID_FEC_CONV_V27P34: fec_conv_init_v27p34(q); break; case LIQUID_FEC_CONV_V27P45: fec_conv_init_v27p45(q); break; case LIQUID_FEC_CONV_V27P56: fec_conv_init_v27p56(q); break; case LIQUID_FEC_CONV_V27P67: fec_conv_init_v27p67(q); break; case LIQUID_FEC_CONV_V27P78: fec_conv_init_v27p78(q); break; case LIQUID_FEC_CONV_V29P23: fec_conv_init_v29p23(q); break; case LIQUID_FEC_CONV_V29P34: fec_conv_init_v29p34(q); break; case LIQUID_FEC_CONV_V29P45: fec_conv_init_v29p45(q); break; case LIQUID_FEC_CONV_V29P56: fec_conv_init_v29p56(q); break; case LIQUID_FEC_CONV_V29P67: fec_conv_init_v29p67(q); break; case LIQUID_FEC_CONV_V29P78: fec_conv_init_v29p78(q); break; default: return liquid_error_config("fec_conv_punctured_create(), invalid type"); } // convolutional-specific decoding q->num_dec_bytes = 0; q->enc_bits = NULL; q->vp = NULL; return q; } int fec_conv_punctured_destroy(fec _q) { // delete viterbi decoder if (_q->vp != NULL) _q->delete_viterbi(_q->vp); if (_q->enc_bits != NULL) free(_q->enc_bits); free(_q); return LIQUID_OK; } int fec_conv_punctured_encode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_dec, unsigned char *_msg_enc) { unsigned int i,j,r; // bookkeeping unsigned int sr=0; // convolutional shift register unsigned int n=0; // output bit counter unsigned int p=0; // puncturing matrix column index unsigned char bit; unsigned char byte_in; unsigned char byte_out=0; for (i=0; i<_dec_msg_len; i++) { byte_in = _msg_dec[i]; // break byte into individual bits for (j=0; j<8; j++) { // shift bit starting with most significant bit = (byte_in >> (7-j)) & 0x01; sr = (sr << 1) | bit; // compute parity bits for each polynomial for (r=0; r<_q->R; r++) { // enable output determined by puncturing matrix if (_q->puncturing_matrix[r*(_q->P)+p]) { byte_out = (byte_out<<1) | parity(sr & _q->poly[r]); _msg_enc[n/8] = byte_out; n++; } else { } } // update puncturing matrix column index p = (p+1) % _q->P; } } //printf("\n"); //printf("*** n = %u\n", n); // tail bits for (i=0; i<_q->K-1; i++) { // shift register: push zeros sr = (sr << 1); // compute parity bits for each polynomial for (r=0; r<_q->R; r++) { if (_q->puncturing_matrix[r*(_q->P)+p]) { byte_out = (byte_out<<1) | parity(sr & _q->poly[r]); _msg_enc[n/8] = byte_out; n++; } } // update puncturing matrix column index p = (p+1) % _q->P; } //printf("+++ n = %u\n", n); // ensure even number of bytes while (n%8) { // shift zeros byte_out <<= 1; _msg_enc[n/8] = byte_out; n++; } //printf("n = %u (expected %u)\n", n, 8*fec_get_enc_msg_length(LIQUID_FEC_CONV(_mode),_dec_msg_len)); assert(n == 8*fec_get_enc_msg_length(_q->scheme,_dec_msg_len)); return LIQUID_OK; } //unsigned int int fec_conv_punctured_decode_hard(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { // re-allocate resources if necessary fec_conv_punctured_setlength(_q, _dec_msg_len); // unpack bytes, adding erasures at punctured indices unsigned int num_dec_bits = _q->num_dec_bytes * 8 + _q->K - 1; unsigned int num_enc_bits = num_dec_bits * _q->R; unsigned int i,r; unsigned int n=0; // input byte index unsigned int k=0; // input bit index (0<=k<8) unsigned int p=0; // puncturing matrix column index unsigned char bit; unsigned char byte_in = _msg_enc[n]; for (i=0; iR) { // for (r=0; r<_q->R; r++) { if (_q->puncturing_matrix[r*(_q->P)+p]) { // push bit from input bit = (byte_in >> (7-k)) & 0x01; _q->enc_bits[i+r] = bit ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; k++; if (k==8) { k = 0; n++; byte_in = _msg_enc[n]; } } else { // push erasure _q->enc_bits[i+r] = LIQUID_SOFTBIT_ERASURE; } } p = (p+1) % _q->P; } #if VERBOSE_FEC_CONV_PUNCTURED unsigned int ii; printf("msg encoded (bits):\n"); for (ii=0; iienc_bits[ii]); if (((ii+1)%8)==0) printf("\n"); } printf("\n"); #endif // run decoder _q->init_viterbi(_q->vp,0); // TODO : check to see if this shouldn't be num_enc_bits (punctured) _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1); _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0); #if VERBOSE_FEC_CONV_PUNCTURED for (ii=0; ii<_dec_msg_len; ii++) printf("%.2x ", _msg_dec[ii]); printf("\n"); #endif return LIQUID_OK; } int fec_conv_punctured_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { // re-allocate resources if necessary fec_conv_punctured_setlength(_q, _dec_msg_len); // unpack bytes, adding erasures at punctured indices unsigned int num_dec_bits = _q->num_dec_bytes * 8 + _q->K - 1; unsigned int num_enc_bits = num_dec_bits * _q->R; unsigned int i,r; unsigned int n=0; // input soft bit index unsigned int p=0; // puncturing matrix column index for (i=0; iR) { // for (r=0; r<_q->R; r++) { if (_q->puncturing_matrix[r*(_q->P)+p]) { // push bit from input _q->enc_bits[i+r] = _msg_enc[n++]; } else { // push erasure _q->enc_bits[i+r] = LIQUID_SOFTBIT_ERASURE; } } p = (p+1) % _q->P; } #if VERBOSE_FEC_CONV_PUNCTURED unsigned int ii; printf("msg encoded (bits):\n"); for (ii=0; iienc_bits[ii]); if (((ii+1)%8)==0) printf("\n"); } printf("\n"); #endif // run decoder _q->init_viterbi(_q->vp,0); // TODO : check to see if this shouldn't be num_enc_bits (punctured) _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1); _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0); #if VERBOSE_FEC_CONV_PUNCTURED for (ii=0; ii<_dec_msg_len; ii++) printf("%.2x ", _msg_dec[ii]); printf("\n"); #endif return LIQUID_OK; } int fec_conv_punctured_setlength(fec _q, unsigned int _dec_msg_len) { // re-allocate resources as necessary unsigned int num_dec_bytes = _dec_msg_len; // return if length has not changed if (num_dec_bytes == _q->num_dec_bytes) return LIQUID_OK; // reset number of framebits _q->num_dec_bytes = num_dec_bytes; _q->num_enc_bytes = fec_get_enc_msg_length(_q->scheme, _dec_msg_len); // puncturing: need to expand to full length (decoder // injects erasures at punctured values) unsigned int num_dec_bits = 8*_q->num_dec_bytes; unsigned int n = num_dec_bits + _q->K - 1; unsigned int num_enc_bits = n*(_q->R); #if VERBOSE_FEC_CONV_PUNCTURED printf("(re)creating viterbi decoder, %u frame bytes\n", num_dec_bytes); printf(" num decoded bytes : %u\n", _q->num_dec_bytes); printf(" num encoded bytes : %u\n", _q->num_enc_bytes); printf(" num decoded bits : %u\n", num_dec_bits); printf(" num decoded bits (padded) : %u\n", n); printf(" num encoded bits (full) : %u\n", num_enc_bits); #endif // delete old decoder if necessary if (_q->vp != NULL) _q->delete_viterbi(_q->vp); // re-create / re-allocate memory buffers _q->vp = _q->create_viterbi(8*_q->num_dec_bytes); _q->enc_bits = (unsigned char*) realloc(_q->enc_bits, num_enc_bits*sizeof(unsigned char)); return LIQUID_OK; } // // internal // int fec_conv_init_v27p23(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 2; _q->puncturing_matrix = fec_conv27p23_matrix; return LIQUID_OK; } int fec_conv_init_v27p34(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 3; _q->puncturing_matrix = fec_conv27p34_matrix; return LIQUID_OK; } int fec_conv_init_v27p45(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 4; _q->puncturing_matrix = fec_conv27p45_matrix; return LIQUID_OK; } int fec_conv_init_v27p56(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 5; _q->puncturing_matrix = fec_conv27p56_matrix; return LIQUID_OK; } int fec_conv_init_v27p67(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 6; _q->puncturing_matrix = fec_conv27p67_matrix; return LIQUID_OK; } int fec_conv_init_v27p78(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v27(_q); _q->P = 7; _q->puncturing_matrix = fec_conv27p78_matrix; return LIQUID_OK; } int fec_conv_init_v29p23(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 2; _q->puncturing_matrix = fec_conv29p23_matrix; return LIQUID_OK; } int fec_conv_init_v29p34(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 3; _q->puncturing_matrix = fec_conv29p34_matrix; return LIQUID_OK; } int fec_conv_init_v29p45(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 4; _q->puncturing_matrix = fec_conv29p45_matrix; return LIQUID_OK; } int fec_conv_init_v29p56(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 5; _q->puncturing_matrix = fec_conv29p56_matrix; return LIQUID_OK; } int fec_conv_init_v29p67(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 6; _q->puncturing_matrix = fec_conv29p67_matrix; return LIQUID_OK; } int fec_conv_init_v29p78(fec _q) { // initialize R, K, polynomial, and viterbi methods fec_conv_init_v29(_q); _q->P = 7; _q->puncturing_matrix = fec_conv29p78_matrix; return LIQUID_OK; } #else // LIBFEC_ENABLED fec fec_conv_punctured_create(fec_scheme _fs) { return liquid_error_config("fec_conv_create(), libfec not installed"); } int fec_conv_punctured_destroy(fec _q) { return liquid_error(LIQUID_EUMODE,"fec_conv_punctured_destroy(), libfec not installed"); } int fec_conv_punctured_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { return liquid_error(LIQUID_EUMODE,"fec_conv_punctured_encode(), libfec not installed"); } //unsigned int int fec_conv_punctured_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { return liquid_error(LIQUID_EUMODE,"fec_conv_punctured_decode(), libfec not installed"); } #endif // LIBFEC_ENABLED liquid-dsp-1.7.0/src/fec/src/fec_golay2412.c000066400000000000000000000323501474751757600203440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Golay(24,12) half-rate forward error-correction code // // References: // [Lin:2004] Lin, Shu and Costello, Daniel L. Jr., "Error Control // Coding," Prentice Hall, New Jersey, 2nd edition, 2004. // #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_GOLAY2412 0 // P matrix [12 x 12] unsigned int golay2412_P[12] = { 0x08ed, 0x01db, 0x03b5, 0x0769, 0x0ed1, 0x0da3, 0x0b47, 0x068f, 0x0d1d, 0x0a3b, 0x0477, 0x0ffe}; #if 0 // generator matrix [12 x 24] unsigned int golay2412_G[12] = { 0x008ed800, 0x001db400, 0x003b5200, 0x00769100, 0x00ed1080, 0x00da3040, 0x00b47020, 0x0068f010, 0x00d1d008, 0x00a3b004, 0x00477002, 0x00ffe001}; #endif // generator matrix transposed [24 x 12] unsigned int golay2412_Gt[24] = { 0x08ed, 0x01db, 0x03b5, 0x0769, 0x0ed1, 0x0da3, 0x0b47, 0x068f, 0x0d1d, 0x0a3b, 0x0477, 0x0ffe, 0x0800, 0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001}; // parity check matrix [12 x 24] unsigned int golay2412_H[12] = { 0x008008ed, 0x004001db, 0x002003b5, 0x00100769, 0x00080ed1, 0x00040da3, 0x00020b47, 0x0001068f, 0x00008d1d, 0x00004a3b, 0x00002477, 0x00001ffe}; // multiply input vector with parity check matrix, H unsigned int golay2412_matrix_mul(unsigned int _v, unsigned int * _A, unsigned int _n) { unsigned int x = 0; unsigned int i; for (i=0; i<_n; i++) { x <<= 1; #if 0 // compute dot product mod 2 x |= liquid_count_ones_mod2( _A[i] & _v ); #else // same as above, but exploit the fact that vectors are at // most 24 bits long; liquid_count_ones_mod2() assumes full // 32- or 64-bit integer unsigned int c = 0; unsigned int p = _A[i] & _v; c += liquid_c_ones[ p & 0xff ]; p >>= 8; c += liquid_c_ones[ p & 0xff ]; p >>= 8; c += liquid_c_ones[ p & 0xff ]; x |= c & 0x0001; // mod 2 #endif } return x; } unsigned int fec_golay2412_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<12)) { liquid_error(LIQUID_EICONFIG,"fec_golay2412_encode_symbol(), input symbol too large"); return 0; } // compute encoded/transmitted message: v = m*G return golay2412_matrix_mul(_sym_dec, golay2412_Gt, 24); } // search for p[i] such that w(v+p[i]) <= 2, return -1 on fail int golay2412_parity_search(unsigned int _v) { //assert( _v < (1<<12) ); unsigned int i; for (i=0; i<12; i++) { #if 0 unsigned int wj = liquid_count_ones(_v ^ golay2412_P[i]); #else // same as above but faster, exploiting fact that P has // only 12 bits of resolution unsigned int wj = 0; unsigned int p = _v ^ golay2412_P[i]; wj += liquid_c_ones[ (p ) & 0xff ]; wj += liquid_c_ones[ (p >> 8) & 0xff ]; #endif if (wj <= 2) return i; } // could not find p[i] to satisfy criteria return -1; } unsigned int fec_golay2412_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<24)) { liquid_error(LIQUID_EICONFIG,"fec_golay2412_decode_symbol(), input symbol too large"); return 0; } // state variables unsigned int s=0; // syndrome vector unsigned int e_hat=0; // estimated error vector unsigned int v_hat=0; // estimated transmitted message unsigned int m_hat=0; // estimated original message // compute syndrome vector, s = r*H^T = ( H*r^T )^T s = golay2412_matrix_mul(_sym_enc, golay2412_H, 12); #if DEBUG_FEC_GOLAY2412 printf("s (syndrome vector): "); liquid_print_bitstring(s,12); printf("\n"); #endif // compute weight of s (12 bits) unsigned int ws = liquid_count_ones_uint16(s); #if DEBUG_FEC_GOLAY2412 printf("w(s) = %u\n", ws); #endif // step 2: e_hat = 0; if (ws <= 3) { #if DEBUG_FEC_GOLAY2412 printf(" w(s) <= 3: estimating error vector as [s, 0(12)]\n"); #endif // set e_hat = [s 0(12)] e_hat = (s << 12) & 0xfff000; } else { // step 3: search for p[i] s.t. w(s+p[i]) <= 2 #if DEBUG_FEC_GOLAY2412 printf(" searching for w(s + p_i) <= 2...\n"); #endif int s_index = golay2412_parity_search(s); if (s_index >= 0) { // vector found! #if DEBUG_FEC_GOLAY2412 printf(" w(s + p[%2u]) <= 2: estimating error vector as [s+p[%2u],u[%2u]]\n", s_index, s_index, s_index); #endif // NOTE : uj = 1 << (12-j-1) e_hat = ((s ^ golay2412_P[s_index]) << 12) | (1 << (11-s_index)); } else { // step 4: compute s*P unsigned int sP = golay2412_matrix_mul(s, golay2412_P, 12); #if DEBUG_FEC_GOLAY2412 printf("s*P: "); liquid_print_bitstring(sP,12); printf("\n"); #endif // compute weight of sP (12 bits) unsigned int wsP = liquid_count_ones_uint16(sP); #if DEBUG_FEC_GOLAY2412 printf("w(s*P) = %u\n", wsP); #endif if (wsP == 2 || wsP == 3) { // step 5: set e = [0, s*P] #if DEBUG_FEC_GOLAY2412 printf(" w(s*P) in [2,3]: estimating error vector as [0(12), s*P]\n"); #endif e_hat = sP; } else { // step 6: search for p[i] s.t. w(s*P + p[i]) == 2... #if DEBUG_FEC_GOLAY2412 printf(" searching for w(s*P + p_i) == 2...\n"); #endif int sP_index = golay2412_parity_search(sP); if (sP_index >= 0) { // vector found! #if DEBUG_FEC_GOLAY2412 printf(" w(s*P + p[%2u]) == 2: estimating error vector as [u[%2u],s*P+p[%2u]]\n", sP_index, sP_index, sP_index); #endif // NOTE : uj = 1 << (12-j-1) // [ uj << 1 2 ] [ sP + p[j] ] e_hat = (1 << (23-sP_index)) | (sP ^ golay2412_P[sP_index]); } else { // step 7: decoding error #if DEBUG_FEC_GOLAY2412 printf(" **** decoding error\n"); #endif } } } } // step 8: compute estimated transmitted message: v_hat = r + e_hat v_hat = _sym_enc ^ e_hat; #if DEBUG_FEC_GOLAY2412 printf("r (received vector): "); liquid_print_bitstring(_sym_enc,24); printf("\n"); printf("e-hat (estimated error vector): "); liquid_print_bitstring(e_hat,24); printf("\n"); printf("v-hat (estimated tx vector): "); liquid_print_bitstring(v_hat,24); printf("\n"); #endif // compute estimated original message: (last 12 bits of encoded message) m_hat = v_hat & 0x0fff; return m_hat; } // create Golay(24,12) codec object fec fec_golay2412_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_GOLAY2412; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_golay2412_encode; q->decode_func = &fec_golay2412_decode; q->decode_soft_func = NULL; return q; } // destroy Golay(24,12) object int fec_golay2412_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using Golay(24,12) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_golay2412_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter unsigned int s0, s1, s2; // three 8-bit symbols unsigned int m0, m1; // two 12-bit symbols (uncoded) unsigned int v0, v1; // two 24-bit symbols (encoded) // determine remainder of input length / 3 unsigned int r = _dec_msg_len % 3; for (i=0; i<_dec_msg_len-r; i+=3) { // strip three input bytes (two uncoded symbols) s0 = _msg_dec[i+0]; s1 = _msg_dec[i+1]; s2 = _msg_dec[i+2]; // pack into two 12-bit symbols m0 = ((s0 << 4) & 0x0ff0) | ((s1 >> 4) & 0x000f); m1 = ((s1 << 8) & 0x0f00) | ((s2 ) & 0x00ff); // encode each 12-bit symbol into a 24-bit symbol v0 = fec_golay2412_encode_symbol(m0); v1 = fec_golay2412_encode_symbol(m1); // unpack two 24-bit symbols into six 8-bit bytes // retaining order of bits in output _msg_enc[j+0] = (v0 >> 16) & 0xff; _msg_enc[j+1] = (v0 >> 8) & 0xff; _msg_enc[j+2] = (v0 ) & 0xff; _msg_enc[j+3] = (v1 >> 16) & 0xff; _msg_enc[j+4] = (v1 >> 8) & 0xff; _msg_enc[j+5] = (v1 ) & 0xff; j += 6; } // if input length isn't divisible by 3, encode last 1 or two bytes for (i=_dec_msg_len-r; i<_dec_msg_len; i++) { // strip last input symbol s0 = _msg_dec[i]; // extend as 12-bit symbol m0 = s0; // encode into 24-bit symbol v0 = fec_golay2412_encode_symbol(m0); // unpack one 24-bit symbol into three 8-bit bytes, and // append to output array _msg_enc[j+0] = ( v0 >> 16 ) & 0xff; _msg_enc[j+1] = ( v0 >> 8 ) & 0xff; _msg_enc[j+2] = ( v0 ) & 0xff; j += 3; } assert( j == fec_get_enc_msg_length(LIQUID_FEC_GOLAY2412,_dec_msg_len) ); assert( i == _dec_msg_len); return LIQUID_OK; } // decode block of data using Golay(24,12) decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] // //unsigned int int fec_golay2412_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter unsigned int r0, r1, r2, r3, r4, r5; // six 8-bit bytes unsigned int v0, v1; // two 24-bit encoded symbols unsigned int m0_hat, m1_hat; // two 12-bit decoded symbols // determine remainder of input length / 3 unsigned int r = _dec_msg_len % 3; for (i=0; i<_dec_msg_len-r; i+=3) { // strip six input bytes (two encoded symbols) r0 = _msg_enc[j+0]; r1 = _msg_enc[j+1]; r2 = _msg_enc[j+2]; r3 = _msg_enc[j+3]; r4 = _msg_enc[j+4]; r5 = _msg_enc[j+5]; // pack six 8-bit symbols into two 24-bit symbols v0 = ((r0 << 16) & 0xff0000) | ((r1 << 8) & 0x00ff00) | ((r2 ) & 0x0000ff); v1 = ((r3 << 16) & 0xff0000) | ((r4 << 8) & 0x00ff00) | ((r5 << 0) & 0x0000ff); // decode each symbol into a 12-bit symbol m0_hat = fec_golay2412_decode_symbol(v0); m1_hat = fec_golay2412_decode_symbol(v1); // unpack two 12-bit symbols into three 8-bit bytes _msg_dec[i+0] = ((m0_hat >> 4) & 0xff); _msg_dec[i+1] = ((m0_hat << 4) & 0xf0) | ((m1_hat >> 8) & 0x0f); _msg_dec[i+2] = ((m1_hat ) & 0xff); j += 6; } // if input length isn't divisible by 3, decode last 1 or two bytes for (i=_dec_msg_len-r; i<_dec_msg_len; i++) { // strip last input symbol (three bytes) r0 = _msg_enc[j+0]; r1 = _msg_enc[j+1]; r2 = _msg_enc[j+2]; // pack three 8-bit symbols into one 24-bit symbol v0 = ((r0 << 16) & 0xff0000) | ((r1 << 8) & 0x00ff00) | ((r2 ) & 0x0000ff); // decode into a 12-bit symbol m0_hat = fec_golay2412_decode_symbol(v0); // retain last 8 bits of 12-bit symbol _msg_dec[i] = m0_hat & 0xff; j += 3; } assert( j== fec_get_enc_msg_length(LIQUID_FEC_GOLAY2412,_dec_msg_len) ); assert( i == _dec_msg_len); return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/fec_hamming128.c000066400000000000000000000402011474751757600205650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 2/3-rate (12,8) Hamming code // // bit position 1 2 3 4 5 6 7 8 9 10 11 12 // encoded bits P1 P2 1 P4 2 3 4 P8 5 6 7 8 // // parity bit P1 x . x . x . x . x . x . // coveratge P2 . x x . . x x . . x x . // P4 . . . x x x x . . . . x // P8 . . . . . . . x x x x x #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_HAMMING128 0 // debugging flag #define FEC_HAMMING128_ENC_GENTAB 1 // use look-up table for encoding? // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:8) // // bit position 3 5 6 7 9 10 11 12 // // parity bit P1 x x . x x . x . = 1101 1010 // coverage P2 x . x x . x x . = 1011 0110 // P4 . x x x . . . x = 0111 0001 // P8 . . . . x x x x = 0000 1111 #define HAMMING128_M1 0xda // 1101 1010 #define HAMMING128_M2 0xb6 // 1011 0110 #define HAMMING128_M4 0x71 // 0111 0001 #define HAMMING128_M8 0x0f // 0000 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING128_S1 0x0aaa // .... 1010 1010 1010 #define HAMMING128_S2 0x0666 // .... 0110 0110 0110 #define HAMMING128_S4 0x01e1 // .... 0001 1110 0001 #define HAMMING128_S8 0x001f // .... 0000 0001 1111 unsigned int fec_hamming128_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<8)) { liquid_error(LIQUID_EICONFIG,"fec_hamming128_encode(), input symbol too large"); return 0; } // compute parity bits unsigned int p1 = liquid_bdotprod_uint16(_sym_dec, HAMMING128_M1); unsigned int p2 = liquid_bdotprod_uint16(_sym_dec, HAMMING128_M2); unsigned int p4 = liquid_bdotprod_uint16(_sym_dec, HAMMING128_M4); unsigned int p8 = liquid_bdotprod_uint16(_sym_dec, HAMMING128_M8); #if DEBUG_FEC_HAMMING128 printf("parity bits (p1,p2,p4,p8) : (%1u,%1u,%1u,%1u)\n", p1, p2, p4, p8); #endif // encode symbol by inserting parity bits with data bits to // make a 12-bit symbol unsigned int sym_enc = ((_sym_dec & 0x000f) << 0) | ((_sym_dec & 0x0070) << 1) | ((_sym_dec & 0x0080) << 2) | ( p1 << 11 ) | ( p2 << 10 ) | ( p4 << 8 ) | ( p8 << 4 ); return sym_enc; } unsigned int fec_hamming128_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<12)) { liquid_error(LIQUID_EICONFIG,"fec_hamming128_decode(), input symbol too large"); return 0; } // compute syndrome bits unsigned int s1 = liquid_bdotprod_uint16(_sym_enc, HAMMING128_S1); unsigned int s2 = liquid_bdotprod_uint16(_sym_enc, HAMMING128_S2); unsigned int s4 = liquid_bdotprod_uint16(_sym_enc, HAMMING128_S4); unsigned int s8 = liquid_bdotprod_uint16(_sym_enc, HAMMING128_S8); // index unsigned int z = (s8<<3) | (s4<<2) | (s2<<1) | s1; #if DEBUG_FEC_HAMMING128 printf("syndrome bits (s1,s2,s4,s8) : (%1u,%1u,%1u,%1u)\n", s1, s2, s4, s8); printf("syndrome z : %u\n", z); #endif // flip bit at this position if (z) { if (z > 12) { // if this happens there are likely too many errors // to correct; just pass without trying to do anything //fprintf(stderr,"warning, fec_hamming128_decode_symbol(), syndrome index exceeds 12\n"); } else { //printf("error detected!\n"); _sym_enc ^= 1 << (12-z); } } // strip data bits (x) from encoded symbol with parity bits (.) // symbol: [..x. xxx. xxxx] // 0000 0000 1111 > 0x000f // 0000 1110 0000 > 0x00e0 // 0010 0000 0000 > 0x0200 unsigned int sym_dec = ((_sym_enc & 0x000f) ) | ((_sym_enc & 0x00e0) >> 1) | ((_sym_enc & 0x0200) >> 2); return sym_dec; } // create Hamming(12,8) codec object fec fec_hamming128_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_HAMMING128; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_hamming128_encode; q->decode_func = &fec_hamming128_decode; q->decode_soft_func = &fec_hamming128_decode_soft; return q; } // destroy Hamming(12,8) object int fec_hamming128_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using Hamming(12,8) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_hamming128_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i, j=0; // input/output symbol counters unsigned char s0, s1; // input 8-bit symbols unsigned int m0, m1; // output 12-bit symbols // determine if input length is odd unsigned int r = _dec_msg_len % 2; for (i=0; i<_dec_msg_len-r; i+=2) { // strip two input bytes s0 = _msg_dec[i+0]; s1 = _msg_dec[i+1]; // encode each byte into 12-bit symbols #if FEC_HAMMING128_ENC_GENTAB m0 = hamming128_enc_gentab[s0]; m1 = hamming128_enc_gentab[s1]; #else m0 = fec_hamming128_encode_symbol(s0); m1 = fec_hamming128_encode_symbol(s1); #endif // append both 12-bit symbols to output (three 8-bit bytes), // retaining order of bits in output _msg_enc[j+0] = (m0 >> 4) & 0xff; _msg_enc[j+1] = ((m0 << 4) & 0xf0) | ((m1 >> 8) & 0x0f); _msg_enc[j+2] = (m1 ) & 0xff; j += 3; } // if input length is even, encode last symbol by itself if (r) { // strip last input symbol s0 = _msg_dec[_dec_msg_len-1]; // encode into 12-bit symbol #if FEC_HAMMING128_ENC_GENTAB m0 = hamming128_enc_gentab[s0]; #else m0 = fec_hamming128_encode_symbol(s0); #endif // append to output _msg_enc[j+0] = ( m0 & 0x0ff0 ) >> 4; _msg_enc[j+1] = ( m0 & 0x000f ) << 4; j += 2; } assert(j== fec_get_enc_msg_length(LIQUID_FEC_HAMMING128,_dec_msg_len)); return LIQUID_OK; } // decode block of data using Hamming(12,8) decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] // //unsigned int int fec_hamming128_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i=0,j=0; unsigned int r = _dec_msg_len % 2; unsigned char r0, r1, r2; unsigned int m0, m1; for (i=0; i<_dec_msg_len-r; i+=2) { // strip three input symbols r0 = _msg_enc[j+0]; r1 = _msg_enc[j+1]; r2 = _msg_enc[j+2]; // combine three 8-bit symbols into two 12-bit symbols m0 = ((r0 << 4) & 0x0ff0) | ((r1 >> 4) & 0x000f); m1 = ((r1 << 8) & 0x0f00) | ((r2 ) & 0x00ff); // decode each symbol into an 8-bit byte _msg_dec[i+0] = fec_hamming128_decode_symbol(m0); _msg_dec[i+1] = fec_hamming128_decode_symbol(m1); j += 3; } // if input length is even, decode last symbol by itself if (r) { // strip last two input bytes (last byte should only contain // for bits) r0 = _msg_enc[j+0]; r1 = _msg_enc[j+1]; // pack into 12-bit symbol m0 = ((r0 << 4) & 0x0ff0) | ((r1 >> 4) & 0x000f); // decode symbol into an 8-bit byte _msg_dec[i++] = fec_hamming128_decode_symbol(m0); j += 2; } assert(j== fec_get_enc_msg_length(LIQUID_FEC_HAMMING128,_dec_msg_len)); return LIQUID_OK; } // decode block of data using Hamming(12,8) soft decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 8*_enc_msg_len x 1] // _msg_dec : decoded message [size: _dec_msg_len x 1] // //unsigned int int fec_hamming128_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i; unsigned int k=0; // array bit index unsigned int r = _dec_msg_len % 2; // compute encoded message length unsigned int enc_msg_len = (3*_dec_msg_len)/2 + r; unsigned char s; // decoded 8-bit symbol //unsigned char num_errors=0; for (i=0; i<_dec_msg_len; i++) { #if 0 // use true ML soft decoding: about 1.45 dB improvement in Eb/N_0 for a BER of 10^-5 // with a decoding complexity of 1.43M cycles/trial (64-byte block) s = fecsoft_hamming128_decode(&_msg_enc[k]); #else // use n-3 nearest neighbors: about 0.54 dB improvement in Eb/N_0 for a BER of 10^-5 // with a decoding complexity of 124k cycles/trial (64-byte block) s = fecsoft_hamming128_decode_n3(&_msg_enc[k]); #endif k += 12; _msg_dec[i] = (unsigned char)(s & 0xff); //printf(" %3u : 0x%.2x > 0x%.2x, 0x%.2x > 0x%.2x (k=%u)\n", i, r0, s0, r1, s1, k); } k += r*4; // for assert method assert(k == 8*enc_msg_len); return LIQUID_OK; } // // internal methods // // soft decoding of one symbol // NOTE : because this method compares the received symbol to every // possible (256) encoded symbols, it is painfully slow to // run. unsigned int fecsoft_hamming128_decode(unsigned char * _soft_bits) { // find symbol with minimum distance from all 2^8 possible unsigned int d; // distance metric unsigned int dmin = 0; // minimum distance unsigned int s_hat = 0; // estimated transmitted symbol unsigned int c; // encoded symbol unsigned int s; for (s=0; s<256; s++) { // encode symbol #if FEC_HAMMING128_ENC_GENTAB c = hamming128_enc_gentab[s]; #else c = fec_hamming128_encode_symbol(s); #endif // compute distance metric d = 0; d += (c & 0x0800) ? 255 - _soft_bits[ 0] : _soft_bits[ 0]; d += (c & 0x0400) ? 255 - _soft_bits[ 1] : _soft_bits[ 1]; d += (c & 0x0200) ? 255 - _soft_bits[ 2] : _soft_bits[ 2]; d += (c & 0x0100) ? 255 - _soft_bits[ 3] : _soft_bits[ 3]; d += (c & 0x0080) ? 255 - _soft_bits[ 4] : _soft_bits[ 4]; d += (c & 0x0040) ? 255 - _soft_bits[ 5] : _soft_bits[ 5]; d += (c & 0x0020) ? 255 - _soft_bits[ 6] : _soft_bits[ 6]; d += (c & 0x0010) ? 255 - _soft_bits[ 7] : _soft_bits[ 7]; d += (c & 0x0008) ? 255 - _soft_bits[ 8] : _soft_bits[ 8]; d += (c & 0x0004) ? 255 - _soft_bits[ 9] : _soft_bits[ 9]; d += (c & 0x0002) ? 255 - _soft_bits[10] : _soft_bits[10]; d += (c & 0x0001) ? 255 - _soft_bits[11] : _soft_bits[11]; if (d < dmin || s==0) { s_hat = s; dmin = d; } } return s_hat; } // soft decoding of one symbol using nearest neighbors unsigned int fecsoft_hamming128_decode_n3(unsigned char * _soft_bits) { // find symbol with minimum distance from 17 nearest neighbors unsigned int d; // distance metric unsigned int dmin = 0; // minimum distance unsigned int s_hat = 0; // estimated transmitted symbol unsigned int c; // encoded symbol // compute hard-decoded symbol c = 0x0000; c |= (_soft_bits[ 0] > 127) ? 0x0800 : 0; c |= (_soft_bits[ 1] > 127) ? 0x0400 : 0; c |= (_soft_bits[ 2] > 127) ? 0x0200 : 0; c |= (_soft_bits[ 3] > 127) ? 0x0100 : 0; c |= (_soft_bits[ 4] > 127) ? 0x0080 : 0; c |= (_soft_bits[ 5] > 127) ? 0x0040 : 0; c |= (_soft_bits[ 6] > 127) ? 0x0020 : 0; c |= (_soft_bits[ 7] > 127) ? 0x0010 : 0; c |= (_soft_bits[ 8] > 127) ? 0x0008 : 0; c |= (_soft_bits[ 9] > 127) ? 0x0004 : 0; c |= (_soft_bits[10] > 127) ? 0x0002 : 0; c |= (_soft_bits[11] > 127) ? 0x0001 : 0; // decode symbol s_hat = fec_hamming128_decode_symbol(c); // re-encode and compute distance #if FEC_HAMMING128_ENC_GENTAB c = hamming128_enc_gentab[s_hat]; #else c = fec_hamming128_encode_symbol(s_hat); #endif // compute distance metric d = 0; d += (c & 0x0800) ? 255 - _soft_bits[ 0] : _soft_bits[ 0]; d += (c & 0x0400) ? 255 - _soft_bits[ 1] : _soft_bits[ 1]; d += (c & 0x0200) ? 255 - _soft_bits[ 2] : _soft_bits[ 2]; d += (c & 0x0100) ? 255 - _soft_bits[ 3] : _soft_bits[ 3]; d += (c & 0x0080) ? 255 - _soft_bits[ 4] : _soft_bits[ 4]; d += (c & 0x0040) ? 255 - _soft_bits[ 5] : _soft_bits[ 5]; d += (c & 0x0020) ? 255 - _soft_bits[ 6] : _soft_bits[ 6]; d += (c & 0x0010) ? 255 - _soft_bits[ 7] : _soft_bits[ 7]; d += (c & 0x0008) ? 255 - _soft_bits[ 8] : _soft_bits[ 8]; d += (c & 0x0004) ? 255 - _soft_bits[ 9] : _soft_bits[ 9]; d += (c & 0x0002) ? 255 - _soft_bits[10] : _soft_bits[10]; d += (c & 0x0001) ? 255 - _soft_bits[11] : _soft_bits[11]; dmin = d; // search over 17 nearest neighbors unsigned int s; unsigned int i; for (i=0; i<17; i++) { // use look-up table for nearest neighbors s = fecsoft_hamming128_n3[s_hat][i]; // encode symbol #if FEC_HAMMING128_ENC_GENTAB c = hamming128_enc_gentab[s]; #else c = fec_hamming128_encode_symbol(s); #endif // compute distance metric d = 0; d += (c & 0x0800) ? 255 - _soft_bits[ 0] : _soft_bits[ 0]; d += (c & 0x0400) ? 255 - _soft_bits[ 1] : _soft_bits[ 1]; d += (c & 0x0200) ? 255 - _soft_bits[ 2] : _soft_bits[ 2]; d += (c & 0x0100) ? 255 - _soft_bits[ 3] : _soft_bits[ 3]; d += (c & 0x0080) ? 255 - _soft_bits[ 4] : _soft_bits[ 4]; d += (c & 0x0040) ? 255 - _soft_bits[ 5] : _soft_bits[ 5]; d += (c & 0x0020) ? 255 - _soft_bits[ 6] : _soft_bits[ 6]; d += (c & 0x0010) ? 255 - _soft_bits[ 7] : _soft_bits[ 7]; d += (c & 0x0008) ? 255 - _soft_bits[ 8] : _soft_bits[ 8]; d += (c & 0x0004) ? 255 - _soft_bits[ 9] : _soft_bits[ 9]; d += (c & 0x0002) ? 255 - _soft_bits[10] : _soft_bits[10]; d += (c & 0x0001) ? 255 - _soft_bits[11] : _soft_bits[11]; if (d < dmin) { s_hat = s; dmin = d; } } return s_hat; } liquid-dsp-1.7.0/src/fec/src/fec_hamming128_gentab.c000066400000000000000000000747711474751757600221300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 2/3-rate (12,8) Hamming code generated tables // // encoding table unsigned short int hamming128_enc_gentab[256] = { 0x0000, 0x0111, 0x0c12, 0x0d03, 0x0414, 0x0505, 0x0806, 0x0917, 0x0818, 0x0909, 0x040a, 0x051b, 0x0c0c, 0x0d1d, 0x001e, 0x010f, 0x0d20, 0x0c31, 0x0132, 0x0023, 0x0934, 0x0825, 0x0526, 0x0437, 0x0538, 0x0429, 0x092a, 0x083b, 0x012c, 0x003d, 0x0d3e, 0x0c2f, 0x0540, 0x0451, 0x0952, 0x0843, 0x0154, 0x0045, 0x0d46, 0x0c57, 0x0d58, 0x0c49, 0x014a, 0x005b, 0x094c, 0x085d, 0x055e, 0x044f, 0x0860, 0x0971, 0x0472, 0x0563, 0x0c74, 0x0d65, 0x0066, 0x0177, 0x0078, 0x0169, 0x0c6a, 0x0d7b, 0x046c, 0x057d, 0x087e, 0x096f, 0x0980, 0x0891, 0x0592, 0x0483, 0x0d94, 0x0c85, 0x0186, 0x0097, 0x0198, 0x0089, 0x0d8a, 0x0c9b, 0x058c, 0x049d, 0x099e, 0x088f, 0x04a0, 0x05b1, 0x08b2, 0x09a3, 0x00b4, 0x01a5, 0x0ca6, 0x0db7, 0x0cb8, 0x0da9, 0x00aa, 0x01bb, 0x08ac, 0x09bd, 0x04be, 0x05af, 0x0cc0, 0x0dd1, 0x00d2, 0x01c3, 0x08d4, 0x09c5, 0x04c6, 0x05d7, 0x04d8, 0x05c9, 0x08ca, 0x09db, 0x00cc, 0x01dd, 0x0cde, 0x0dcf, 0x01e0, 0x00f1, 0x0df2, 0x0ce3, 0x05f4, 0x04e5, 0x09e6, 0x08f7, 0x09f8, 0x08e9, 0x05ea, 0x04fb, 0x0dec, 0x0cfd, 0x01fe, 0x00ef, 0x0e00, 0x0f11, 0x0212, 0x0303, 0x0a14, 0x0b05, 0x0606, 0x0717, 0x0618, 0x0709, 0x0a0a, 0x0b1b, 0x020c, 0x031d, 0x0e1e, 0x0f0f, 0x0320, 0x0231, 0x0f32, 0x0e23, 0x0734, 0x0625, 0x0b26, 0x0a37, 0x0b38, 0x0a29, 0x072a, 0x063b, 0x0f2c, 0x0e3d, 0x033e, 0x022f, 0x0b40, 0x0a51, 0x0752, 0x0643, 0x0f54, 0x0e45, 0x0346, 0x0257, 0x0358, 0x0249, 0x0f4a, 0x0e5b, 0x074c, 0x065d, 0x0b5e, 0x0a4f, 0x0660, 0x0771, 0x0a72, 0x0b63, 0x0274, 0x0365, 0x0e66, 0x0f77, 0x0e78, 0x0f69, 0x026a, 0x037b, 0x0a6c, 0x0b7d, 0x067e, 0x076f, 0x0780, 0x0691, 0x0b92, 0x0a83, 0x0394, 0x0285, 0x0f86, 0x0e97, 0x0f98, 0x0e89, 0x038a, 0x029b, 0x0b8c, 0x0a9d, 0x079e, 0x068f, 0x0aa0, 0x0bb1, 0x06b2, 0x07a3, 0x0eb4, 0x0fa5, 0x02a6, 0x03b7, 0x02b8, 0x03a9, 0x0eaa, 0x0fbb, 0x06ac, 0x07bd, 0x0abe, 0x0baf, 0x02c0, 0x03d1, 0x0ed2, 0x0fc3, 0x06d4, 0x07c5, 0x0ac6, 0x0bd7, 0x0ad8, 0x0bc9, 0x06ca, 0x07db, 0x0ecc, 0x0fdd, 0x02de, 0x03cf, 0x0fe0, 0x0ef1, 0x03f2, 0x02e3, 0x0bf4, 0x0ae5, 0x07e6, 0x06f7, 0x07f8, 0x06e9, 0x0bea, 0x0afb, 0x03ec, 0x02fd, 0x0ffe, 0x0eef}; // nearest neighbors with Hamming distance 3 (for soft decoding) unsigned char fecsoft_hamming128_n3[256][17] = { {0x01, 0x04, 0x06, 0x08, 0x0a, 0x13, 0x20, 0x25, 0x30, 0x40, 0x49, 0x50, 0x80, 0x82, 0x8c, 0x90, 0xe0}, {0x00, 0x05, 0x07, 0x09, 0x0b, 0x12, 0x21, 0x24, 0x31, 0x41, 0x48, 0x51, 0x81, 0x83, 0x8d, 0x91, 0xe1}, {0x03, 0x04, 0x06, 0x08, 0x0a, 0x11, 0x22, 0x27, 0x32, 0x42, 0x4b, 0x52, 0x80, 0x82, 0x8e, 0x92, 0xe2}, {0x02, 0x05, 0x07, 0x09, 0x0b, 0x10, 0x23, 0x26, 0x33, 0x43, 0x4a, 0x53, 0x81, 0x83, 0x8f, 0x93, 0xe3}, {0x00, 0x02, 0x05, 0x0c, 0x0e, 0x17, 0x21, 0x24, 0x34, 0x44, 0x4d, 0x54, 0x84, 0x86, 0x88, 0x94, 0xe4}, {0x01, 0x03, 0x04, 0x0d, 0x0f, 0x16, 0x20, 0x25, 0x35, 0x45, 0x4c, 0x55, 0x85, 0x87, 0x89, 0x95, 0xe5}, {0x00, 0x02, 0x07, 0x0c, 0x0e, 0x15, 0x23, 0x26, 0x36, 0x46, 0x4f, 0x56, 0x84, 0x86, 0x8a, 0x96, 0xe6}, {0x01, 0x03, 0x06, 0x0d, 0x0f, 0x14, 0x22, 0x27, 0x37, 0x47, 0x4e, 0x57, 0x85, 0x87, 0x8b, 0x97, 0xe7}, {0x00, 0x02, 0x09, 0x0c, 0x0e, 0x1b, 0x28, 0x2d, 0x38, 0x41, 0x48, 0x58, 0x84, 0x88, 0x8a, 0x98, 0xe8}, {0x01, 0x03, 0x08, 0x0d, 0x0f, 0x1a, 0x29, 0x2c, 0x39, 0x40, 0x49, 0x59, 0x85, 0x89, 0x8b, 0x99, 0xe9}, {0x00, 0x02, 0x0b, 0x0c, 0x0e, 0x19, 0x2a, 0x2f, 0x3a, 0x43, 0x4a, 0x5a, 0x86, 0x88, 0x8a, 0x9a, 0xea}, {0x01, 0x03, 0x0a, 0x0d, 0x0f, 0x18, 0x2b, 0x2e, 0x3b, 0x42, 0x4b, 0x5b, 0x87, 0x89, 0x8b, 0x9b, 0xeb}, {0x04, 0x06, 0x08, 0x0a, 0x0d, 0x1f, 0x29, 0x2c, 0x3c, 0x45, 0x4c, 0x5c, 0x80, 0x8c, 0x8e, 0x9c, 0xec}, {0x05, 0x07, 0x09, 0x0b, 0x0c, 0x1e, 0x28, 0x2d, 0x3d, 0x44, 0x4d, 0x5d, 0x81, 0x8d, 0x8f, 0x9d, 0xed}, {0x04, 0x06, 0x08, 0x0a, 0x0f, 0x1d, 0x2b, 0x2e, 0x3e, 0x47, 0x4e, 0x5e, 0x82, 0x8c, 0x8e, 0x9e, 0xee}, {0x05, 0x07, 0x09, 0x0b, 0x0e, 0x1c, 0x2a, 0x2f, 0x3f, 0x46, 0x4f, 0x5f, 0x83, 0x8d, 0x8f, 0x9f, 0xef}, {0x03, 0x11, 0x14, 0x16, 0x18, 0x1a, 0x20, 0x30, 0x35, 0x40, 0x50, 0x59, 0x80, 0x90, 0x92, 0x9c, 0xf0}, {0x02, 0x10, 0x15, 0x17, 0x19, 0x1b, 0x21, 0x31, 0x34, 0x41, 0x51, 0x58, 0x81, 0x91, 0x93, 0x9d, 0xf1}, {0x01, 0x13, 0x14, 0x16, 0x18, 0x1a, 0x22, 0x32, 0x37, 0x42, 0x52, 0x5b, 0x82, 0x90, 0x92, 0x9e, 0xf2}, {0x00, 0x12, 0x15, 0x17, 0x19, 0x1b, 0x23, 0x33, 0x36, 0x43, 0x53, 0x5a, 0x83, 0x91, 0x93, 0x9f, 0xf3}, {0x07, 0x10, 0x12, 0x15, 0x1c, 0x1e, 0x24, 0x31, 0x34, 0x44, 0x54, 0x5d, 0x84, 0x94, 0x96, 0x98, 0xf4}, {0x06, 0x11, 0x13, 0x14, 0x1d, 0x1f, 0x25, 0x30, 0x35, 0x45, 0x55, 0x5c, 0x85, 0x95, 0x97, 0x99, 0xf5}, {0x05, 0x10, 0x12, 0x17, 0x1c, 0x1e, 0x26, 0x33, 0x36, 0x46, 0x56, 0x5f, 0x86, 0x94, 0x96, 0x9a, 0xf6}, {0x04, 0x11, 0x13, 0x16, 0x1d, 0x1f, 0x27, 0x32, 0x37, 0x47, 0x57, 0x5e, 0x87, 0x95, 0x97, 0x9b, 0xf7}, {0x0b, 0x10, 0x12, 0x19, 0x1c, 0x1e, 0x28, 0x38, 0x3d, 0x48, 0x51, 0x58, 0x88, 0x94, 0x98, 0x9a, 0xf8}, {0x0a, 0x11, 0x13, 0x18, 0x1d, 0x1f, 0x29, 0x39, 0x3c, 0x49, 0x50, 0x59, 0x89, 0x95, 0x99, 0x9b, 0xf9}, {0x09, 0x10, 0x12, 0x1b, 0x1c, 0x1e, 0x2a, 0x3a, 0x3f, 0x4a, 0x53, 0x5a, 0x8a, 0x96, 0x98, 0x9a, 0xfa}, {0x08, 0x11, 0x13, 0x1a, 0x1d, 0x1f, 0x2b, 0x3b, 0x3e, 0x4b, 0x52, 0x5b, 0x8b, 0x97, 0x99, 0x9b, 0xfb}, {0x0f, 0x14, 0x16, 0x18, 0x1a, 0x1d, 0x2c, 0x39, 0x3c, 0x4c, 0x55, 0x5c, 0x8c, 0x90, 0x9c, 0x9e, 0xfc}, {0x0e, 0x15, 0x17, 0x19, 0x1b, 0x1c, 0x2d, 0x38, 0x3d, 0x4d, 0x54, 0x5d, 0x8d, 0x91, 0x9d, 0x9f, 0xfd}, {0x0d, 0x14, 0x16, 0x18, 0x1a, 0x1f, 0x2e, 0x3b, 0x3e, 0x4e, 0x57, 0x5e, 0x8e, 0x92, 0x9c, 0x9e, 0xfe}, {0x0c, 0x15, 0x17, 0x19, 0x1b, 0x1e, 0x2f, 0x3a, 0x3f, 0x4f, 0x56, 0x5f, 0x8f, 0x93, 0x9d, 0x9f, 0xff}, {0x00, 0x05, 0x10, 0x21, 0x24, 0x26, 0x28, 0x2a, 0x33, 0x60, 0x69, 0x70, 0xa0, 0xa2, 0xac, 0xb0, 0xc0}, {0x01, 0x04, 0x11, 0x20, 0x25, 0x27, 0x29, 0x2b, 0x32, 0x61, 0x68, 0x71, 0xa1, 0xa3, 0xad, 0xb1, 0xc1}, {0x02, 0x07, 0x12, 0x23, 0x24, 0x26, 0x28, 0x2a, 0x31, 0x62, 0x6b, 0x72, 0xa0, 0xa2, 0xae, 0xb2, 0xc2}, {0x03, 0x06, 0x13, 0x22, 0x25, 0x27, 0x29, 0x2b, 0x30, 0x63, 0x6a, 0x73, 0xa1, 0xa3, 0xaf, 0xb3, 0xc3}, {0x01, 0x04, 0x14, 0x20, 0x22, 0x25, 0x2c, 0x2e, 0x37, 0x64, 0x6d, 0x74, 0xa4, 0xa6, 0xa8, 0xb4, 0xc4}, {0x00, 0x05, 0x15, 0x21, 0x23, 0x24, 0x2d, 0x2f, 0x36, 0x65, 0x6c, 0x75, 0xa5, 0xa7, 0xa9, 0xb5, 0xc5}, {0x03, 0x06, 0x16, 0x20, 0x22, 0x27, 0x2c, 0x2e, 0x35, 0x66, 0x6f, 0x76, 0xa4, 0xa6, 0xaa, 0xb6, 0xc6}, {0x02, 0x07, 0x17, 0x21, 0x23, 0x26, 0x2d, 0x2f, 0x34, 0x67, 0x6e, 0x77, 0xa5, 0xa7, 0xab, 0xb7, 0xc7}, {0x08, 0x0d, 0x18, 0x20, 0x22, 0x29, 0x2c, 0x2e, 0x3b, 0x61, 0x68, 0x78, 0xa4, 0xa8, 0xaa, 0xb8, 0xc8}, {0x09, 0x0c, 0x19, 0x21, 0x23, 0x28, 0x2d, 0x2f, 0x3a, 0x60, 0x69, 0x79, 0xa5, 0xa9, 0xab, 0xb9, 0xc9}, {0x0a, 0x0f, 0x1a, 0x20, 0x22, 0x2b, 0x2c, 0x2e, 0x39, 0x63, 0x6a, 0x7a, 0xa6, 0xa8, 0xaa, 0xba, 0xca}, {0x0b, 0x0e, 0x1b, 0x21, 0x23, 0x2a, 0x2d, 0x2f, 0x38, 0x62, 0x6b, 0x7b, 0xa7, 0xa9, 0xab, 0xbb, 0xcb}, {0x09, 0x0c, 0x1c, 0x24, 0x26, 0x28, 0x2a, 0x2d, 0x3f, 0x65, 0x6c, 0x7c, 0xa0, 0xac, 0xae, 0xbc, 0xcc}, {0x08, 0x0d, 0x1d, 0x25, 0x27, 0x29, 0x2b, 0x2c, 0x3e, 0x64, 0x6d, 0x7d, 0xa1, 0xad, 0xaf, 0xbd, 0xcd}, {0x0b, 0x0e, 0x1e, 0x24, 0x26, 0x28, 0x2a, 0x2f, 0x3d, 0x67, 0x6e, 0x7e, 0xa2, 0xac, 0xae, 0xbe, 0xce}, {0x0a, 0x0f, 0x1f, 0x25, 0x27, 0x29, 0x2b, 0x2e, 0x3c, 0x66, 0x6f, 0x7f, 0xa3, 0xad, 0xaf, 0xbf, 0xcf}, {0x00, 0x10, 0x15, 0x23, 0x31, 0x34, 0x36, 0x38, 0x3a, 0x60, 0x70, 0x79, 0xa0, 0xb0, 0xb2, 0xbc, 0xd0}, {0x01, 0x11, 0x14, 0x22, 0x30, 0x35, 0x37, 0x39, 0x3b, 0x61, 0x71, 0x78, 0xa1, 0xb1, 0xb3, 0xbd, 0xd1}, {0x02, 0x12, 0x17, 0x21, 0x33, 0x34, 0x36, 0x38, 0x3a, 0x62, 0x72, 0x7b, 0xa2, 0xb0, 0xb2, 0xbe, 0xd2}, {0x03, 0x13, 0x16, 0x20, 0x32, 0x35, 0x37, 0x39, 0x3b, 0x63, 0x73, 0x7a, 0xa3, 0xb1, 0xb3, 0xbf, 0xd3}, {0x04, 0x11, 0x14, 0x27, 0x30, 0x32, 0x35, 0x3c, 0x3e, 0x64, 0x74, 0x7d, 0xa4, 0xb4, 0xb6, 0xb8, 0xd4}, {0x05, 0x10, 0x15, 0x26, 0x31, 0x33, 0x34, 0x3d, 0x3f, 0x65, 0x75, 0x7c, 0xa5, 0xb5, 0xb7, 0xb9, 0xd5}, {0x06, 0x13, 0x16, 0x25, 0x30, 0x32, 0x37, 0x3c, 0x3e, 0x66, 0x76, 0x7f, 0xa6, 0xb4, 0xb6, 0xba, 0xd6}, {0x07, 0x12, 0x17, 0x24, 0x31, 0x33, 0x36, 0x3d, 0x3f, 0x67, 0x77, 0x7e, 0xa7, 0xb5, 0xb7, 0xbb, 0xd7}, {0x08, 0x18, 0x1d, 0x2b, 0x30, 0x32, 0x39, 0x3c, 0x3e, 0x68, 0x71, 0x78, 0xa8, 0xb4, 0xb8, 0xba, 0xd8}, {0x09, 0x19, 0x1c, 0x2a, 0x31, 0x33, 0x38, 0x3d, 0x3f, 0x69, 0x70, 0x79, 0xa9, 0xb5, 0xb9, 0xbb, 0xd9}, {0x0a, 0x1a, 0x1f, 0x29, 0x30, 0x32, 0x3b, 0x3c, 0x3e, 0x6a, 0x73, 0x7a, 0xaa, 0xb6, 0xb8, 0xba, 0xda}, {0x0b, 0x1b, 0x1e, 0x28, 0x31, 0x33, 0x3a, 0x3d, 0x3f, 0x6b, 0x72, 0x7b, 0xab, 0xb7, 0xb9, 0xbb, 0xdb}, {0x0c, 0x19, 0x1c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3d, 0x6c, 0x75, 0x7c, 0xac, 0xb0, 0xbc, 0xbe, 0xdc}, {0x0d, 0x18, 0x1d, 0x2e, 0x35, 0x37, 0x39, 0x3b, 0x3c, 0x6d, 0x74, 0x7d, 0xad, 0xb1, 0xbd, 0xbf, 0xdd}, {0x0e, 0x1b, 0x1e, 0x2d, 0x34, 0x36, 0x38, 0x3a, 0x3f, 0x6e, 0x77, 0x7e, 0xae, 0xb2, 0xbc, 0xbe, 0xde}, {0x0f, 0x1a, 0x1f, 0x2c, 0x35, 0x37, 0x39, 0x3b, 0x3e, 0x6f, 0x76, 0x7f, 0xaf, 0xb3, 0xbd, 0xbf, 0xdf}, {0x00, 0x09, 0x10, 0x41, 0x44, 0x46, 0x48, 0x4a, 0x53, 0x60, 0x65, 0x70, 0xa0, 0xc0, 0xc2, 0xcc, 0xd0}, {0x01, 0x08, 0x11, 0x40, 0x45, 0x47, 0x49, 0x4b, 0x52, 0x61, 0x64, 0x71, 0xa1, 0xc1, 0xc3, 0xcd, 0xd1}, {0x02, 0x0b, 0x12, 0x43, 0x44, 0x46, 0x48, 0x4a, 0x51, 0x62, 0x67, 0x72, 0xa2, 0xc0, 0xc2, 0xce, 0xd2}, {0x03, 0x0a, 0x13, 0x42, 0x45, 0x47, 0x49, 0x4b, 0x50, 0x63, 0x66, 0x73, 0xa3, 0xc1, 0xc3, 0xcf, 0xd3}, {0x04, 0x0d, 0x14, 0x40, 0x42, 0x45, 0x4c, 0x4e, 0x57, 0x61, 0x64, 0x74, 0xa4, 0xc4, 0xc6, 0xc8, 0xd4}, {0x05, 0x0c, 0x15, 0x41, 0x43, 0x44, 0x4d, 0x4f, 0x56, 0x60, 0x65, 0x75, 0xa5, 0xc5, 0xc7, 0xc9, 0xd5}, {0x06, 0x0f, 0x16, 0x40, 0x42, 0x47, 0x4c, 0x4e, 0x55, 0x63, 0x66, 0x76, 0xa6, 0xc4, 0xc6, 0xca, 0xd6}, {0x07, 0x0e, 0x17, 0x41, 0x43, 0x46, 0x4d, 0x4f, 0x54, 0x62, 0x67, 0x77, 0xa7, 0xc5, 0xc7, 0xcb, 0xd7}, {0x01, 0x08, 0x18, 0x40, 0x42, 0x49, 0x4c, 0x4e, 0x5b, 0x68, 0x6d, 0x78, 0xa8, 0xc4, 0xc8, 0xca, 0xd8}, {0x00, 0x09, 0x19, 0x41, 0x43, 0x48, 0x4d, 0x4f, 0x5a, 0x69, 0x6c, 0x79, 0xa9, 0xc5, 0xc9, 0xcb, 0xd9}, {0x03, 0x0a, 0x1a, 0x40, 0x42, 0x4b, 0x4c, 0x4e, 0x59, 0x6a, 0x6f, 0x7a, 0xaa, 0xc6, 0xc8, 0xca, 0xda}, {0x02, 0x0b, 0x1b, 0x41, 0x43, 0x4a, 0x4d, 0x4f, 0x58, 0x6b, 0x6e, 0x7b, 0xab, 0xc7, 0xc9, 0xcb, 0xdb}, {0x05, 0x0c, 0x1c, 0x44, 0x46, 0x48, 0x4a, 0x4d, 0x5f, 0x69, 0x6c, 0x7c, 0xac, 0xc0, 0xcc, 0xce, 0xdc}, {0x04, 0x0d, 0x1d, 0x45, 0x47, 0x49, 0x4b, 0x4c, 0x5e, 0x68, 0x6d, 0x7d, 0xad, 0xc1, 0xcd, 0xcf, 0xdd}, {0x07, 0x0e, 0x1e, 0x44, 0x46, 0x48, 0x4a, 0x4f, 0x5d, 0x6b, 0x6e, 0x7e, 0xae, 0xc2, 0xcc, 0xce, 0xde}, {0x06, 0x0f, 0x1f, 0x45, 0x47, 0x49, 0x4b, 0x4e, 0x5c, 0x6a, 0x6f, 0x7f, 0xaf, 0xc3, 0xcd, 0xcf, 0xdf}, {0x00, 0x10, 0x19, 0x43, 0x51, 0x54, 0x56, 0x58, 0x5a, 0x60, 0x70, 0x75, 0xb0, 0xc0, 0xd0, 0xd2, 0xdc}, {0x01, 0x11, 0x18, 0x42, 0x50, 0x55, 0x57, 0x59, 0x5b, 0x61, 0x71, 0x74, 0xb1, 0xc1, 0xd1, 0xd3, 0xdd}, {0x02, 0x12, 0x1b, 0x41, 0x53, 0x54, 0x56, 0x58, 0x5a, 0x62, 0x72, 0x77, 0xb2, 0xc2, 0xd0, 0xd2, 0xde}, {0x03, 0x13, 0x1a, 0x40, 0x52, 0x55, 0x57, 0x59, 0x5b, 0x63, 0x73, 0x76, 0xb3, 0xc3, 0xd1, 0xd3, 0xdf}, {0x04, 0x14, 0x1d, 0x47, 0x50, 0x52, 0x55, 0x5c, 0x5e, 0x64, 0x71, 0x74, 0xb4, 0xc4, 0xd4, 0xd6, 0xd8}, {0x05, 0x15, 0x1c, 0x46, 0x51, 0x53, 0x54, 0x5d, 0x5f, 0x65, 0x70, 0x75, 0xb5, 0xc5, 0xd5, 0xd7, 0xd9}, {0x06, 0x16, 0x1f, 0x45, 0x50, 0x52, 0x57, 0x5c, 0x5e, 0x66, 0x73, 0x76, 0xb6, 0xc6, 0xd4, 0xd6, 0xda}, {0x07, 0x17, 0x1e, 0x44, 0x51, 0x53, 0x56, 0x5d, 0x5f, 0x67, 0x72, 0x77, 0xb7, 0xc7, 0xd5, 0xd7, 0xdb}, {0x08, 0x11, 0x18, 0x4b, 0x50, 0x52, 0x59, 0x5c, 0x5e, 0x68, 0x78, 0x7d, 0xb8, 0xc8, 0xd4, 0xd8, 0xda}, {0x09, 0x10, 0x19, 0x4a, 0x51, 0x53, 0x58, 0x5d, 0x5f, 0x69, 0x79, 0x7c, 0xb9, 0xc9, 0xd5, 0xd9, 0xdb}, {0x0a, 0x13, 0x1a, 0x49, 0x50, 0x52, 0x5b, 0x5c, 0x5e, 0x6a, 0x7a, 0x7f, 0xba, 0xca, 0xd6, 0xd8, 0xda}, {0x0b, 0x12, 0x1b, 0x48, 0x51, 0x53, 0x5a, 0x5d, 0x5f, 0x6b, 0x7b, 0x7e, 0xbb, 0xcb, 0xd7, 0xd9, 0xdb}, {0x0c, 0x15, 0x1c, 0x4f, 0x54, 0x56, 0x58, 0x5a, 0x5d, 0x6c, 0x79, 0x7c, 0xbc, 0xcc, 0xd0, 0xdc, 0xde}, {0x0d, 0x14, 0x1d, 0x4e, 0x55, 0x57, 0x59, 0x5b, 0x5c, 0x6d, 0x78, 0x7d, 0xbd, 0xcd, 0xd1, 0xdd, 0xdf}, {0x0e, 0x17, 0x1e, 0x4d, 0x54, 0x56, 0x58, 0x5a, 0x5f, 0x6e, 0x7b, 0x7e, 0xbe, 0xce, 0xd2, 0xdc, 0xde}, {0x0f, 0x16, 0x1f, 0x4c, 0x55, 0x57, 0x59, 0x5b, 0x5e, 0x6f, 0x7a, 0x7f, 0xbf, 0xcf, 0xd3, 0xdd, 0xdf}, {0x20, 0x29, 0x30, 0x40, 0x45, 0x50, 0x61, 0x64, 0x66, 0x68, 0x6a, 0x73, 0x80, 0xe0, 0xe2, 0xec, 0xf0}, {0x21, 0x28, 0x31, 0x41, 0x44, 0x51, 0x60, 0x65, 0x67, 0x69, 0x6b, 0x72, 0x81, 0xe1, 0xe3, 0xed, 0xf1}, {0x22, 0x2b, 0x32, 0x42, 0x47, 0x52, 0x63, 0x64, 0x66, 0x68, 0x6a, 0x71, 0x82, 0xe0, 0xe2, 0xee, 0xf2}, {0x23, 0x2a, 0x33, 0x43, 0x46, 0x53, 0x62, 0x65, 0x67, 0x69, 0x6b, 0x70, 0x83, 0xe1, 0xe3, 0xef, 0xf3}, {0x24, 0x2d, 0x34, 0x41, 0x44, 0x54, 0x60, 0x62, 0x65, 0x6c, 0x6e, 0x77, 0x84, 0xe4, 0xe6, 0xe8, 0xf4}, {0x25, 0x2c, 0x35, 0x40, 0x45, 0x55, 0x61, 0x63, 0x64, 0x6d, 0x6f, 0x76, 0x85, 0xe5, 0xe7, 0xe9, 0xf5}, {0x26, 0x2f, 0x36, 0x43, 0x46, 0x56, 0x60, 0x62, 0x67, 0x6c, 0x6e, 0x75, 0x86, 0xe4, 0xe6, 0xea, 0xf6}, {0x27, 0x2e, 0x37, 0x42, 0x47, 0x57, 0x61, 0x63, 0x66, 0x6d, 0x6f, 0x74, 0x87, 0xe5, 0xe7, 0xeb, 0xf7}, {0x21, 0x28, 0x38, 0x48, 0x4d, 0x58, 0x60, 0x62, 0x69, 0x6c, 0x6e, 0x7b, 0x88, 0xe4, 0xe8, 0xea, 0xf8}, {0x20, 0x29, 0x39, 0x49, 0x4c, 0x59, 0x61, 0x63, 0x68, 0x6d, 0x6f, 0x7a, 0x89, 0xe5, 0xe9, 0xeb, 0xf9}, {0x23, 0x2a, 0x3a, 0x4a, 0x4f, 0x5a, 0x60, 0x62, 0x6b, 0x6c, 0x6e, 0x79, 0x8a, 0xe6, 0xe8, 0xea, 0xfa}, {0x22, 0x2b, 0x3b, 0x4b, 0x4e, 0x5b, 0x61, 0x63, 0x6a, 0x6d, 0x6f, 0x78, 0x8b, 0xe7, 0xe9, 0xeb, 0xfb}, {0x25, 0x2c, 0x3c, 0x49, 0x4c, 0x5c, 0x64, 0x66, 0x68, 0x6a, 0x6d, 0x7f, 0x8c, 0xe0, 0xec, 0xee, 0xfc}, {0x24, 0x2d, 0x3d, 0x48, 0x4d, 0x5d, 0x65, 0x67, 0x69, 0x6b, 0x6c, 0x7e, 0x8d, 0xe1, 0xed, 0xef, 0xfd}, {0x27, 0x2e, 0x3e, 0x4b, 0x4e, 0x5e, 0x64, 0x66, 0x68, 0x6a, 0x6f, 0x7d, 0x8e, 0xe2, 0xec, 0xee, 0xfe}, {0x26, 0x2f, 0x3f, 0x4a, 0x4f, 0x5f, 0x65, 0x67, 0x69, 0x6b, 0x6e, 0x7c, 0x8f, 0xe3, 0xed, 0xef, 0xff}, {0x20, 0x30, 0x39, 0x40, 0x50, 0x55, 0x63, 0x71, 0x74, 0x76, 0x78, 0x7a, 0x90, 0xe0, 0xf0, 0xf2, 0xfc}, {0x21, 0x31, 0x38, 0x41, 0x51, 0x54, 0x62, 0x70, 0x75, 0x77, 0x79, 0x7b, 0x91, 0xe1, 0xf1, 0xf3, 0xfd}, {0x22, 0x32, 0x3b, 0x42, 0x52, 0x57, 0x61, 0x73, 0x74, 0x76, 0x78, 0x7a, 0x92, 0xe2, 0xf0, 0xf2, 0xfe}, {0x23, 0x33, 0x3a, 0x43, 0x53, 0x56, 0x60, 0x72, 0x75, 0x77, 0x79, 0x7b, 0x93, 0xe3, 0xf1, 0xf3, 0xff}, {0x24, 0x34, 0x3d, 0x44, 0x51, 0x54, 0x67, 0x70, 0x72, 0x75, 0x7c, 0x7e, 0x94, 0xe4, 0xf4, 0xf6, 0xf8}, {0x25, 0x35, 0x3c, 0x45, 0x50, 0x55, 0x66, 0x71, 0x73, 0x74, 0x7d, 0x7f, 0x95, 0xe5, 0xf5, 0xf7, 0xf9}, {0x26, 0x36, 0x3f, 0x46, 0x53, 0x56, 0x65, 0x70, 0x72, 0x77, 0x7c, 0x7e, 0x96, 0xe6, 0xf4, 0xf6, 0xfa}, {0x27, 0x37, 0x3e, 0x47, 0x52, 0x57, 0x64, 0x71, 0x73, 0x76, 0x7d, 0x7f, 0x97, 0xe7, 0xf5, 0xf7, 0xfb}, {0x28, 0x31, 0x38, 0x48, 0x58, 0x5d, 0x6b, 0x70, 0x72, 0x79, 0x7c, 0x7e, 0x98, 0xe8, 0xf4, 0xf8, 0xfa}, {0x29, 0x30, 0x39, 0x49, 0x59, 0x5c, 0x6a, 0x71, 0x73, 0x78, 0x7d, 0x7f, 0x99, 0xe9, 0xf5, 0xf9, 0xfb}, {0x2a, 0x33, 0x3a, 0x4a, 0x5a, 0x5f, 0x69, 0x70, 0x72, 0x7b, 0x7c, 0x7e, 0x9a, 0xea, 0xf6, 0xf8, 0xfa}, {0x2b, 0x32, 0x3b, 0x4b, 0x5b, 0x5e, 0x68, 0x71, 0x73, 0x7a, 0x7d, 0x7f, 0x9b, 0xeb, 0xf7, 0xf9, 0xfb}, {0x2c, 0x35, 0x3c, 0x4c, 0x59, 0x5c, 0x6f, 0x74, 0x76, 0x78, 0x7a, 0x7d, 0x9c, 0xec, 0xf0, 0xfc, 0xfe}, {0x2d, 0x34, 0x3d, 0x4d, 0x58, 0x5d, 0x6e, 0x75, 0x77, 0x79, 0x7b, 0x7c, 0x9d, 0xed, 0xf1, 0xfd, 0xff}, {0x2e, 0x37, 0x3e, 0x4e, 0x5b, 0x5e, 0x6d, 0x74, 0x76, 0x78, 0x7a, 0x7f, 0x9e, 0xee, 0xf2, 0xfc, 0xfe}, {0x2f, 0x36, 0x3f, 0x4f, 0x5a, 0x5f, 0x6c, 0x75, 0x77, 0x79, 0x7b, 0x7e, 0x9f, 0xef, 0xf3, 0xfd, 0xff}, {0x00, 0x02, 0x0c, 0x10, 0x60, 0x81, 0x84, 0x86, 0x88, 0x8a, 0x93, 0xa0, 0xa5, 0xb0, 0xc0, 0xc9, 0xd0}, {0x01, 0x03, 0x0d, 0x11, 0x61, 0x80, 0x85, 0x87, 0x89, 0x8b, 0x92, 0xa1, 0xa4, 0xb1, 0xc1, 0xc8, 0xd1}, {0x00, 0x02, 0x0e, 0x12, 0x62, 0x83, 0x84, 0x86, 0x88, 0x8a, 0x91, 0xa2, 0xa7, 0xb2, 0xc2, 0xcb, 0xd2}, {0x01, 0x03, 0x0f, 0x13, 0x63, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x90, 0xa3, 0xa6, 0xb3, 0xc3, 0xca, 0xd3}, {0x04, 0x06, 0x08, 0x14, 0x64, 0x80, 0x82, 0x85, 0x8c, 0x8e, 0x97, 0xa1, 0xa4, 0xb4, 0xc4, 0xcd, 0xd4}, {0x05, 0x07, 0x09, 0x15, 0x65, 0x81, 0x83, 0x84, 0x8d, 0x8f, 0x96, 0xa0, 0xa5, 0xb5, 0xc5, 0xcc, 0xd5}, {0x04, 0x06, 0x0a, 0x16, 0x66, 0x80, 0x82, 0x87, 0x8c, 0x8e, 0x95, 0xa3, 0xa6, 0xb6, 0xc6, 0xcf, 0xd6}, {0x05, 0x07, 0x0b, 0x17, 0x67, 0x81, 0x83, 0x86, 0x8d, 0x8f, 0x94, 0xa2, 0xa7, 0xb7, 0xc7, 0xce, 0xd7}, {0x04, 0x08, 0x0a, 0x18, 0x68, 0x80, 0x82, 0x89, 0x8c, 0x8e, 0x9b, 0xa8, 0xad, 0xb8, 0xc1, 0xc8, 0xd8}, {0x05, 0x09, 0x0b, 0x19, 0x69, 0x81, 0x83, 0x88, 0x8d, 0x8f, 0x9a, 0xa9, 0xac, 0xb9, 0xc0, 0xc9, 0xd9}, {0x06, 0x08, 0x0a, 0x1a, 0x6a, 0x80, 0x82, 0x8b, 0x8c, 0x8e, 0x99, 0xaa, 0xaf, 0xba, 0xc3, 0xca, 0xda}, {0x07, 0x09, 0x0b, 0x1b, 0x6b, 0x81, 0x83, 0x8a, 0x8d, 0x8f, 0x98, 0xab, 0xae, 0xbb, 0xc2, 0xcb, 0xdb}, {0x00, 0x0c, 0x0e, 0x1c, 0x6c, 0x84, 0x86, 0x88, 0x8a, 0x8d, 0x9f, 0xa9, 0xac, 0xbc, 0xc5, 0xcc, 0xdc}, {0x01, 0x0d, 0x0f, 0x1d, 0x6d, 0x85, 0x87, 0x89, 0x8b, 0x8c, 0x9e, 0xa8, 0xad, 0xbd, 0xc4, 0xcd, 0xdd}, {0x02, 0x0c, 0x0e, 0x1e, 0x6e, 0x84, 0x86, 0x88, 0x8a, 0x8f, 0x9d, 0xab, 0xae, 0xbe, 0xc7, 0xce, 0xde}, {0x03, 0x0d, 0x0f, 0x1f, 0x6f, 0x85, 0x87, 0x89, 0x8b, 0x8e, 0x9c, 0xaa, 0xaf, 0xbf, 0xc6, 0xcf, 0xdf}, {0x00, 0x10, 0x12, 0x1c, 0x70, 0x83, 0x91, 0x94, 0x96, 0x98, 0x9a, 0xa0, 0xb0, 0xb5, 0xc0, 0xd0, 0xd9}, {0x01, 0x11, 0x13, 0x1d, 0x71, 0x82, 0x90, 0x95, 0x97, 0x99, 0x9b, 0xa1, 0xb1, 0xb4, 0xc1, 0xd1, 0xd8}, {0x02, 0x10, 0x12, 0x1e, 0x72, 0x81, 0x93, 0x94, 0x96, 0x98, 0x9a, 0xa2, 0xb2, 0xb7, 0xc2, 0xd2, 0xdb}, {0x03, 0x11, 0x13, 0x1f, 0x73, 0x80, 0x92, 0x95, 0x97, 0x99, 0x9b, 0xa3, 0xb3, 0xb6, 0xc3, 0xd3, 0xda}, {0x04, 0x14, 0x16, 0x18, 0x74, 0x87, 0x90, 0x92, 0x95, 0x9c, 0x9e, 0xa4, 0xb1, 0xb4, 0xc4, 0xd4, 0xdd}, {0x05, 0x15, 0x17, 0x19, 0x75, 0x86, 0x91, 0x93, 0x94, 0x9d, 0x9f, 0xa5, 0xb0, 0xb5, 0xc5, 0xd5, 0xdc}, {0x06, 0x14, 0x16, 0x1a, 0x76, 0x85, 0x90, 0x92, 0x97, 0x9c, 0x9e, 0xa6, 0xb3, 0xb6, 0xc6, 0xd6, 0xdf}, {0x07, 0x15, 0x17, 0x1b, 0x77, 0x84, 0x91, 0x93, 0x96, 0x9d, 0x9f, 0xa7, 0xb2, 0xb7, 0xc7, 0xd7, 0xde}, {0x08, 0x14, 0x18, 0x1a, 0x78, 0x8b, 0x90, 0x92, 0x99, 0x9c, 0x9e, 0xa8, 0xb8, 0xbd, 0xc8, 0xd1, 0xd8}, {0x09, 0x15, 0x19, 0x1b, 0x79, 0x8a, 0x91, 0x93, 0x98, 0x9d, 0x9f, 0xa9, 0xb9, 0xbc, 0xc9, 0xd0, 0xd9}, {0x0a, 0x16, 0x18, 0x1a, 0x7a, 0x89, 0x90, 0x92, 0x9b, 0x9c, 0x9e, 0xaa, 0xba, 0xbf, 0xca, 0xd3, 0xda}, {0x0b, 0x17, 0x19, 0x1b, 0x7b, 0x88, 0x91, 0x93, 0x9a, 0x9d, 0x9f, 0xab, 0xbb, 0xbe, 0xcb, 0xd2, 0xdb}, {0x0c, 0x10, 0x1c, 0x1e, 0x7c, 0x8f, 0x94, 0x96, 0x98, 0x9a, 0x9d, 0xac, 0xb9, 0xbc, 0xcc, 0xd5, 0xdc}, {0x0d, 0x11, 0x1d, 0x1f, 0x7d, 0x8e, 0x95, 0x97, 0x99, 0x9b, 0x9c, 0xad, 0xb8, 0xbd, 0xcd, 0xd4, 0xdd}, {0x0e, 0x12, 0x1c, 0x1e, 0x7e, 0x8d, 0x94, 0x96, 0x98, 0x9a, 0x9f, 0xae, 0xbb, 0xbe, 0xce, 0xd7, 0xde}, {0x0f, 0x13, 0x1d, 0x1f, 0x7f, 0x8c, 0x95, 0x97, 0x99, 0x9b, 0x9e, 0xaf, 0xba, 0xbf, 0xcf, 0xd6, 0xdf}, {0x20, 0x22, 0x2c, 0x30, 0x40, 0x80, 0x85, 0x90, 0xa1, 0xa4, 0xa6, 0xa8, 0xaa, 0xb3, 0xe0, 0xe9, 0xf0}, {0x21, 0x23, 0x2d, 0x31, 0x41, 0x81, 0x84, 0x91, 0xa0, 0xa5, 0xa7, 0xa9, 0xab, 0xb2, 0xe1, 0xe8, 0xf1}, {0x20, 0x22, 0x2e, 0x32, 0x42, 0x82, 0x87, 0x92, 0xa3, 0xa4, 0xa6, 0xa8, 0xaa, 0xb1, 0xe2, 0xeb, 0xf2}, {0x21, 0x23, 0x2f, 0x33, 0x43, 0x83, 0x86, 0x93, 0xa2, 0xa5, 0xa7, 0xa9, 0xab, 0xb0, 0xe3, 0xea, 0xf3}, {0x24, 0x26, 0x28, 0x34, 0x44, 0x81, 0x84, 0x94, 0xa0, 0xa2, 0xa5, 0xac, 0xae, 0xb7, 0xe4, 0xed, 0xf4}, {0x25, 0x27, 0x29, 0x35, 0x45, 0x80, 0x85, 0x95, 0xa1, 0xa3, 0xa4, 0xad, 0xaf, 0xb6, 0xe5, 0xec, 0xf5}, {0x24, 0x26, 0x2a, 0x36, 0x46, 0x83, 0x86, 0x96, 0xa0, 0xa2, 0xa7, 0xac, 0xae, 0xb5, 0xe6, 0xef, 0xf6}, {0x25, 0x27, 0x2b, 0x37, 0x47, 0x82, 0x87, 0x97, 0xa1, 0xa3, 0xa6, 0xad, 0xaf, 0xb4, 0xe7, 0xee, 0xf7}, {0x24, 0x28, 0x2a, 0x38, 0x48, 0x88, 0x8d, 0x98, 0xa0, 0xa2, 0xa9, 0xac, 0xae, 0xbb, 0xe1, 0xe8, 0xf8}, {0x25, 0x29, 0x2b, 0x39, 0x49, 0x89, 0x8c, 0x99, 0xa1, 0xa3, 0xa8, 0xad, 0xaf, 0xba, 0xe0, 0xe9, 0xf9}, {0x26, 0x28, 0x2a, 0x3a, 0x4a, 0x8a, 0x8f, 0x9a, 0xa0, 0xa2, 0xab, 0xac, 0xae, 0xb9, 0xe3, 0xea, 0xfa}, {0x27, 0x29, 0x2b, 0x3b, 0x4b, 0x8b, 0x8e, 0x9b, 0xa1, 0xa3, 0xaa, 0xad, 0xaf, 0xb8, 0xe2, 0xeb, 0xfb}, {0x20, 0x2c, 0x2e, 0x3c, 0x4c, 0x89, 0x8c, 0x9c, 0xa4, 0xa6, 0xa8, 0xaa, 0xad, 0xbf, 0xe5, 0xec, 0xfc}, {0x21, 0x2d, 0x2f, 0x3d, 0x4d, 0x88, 0x8d, 0x9d, 0xa5, 0xa7, 0xa9, 0xab, 0xac, 0xbe, 0xe4, 0xed, 0xfd}, {0x22, 0x2c, 0x2e, 0x3e, 0x4e, 0x8b, 0x8e, 0x9e, 0xa4, 0xa6, 0xa8, 0xaa, 0xaf, 0xbd, 0xe7, 0xee, 0xfe}, {0x23, 0x2d, 0x2f, 0x3f, 0x4f, 0x8a, 0x8f, 0x9f, 0xa5, 0xa7, 0xa9, 0xab, 0xae, 0xbc, 0xe6, 0xef, 0xff}, {0x20, 0x30, 0x32, 0x3c, 0x50, 0x80, 0x90, 0x95, 0xa3, 0xb1, 0xb4, 0xb6, 0xb8, 0xba, 0xe0, 0xf0, 0xf9}, {0x21, 0x31, 0x33, 0x3d, 0x51, 0x81, 0x91, 0x94, 0xa2, 0xb0, 0xb5, 0xb7, 0xb9, 0xbb, 0xe1, 0xf1, 0xf8}, {0x22, 0x30, 0x32, 0x3e, 0x52, 0x82, 0x92, 0x97, 0xa1, 0xb3, 0xb4, 0xb6, 0xb8, 0xba, 0xe2, 0xf2, 0xfb}, {0x23, 0x31, 0x33, 0x3f, 0x53, 0x83, 0x93, 0x96, 0xa0, 0xb2, 0xb5, 0xb7, 0xb9, 0xbb, 0xe3, 0xf3, 0xfa}, {0x24, 0x34, 0x36, 0x38, 0x54, 0x84, 0x91, 0x94, 0xa7, 0xb0, 0xb2, 0xb5, 0xbc, 0xbe, 0xe4, 0xf4, 0xfd}, {0x25, 0x35, 0x37, 0x39, 0x55, 0x85, 0x90, 0x95, 0xa6, 0xb1, 0xb3, 0xb4, 0xbd, 0xbf, 0xe5, 0xf5, 0xfc}, {0x26, 0x34, 0x36, 0x3a, 0x56, 0x86, 0x93, 0x96, 0xa5, 0xb0, 0xb2, 0xb7, 0xbc, 0xbe, 0xe6, 0xf6, 0xff}, {0x27, 0x35, 0x37, 0x3b, 0x57, 0x87, 0x92, 0x97, 0xa4, 0xb1, 0xb3, 0xb6, 0xbd, 0xbf, 0xe7, 0xf7, 0xfe}, {0x28, 0x34, 0x38, 0x3a, 0x58, 0x88, 0x98, 0x9d, 0xab, 0xb0, 0xb2, 0xb9, 0xbc, 0xbe, 0xe8, 0xf1, 0xf8}, {0x29, 0x35, 0x39, 0x3b, 0x59, 0x89, 0x99, 0x9c, 0xaa, 0xb1, 0xb3, 0xb8, 0xbd, 0xbf, 0xe9, 0xf0, 0xf9}, {0x2a, 0x36, 0x38, 0x3a, 0x5a, 0x8a, 0x9a, 0x9f, 0xa9, 0xb0, 0xb2, 0xbb, 0xbc, 0xbe, 0xea, 0xf3, 0xfa}, {0x2b, 0x37, 0x39, 0x3b, 0x5b, 0x8b, 0x9b, 0x9e, 0xa8, 0xb1, 0xb3, 0xba, 0xbd, 0xbf, 0xeb, 0xf2, 0xfb}, {0x2c, 0x30, 0x3c, 0x3e, 0x5c, 0x8c, 0x99, 0x9c, 0xaf, 0xb4, 0xb6, 0xb8, 0xba, 0xbd, 0xec, 0xf5, 0xfc}, {0x2d, 0x31, 0x3d, 0x3f, 0x5d, 0x8d, 0x98, 0x9d, 0xae, 0xb5, 0xb7, 0xb9, 0xbb, 0xbc, 0xed, 0xf4, 0xfd}, {0x2e, 0x32, 0x3c, 0x3e, 0x5e, 0x8e, 0x9b, 0x9e, 0xad, 0xb4, 0xb6, 0xb8, 0xba, 0xbf, 0xee, 0xf7, 0xfe}, {0x2f, 0x33, 0x3d, 0x3f, 0x5f, 0x8f, 0x9a, 0x9f, 0xac, 0xb5, 0xb7, 0xb9, 0xbb, 0xbe, 0xef, 0xf6, 0xff}, {0x20, 0x40, 0x42, 0x4c, 0x50, 0x80, 0x89, 0x90, 0xc1, 0xc4, 0xc6, 0xc8, 0xca, 0xd3, 0xe0, 0xe5, 0xf0}, {0x21, 0x41, 0x43, 0x4d, 0x51, 0x81, 0x88, 0x91, 0xc0, 0xc5, 0xc7, 0xc9, 0xcb, 0xd2, 0xe1, 0xe4, 0xf1}, {0x22, 0x40, 0x42, 0x4e, 0x52, 0x82, 0x8b, 0x92, 0xc3, 0xc4, 0xc6, 0xc8, 0xca, 0xd1, 0xe2, 0xe7, 0xf2}, {0x23, 0x41, 0x43, 0x4f, 0x53, 0x83, 0x8a, 0x93, 0xc2, 0xc5, 0xc7, 0xc9, 0xcb, 0xd0, 0xe3, 0xe6, 0xf3}, {0x24, 0x44, 0x46, 0x48, 0x54, 0x84, 0x8d, 0x94, 0xc0, 0xc2, 0xc5, 0xcc, 0xce, 0xd7, 0xe1, 0xe4, 0xf4}, {0x25, 0x45, 0x47, 0x49, 0x55, 0x85, 0x8c, 0x95, 0xc1, 0xc3, 0xc4, 0xcd, 0xcf, 0xd6, 0xe0, 0xe5, 0xf5}, {0x26, 0x44, 0x46, 0x4a, 0x56, 0x86, 0x8f, 0x96, 0xc0, 0xc2, 0xc7, 0xcc, 0xce, 0xd5, 0xe3, 0xe6, 0xf6}, {0x27, 0x45, 0x47, 0x4b, 0x57, 0x87, 0x8e, 0x97, 0xc1, 0xc3, 0xc6, 0xcd, 0xcf, 0xd4, 0xe2, 0xe7, 0xf7}, {0x28, 0x44, 0x48, 0x4a, 0x58, 0x81, 0x88, 0x98, 0xc0, 0xc2, 0xc9, 0xcc, 0xce, 0xdb, 0xe8, 0xed, 0xf8}, {0x29, 0x45, 0x49, 0x4b, 0x59, 0x80, 0x89, 0x99, 0xc1, 0xc3, 0xc8, 0xcd, 0xcf, 0xda, 0xe9, 0xec, 0xf9}, {0x2a, 0x46, 0x48, 0x4a, 0x5a, 0x83, 0x8a, 0x9a, 0xc0, 0xc2, 0xcb, 0xcc, 0xce, 0xd9, 0xea, 0xef, 0xfa}, {0x2b, 0x47, 0x49, 0x4b, 0x5b, 0x82, 0x8b, 0x9b, 0xc1, 0xc3, 0xca, 0xcd, 0xcf, 0xd8, 0xeb, 0xee, 0xfb}, {0x2c, 0x40, 0x4c, 0x4e, 0x5c, 0x85, 0x8c, 0x9c, 0xc4, 0xc6, 0xc8, 0xca, 0xcd, 0xdf, 0xe9, 0xec, 0xfc}, {0x2d, 0x41, 0x4d, 0x4f, 0x5d, 0x84, 0x8d, 0x9d, 0xc5, 0xc7, 0xc9, 0xcb, 0xcc, 0xde, 0xe8, 0xed, 0xfd}, {0x2e, 0x42, 0x4c, 0x4e, 0x5e, 0x87, 0x8e, 0x9e, 0xc4, 0xc6, 0xc8, 0xca, 0xcf, 0xdd, 0xeb, 0xee, 0xfe}, {0x2f, 0x43, 0x4d, 0x4f, 0x5f, 0x86, 0x8f, 0x9f, 0xc5, 0xc7, 0xc9, 0xcb, 0xce, 0xdc, 0xea, 0xef, 0xff}, {0x30, 0x40, 0x50, 0x52, 0x5c, 0x80, 0x90, 0x99, 0xc3, 0xd1, 0xd4, 0xd6, 0xd8, 0xda, 0xe0, 0xf0, 0xf5}, {0x31, 0x41, 0x51, 0x53, 0x5d, 0x81, 0x91, 0x98, 0xc2, 0xd0, 0xd5, 0xd7, 0xd9, 0xdb, 0xe1, 0xf1, 0xf4}, {0x32, 0x42, 0x50, 0x52, 0x5e, 0x82, 0x92, 0x9b, 0xc1, 0xd3, 0xd4, 0xd6, 0xd8, 0xda, 0xe2, 0xf2, 0xf7}, {0x33, 0x43, 0x51, 0x53, 0x5f, 0x83, 0x93, 0x9a, 0xc0, 0xd2, 0xd5, 0xd7, 0xd9, 0xdb, 0xe3, 0xf3, 0xf6}, {0x34, 0x44, 0x54, 0x56, 0x58, 0x84, 0x94, 0x9d, 0xc7, 0xd0, 0xd2, 0xd5, 0xdc, 0xde, 0xe4, 0xf1, 0xf4}, {0x35, 0x45, 0x55, 0x57, 0x59, 0x85, 0x95, 0x9c, 0xc6, 0xd1, 0xd3, 0xd4, 0xdd, 0xdf, 0xe5, 0xf0, 0xf5}, {0x36, 0x46, 0x54, 0x56, 0x5a, 0x86, 0x96, 0x9f, 0xc5, 0xd0, 0xd2, 0xd7, 0xdc, 0xde, 0xe6, 0xf3, 0xf6}, {0x37, 0x47, 0x55, 0x57, 0x5b, 0x87, 0x97, 0x9e, 0xc4, 0xd1, 0xd3, 0xd6, 0xdd, 0xdf, 0xe7, 0xf2, 0xf7}, {0x38, 0x48, 0x54, 0x58, 0x5a, 0x88, 0x91, 0x98, 0xcb, 0xd0, 0xd2, 0xd9, 0xdc, 0xde, 0xe8, 0xf8, 0xfd}, {0x39, 0x49, 0x55, 0x59, 0x5b, 0x89, 0x90, 0x99, 0xca, 0xd1, 0xd3, 0xd8, 0xdd, 0xdf, 0xe9, 0xf9, 0xfc}, {0x3a, 0x4a, 0x56, 0x58, 0x5a, 0x8a, 0x93, 0x9a, 0xc9, 0xd0, 0xd2, 0xdb, 0xdc, 0xde, 0xea, 0xfa, 0xff}, {0x3b, 0x4b, 0x57, 0x59, 0x5b, 0x8b, 0x92, 0x9b, 0xc8, 0xd1, 0xd3, 0xda, 0xdd, 0xdf, 0xeb, 0xfb, 0xfe}, {0x3c, 0x4c, 0x50, 0x5c, 0x5e, 0x8c, 0x95, 0x9c, 0xcf, 0xd4, 0xd6, 0xd8, 0xda, 0xdd, 0xec, 0xf9, 0xfc}, {0x3d, 0x4d, 0x51, 0x5d, 0x5f, 0x8d, 0x94, 0x9d, 0xce, 0xd5, 0xd7, 0xd9, 0xdb, 0xdc, 0xed, 0xf8, 0xfd}, {0x3e, 0x4e, 0x52, 0x5c, 0x5e, 0x8e, 0x97, 0x9e, 0xcd, 0xd4, 0xd6, 0xd8, 0xda, 0xdf, 0xee, 0xfb, 0xfe}, {0x3f, 0x4f, 0x53, 0x5d, 0x5f, 0x8f, 0x96, 0x9f, 0xcc, 0xd5, 0xd7, 0xd9, 0xdb, 0xde, 0xef, 0xfa, 0xff}, {0x00, 0x60, 0x62, 0x6c, 0x70, 0xa0, 0xa9, 0xb0, 0xc0, 0xc5, 0xd0, 0xe1, 0xe4, 0xe6, 0xe8, 0xea, 0xf3}, {0x01, 0x61, 0x63, 0x6d, 0x71, 0xa1, 0xa8, 0xb1, 0xc1, 0xc4, 0xd1, 0xe0, 0xe5, 0xe7, 0xe9, 0xeb, 0xf2}, {0x02, 0x60, 0x62, 0x6e, 0x72, 0xa2, 0xab, 0xb2, 0xc2, 0xc7, 0xd2, 0xe3, 0xe4, 0xe6, 0xe8, 0xea, 0xf1}, {0x03, 0x61, 0x63, 0x6f, 0x73, 0xa3, 0xaa, 0xb3, 0xc3, 0xc6, 0xd3, 0xe2, 0xe5, 0xe7, 0xe9, 0xeb, 0xf0}, {0x04, 0x64, 0x66, 0x68, 0x74, 0xa4, 0xad, 0xb4, 0xc1, 0xc4, 0xd4, 0xe0, 0xe2, 0xe5, 0xec, 0xee, 0xf7}, {0x05, 0x65, 0x67, 0x69, 0x75, 0xa5, 0xac, 0xb5, 0xc0, 0xc5, 0xd5, 0xe1, 0xe3, 0xe4, 0xed, 0xef, 0xf6}, {0x06, 0x64, 0x66, 0x6a, 0x76, 0xa6, 0xaf, 0xb6, 0xc3, 0xc6, 0xd6, 0xe0, 0xe2, 0xe7, 0xec, 0xee, 0xf5}, {0x07, 0x65, 0x67, 0x6b, 0x77, 0xa7, 0xae, 0xb7, 0xc2, 0xc7, 0xd7, 0xe1, 0xe3, 0xe6, 0xed, 0xef, 0xf4}, {0x08, 0x64, 0x68, 0x6a, 0x78, 0xa1, 0xa8, 0xb8, 0xc8, 0xcd, 0xd8, 0xe0, 0xe2, 0xe9, 0xec, 0xee, 0xfb}, {0x09, 0x65, 0x69, 0x6b, 0x79, 0xa0, 0xa9, 0xb9, 0xc9, 0xcc, 0xd9, 0xe1, 0xe3, 0xe8, 0xed, 0xef, 0xfa}, {0x0a, 0x66, 0x68, 0x6a, 0x7a, 0xa3, 0xaa, 0xba, 0xca, 0xcf, 0xda, 0xe0, 0xe2, 0xeb, 0xec, 0xee, 0xf9}, {0x0b, 0x67, 0x69, 0x6b, 0x7b, 0xa2, 0xab, 0xbb, 0xcb, 0xce, 0xdb, 0xe1, 0xe3, 0xea, 0xed, 0xef, 0xf8}, {0x0c, 0x60, 0x6c, 0x6e, 0x7c, 0xa5, 0xac, 0xbc, 0xc9, 0xcc, 0xdc, 0xe4, 0xe6, 0xe8, 0xea, 0xed, 0xff}, {0x0d, 0x61, 0x6d, 0x6f, 0x7d, 0xa4, 0xad, 0xbd, 0xc8, 0xcd, 0xdd, 0xe5, 0xe7, 0xe9, 0xeb, 0xec, 0xfe}, {0x0e, 0x62, 0x6c, 0x6e, 0x7e, 0xa7, 0xae, 0xbe, 0xcb, 0xce, 0xde, 0xe4, 0xe6, 0xe8, 0xea, 0xef, 0xfd}, {0x0f, 0x63, 0x6d, 0x6f, 0x7f, 0xa6, 0xaf, 0xbf, 0xca, 0xcf, 0xdf, 0xe5, 0xe7, 0xe9, 0xeb, 0xee, 0xfc}, {0x10, 0x60, 0x70, 0x72, 0x7c, 0xa0, 0xb0, 0xb9, 0xc0, 0xd0, 0xd5, 0xe3, 0xf1, 0xf4, 0xf6, 0xf8, 0xfa}, {0x11, 0x61, 0x71, 0x73, 0x7d, 0xa1, 0xb1, 0xb8, 0xc1, 0xd1, 0xd4, 0xe2, 0xf0, 0xf5, 0xf7, 0xf9, 0xfb}, {0x12, 0x62, 0x70, 0x72, 0x7e, 0xa2, 0xb2, 0xbb, 0xc2, 0xd2, 0xd7, 0xe1, 0xf3, 0xf4, 0xf6, 0xf8, 0xfa}, {0x13, 0x63, 0x71, 0x73, 0x7f, 0xa3, 0xb3, 0xba, 0xc3, 0xd3, 0xd6, 0xe0, 0xf2, 0xf5, 0xf7, 0xf9, 0xfb}, {0x14, 0x64, 0x74, 0x76, 0x78, 0xa4, 0xb4, 0xbd, 0xc4, 0xd1, 0xd4, 0xe7, 0xf0, 0xf2, 0xf5, 0xfc, 0xfe}, {0x15, 0x65, 0x75, 0x77, 0x79, 0xa5, 0xb5, 0xbc, 0xc5, 0xd0, 0xd5, 0xe6, 0xf1, 0xf3, 0xf4, 0xfd, 0xff}, {0x16, 0x66, 0x74, 0x76, 0x7a, 0xa6, 0xb6, 0xbf, 0xc6, 0xd3, 0xd6, 0xe5, 0xf0, 0xf2, 0xf7, 0xfc, 0xfe}, {0x17, 0x67, 0x75, 0x77, 0x7b, 0xa7, 0xb7, 0xbe, 0xc7, 0xd2, 0xd7, 0xe4, 0xf1, 0xf3, 0xf6, 0xfd, 0xff}, {0x18, 0x68, 0x74, 0x78, 0x7a, 0xa8, 0xb1, 0xb8, 0xc8, 0xd8, 0xdd, 0xeb, 0xf0, 0xf2, 0xf9, 0xfc, 0xfe}, {0x19, 0x69, 0x75, 0x79, 0x7b, 0xa9, 0xb0, 0xb9, 0xc9, 0xd9, 0xdc, 0xea, 0xf1, 0xf3, 0xf8, 0xfd, 0xff}, {0x1a, 0x6a, 0x76, 0x78, 0x7a, 0xaa, 0xb3, 0xba, 0xca, 0xda, 0xdf, 0xe9, 0xf0, 0xf2, 0xfb, 0xfc, 0xfe}, {0x1b, 0x6b, 0x77, 0x79, 0x7b, 0xab, 0xb2, 0xbb, 0xcb, 0xdb, 0xde, 0xe8, 0xf1, 0xf3, 0xfa, 0xfd, 0xff}, {0x1c, 0x6c, 0x70, 0x7c, 0x7e, 0xac, 0xb5, 0xbc, 0xcc, 0xd9, 0xdc, 0xef, 0xf4, 0xf6, 0xf8, 0xfa, 0xfd}, {0x1d, 0x6d, 0x71, 0x7d, 0x7f, 0xad, 0xb4, 0xbd, 0xcd, 0xd8, 0xdd, 0xee, 0xf5, 0xf7, 0xf9, 0xfb, 0xfc}, {0x1e, 0x6e, 0x72, 0x7c, 0x7e, 0xae, 0xb7, 0xbe, 0xce, 0xdb, 0xde, 0xed, 0xf4, 0xf6, 0xf8, 0xfa, 0xff}, {0x1f, 0x6f, 0x73, 0x7d, 0x7f, 0xaf, 0xb6, 0xbf, 0xcf, 0xda, 0xdf, 0xec, 0xf5, 0xf7, 0xf9, 0xfb, 0xfe}}; liquid-dsp-1.7.0/src/fec/src/fec_hamming1511.c000066400000000000000000000121671474751757600206540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_HAMMING1511 0 // // Hamming(15,11) code // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8 and only including // data bits 1:11) // // parity bit P1 x x . x x . x . x . x = .110 1101 0101 // coverage P2 x . x x . x x . . x x = .101 1011 0011 // P4 . x x x . . . x x x x = .011 1000 1111 // P8 . . . . x x x x x x x = .000 0111 1111 #define HAMMING_M1 0x06d5 // .110 1101 0101 #define HAMMING_M2 0x05b3 // .101 1011 0011 #define HAMMING_M4 0x038f // .011 1000 1111 #define HAMMING_M8 0x007f // .000 0111 1111 // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see first figure, above). #define HAMMING_S1 0x5555 // .101 0101 0101 0101 #define HAMMING_S2 0x3333 // .011 0011 0011 0011 #define HAMMING_S4 0x0f0f // .000 1111 0000 1111 #define HAMMING_S8 0x00ff // .000 0000 1111 1111 unsigned int fec_hamming1511_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<11)) { liquid_error(LIQUID_EICONFIG,"fec_hamming_encode(), input symbol too large"); return 0; } // compute parity bits unsigned int p1 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M1); unsigned int p2 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M2); unsigned int p4 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M4); unsigned int p8 = liquid_bdotprod_uint16(_sym_dec, HAMMING_M8); #if DEBUG_FEC_HAMMING1511 printf("parity bits (p1,p2,p4,p8) : (%1u,%1u,%1u,%1u)\n", p1, p2, p4, p8); #endif // encode symbol by inserting parity bits with data bits to // make a 15-bit symbol unsigned int sym_enc = ((_sym_dec & 0x007f) << 0) | ((_sym_dec & 0x0380) << 1) | ((_sym_dec & 0x0400) << 2) | ( p1 << 14 ) | ( p2 << 13 ) | ( p4 << 11 ) | ( p8 << 7 ); return sym_enc; } unsigned int fec_hamming1511_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1<<15)) { liquid_error(LIQUID_EICONFIG,"fec_hamming_decode(), input symbol too large"); return 0; } // compute syndrome bits unsigned int s1 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S1); unsigned int s2 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S2); unsigned int s4 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S4); unsigned int s8 = liquid_bdotprod_uint16(_sym_enc, HAMMING_S8); // index unsigned int z = (s8<<3) | (s4<<2) | (s2<<1) | s1; #if DEBUG_FEC_HAMMING1511 printf("syndrome bits (s1,s2,s4,s8) : (%1u,%1u,%1u,%1u)\n", s1, s2, s4, s8); printf("syndrome z : %u\n", z); #endif // flip bit at this position if (z) { if (z > 15) { // if this happens there are likely too many errors // to correct; just pass without trying to do anything fprintf(stderr,"warning, fec_hamming1511_decode_symbol(), syndrome index exceeds maximum\n"); } else { //printf("error detected!\n"); _sym_enc ^= 1 << (15-z); } } // strip data bits (x) from encoded symbol with parity bits (.) // symbol: [..x. xxx. xxxx] // 0000 0000 1111 > 0x000f // 0000 1110 0000 > 0x00e0 // 0010 0000 0000 > 0x0200 // // symbol: [ -..x .xxx .xxx xxxx] // -000 0000 0xxx xxxx > 0x007f // -000 0111 0000 0000 > 0x0700 // -001 0000 0000 0000 > 0x1000 unsigned int sym_dec = ((_sym_enc & 0x007f) ) | ((_sym_enc & 0x0700) >> 1) | ((_sym_enc & 0x1000) >> 2); return sym_dec; } liquid-dsp-1.7.0/src/fec/src/fec_hamming3126.c000066400000000000000000000174061474751757600206610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.internal.h" #define DEBUG_FEC_HAMMING3126 0 // // (31,26) Hamming code // // parity bit coverage mask for encoder (collapsed version of figure // above, stripping out parity bits P1, P2, P4, P8, P16 and only including // data bits 1:26) // // bit position 3 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // * * * * * * // parity bit P1 x x . x x . x . x . x x . x . x . x . x . x . x . x = ..11 0110 1010 1101 0101 0101 0101 // coverage P2 x . x x . x x . . x x . x x . . x x . . x x . . x x = ..10 1101 1001 1011 0011 0011 0011 // P4 . x x x . . . x x x x . . . x x x x . . . . x x x x = ..01 1100 0111 1000 1111 0000 1111 // P8 . . . . x x x x x x x . . . . . . . x x x x x x x x = ..00 0011 1111 1000 0000 1111 1111 // P16 . . . . . . . . . . . x x x x x x x x x x x x x x x = ..00 0000 0000 0111 1111 1111 1111 #define HAMMING_M1 0x036AD555 // ..11 0110 1010 1101 0101 0101 0101 #define HAMMING_M2 0x02D9B333 // ..10 1101 1001 1011 0011 0011 0011 #define HAMMING_M4 0x01C78F0F // ..01 1100 0111 1000 1111 0000 1111 #define HAMMING_M8 0x003F80FF // ..00 0011 1111 1000 0000 1111 1111 #define HAMMING_M16 0x00007FFF // ..00 0000 0000 0111 1111 1111 1111 // bit position 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // * * * * * * * // parity bit P1 x . x . x . x . x . x . x . x . x . x . x . x . x . x . x . x = .101 0101 0101 0101 0101 0101 0101 0101 // coverage P2 . x x . . x x . . x x . . x x . . x x . . x x . . x x . . x x = .011 0011 0011 0011 0011 0011 0011 0011 // P4 . . . x x x x . . . . x x x x . . . . x x x x . . . . x x x x = .000 1111 0000 1111 0000 1111 0000 1111 // P8 . . . . . . . x x x x x x x x . . . . . . . . x x x x x x x x = .000 0000 1111 1111 0000 0000 1111 1111 // P16 . . . . . . . . . . . . . . . x x x x x x x x x x x x x x x x = .000 0000 0000 0000 1111 1111 1111 1111 // // parity bit coverage mask for decoder; used to compute syndromes // for decoding a received message (see figure, above). #define HAMMING_S1 0x55555555 // .101 0101 0101 0101 0101 0101 0101 0101 #define HAMMING_S2 0x33333333 // .011 0011 0011 0011 0011 0011 0011 0011 #define HAMMING_S4 0x0f0f0f0f // .000 1111 0000 1111 0000 1111 0000 1111 #define HAMMING_S8 0x00ff00ff // .000 0000 1111 1111 0000 0000 1111 1111 #define HAMMING_S16 0x0000ffff // .000 0000 0000 0000 1111 1111 1111 1111 unsigned int fec_hamming3126_encode_symbol(unsigned int _sym_dec) { // validate input if (_sym_dec >= (1<<26)) { liquid_error(LIQUID_EICONFIG,"fec_hamming_encode(), input symbol too large"); return 0; } // compute parity bits unsigned int p1 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M1); unsigned int p2 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M2); unsigned int p4 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M4); unsigned int p8 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M8); unsigned int p16 = liquid_bdotprod_uint32(_sym_dec, HAMMING_M16); #if DEBUG_FEC_HAMMING printf("parity bits (p1,p2,p4,p8,p16) : (%1u,%1u,%1u,%1u,%1u)\n", p1, p2, p4, p8, p16); #endif // encode symbol by inserting parity bits with data bits to // make a 31-bit symbol unsigned int sym_enc = ((_sym_dec & 0x00007fff) << 0) | // ..00 0000 0000 0111 1111 1111 1111 ((_sym_dec & 0x003F8000) << 1) | // ..00 0011 1111 1000 0000 0000 0000 ((_sym_dec & 0x01C00000) << 2) | // ..01 1100 0000 0000 0000 0000 0000 ((_sym_dec & 0x02000000) << 3) | // ..10 0000 0000 0000 0000 0000 0000 ( p1 << 30 ) | // 30 = 31 - 1 (position of P1) ( p2 << 29 ) | // 29 = 31 - 2 (position of P2) ( p4 << 27 ) | // 27 = 31 - 4 (position of P4) ( p8 << 23 ) | // 23 = 31 - 8 (position of P8) ( p16 << 15 ); // 15 = 31 - 16 (position of P16) return sym_enc; } unsigned int fec_hamming3126_decode_symbol(unsigned int _sym_enc) { // validate input if (_sym_enc >= (1u<<31)) { liquid_error(LIQUID_EICONFIG,"fec_hamming_decode(), input symbol too large"); return 0; } // compute syndrome bits unsigned int s1 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S1); unsigned int s2 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S2); unsigned int s4 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S4); unsigned int s8 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S8); unsigned int s16 = liquid_bdotprod_uint32(_sym_enc, HAMMING_S16); // index unsigned int z = (s16<<4) | (s8<<3) | (s4<<2) | (s2<<1) | s1; #if DEBUG_FEC_HAMMING printf("syndrome bits (s1,s2,s4,s8,16) : (%1u,%1u,%1u,%1u,%1u)\n", s1, s2, s4, s8, s16); printf("syndrome z : %u\n", z); #endif // flip bit at this position if (z) { if (z > 31) { // if this happens there are likely too many errors // to correct; just pass without trying to do anything fprintf(stderr,"warning, fec_hamming3126_decode_symbol(), syndrome index exceeds maximum\n"); } else { //printf("error detected!\n"); _sym_enc ^= 1 << (31-z); } } // strip data bits from encoded symbol with parity bits unsigned int sym_dec = ((_sym_enc & 0x00007fff) ) | // .000 0000 0000 0000 0111 1111 1111 1111 ((_sym_enc & 0x007f0000) >> 1) | // .000 0000 0111 1111 0000 0000 0000 0000 ((_sym_enc & 0x07000000) >> 2) | // .000 0111 0000 0000 0000 0000 0000 0000 ((_sym_enc & 0x10000000) >> 3); // .001 0000 0000 0000 0000 0000 0000 0000 return sym_dec; } liquid-dsp-1.7.0/src/fec/src/fec_hamming74.c000066400000000000000000000174321474751757600205170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 1/2-rate (7,4) Hamming code // #include #include #include #include "liquid.internal.h" // encoder look-up table unsigned char hamming74_enc_gentab[16] = { 0x00, 0x69, 0x2a, 0x43, 0x4c, 0x25, 0x66, 0x0f, 0x70, 0x19, 0x5a, 0x33, 0x3c, 0x55, 0x16, 0x7f}; // decoder look-up table unsigned char hamming74_dec_gentab[128] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0e, 0x07, 0x00, 0x09, 0x02, 0x07, 0x04, 0x07, 0x07, 0x07, 0x00, 0x09, 0x0e, 0x0b, 0x0e, 0x0d, 0x0e, 0x0e, 0x09, 0x09, 0x0a, 0x09, 0x0c, 0x09, 0x0e, 0x07, 0x00, 0x05, 0x02, 0x0b, 0x05, 0x05, 0x06, 0x05, 0x02, 0x01, 0x02, 0x02, 0x0c, 0x05, 0x02, 0x07, 0x08, 0x0b, 0x0b, 0x0b, 0x0c, 0x05, 0x0e, 0x0b, 0x0c, 0x09, 0x02, 0x0b, 0x0c, 0x0c, 0x0c, 0x0f, 0x00, 0x03, 0x03, 0x03, 0x04, 0x0d, 0x06, 0x03, 0x04, 0x01, 0x0a, 0x03, 0x04, 0x04, 0x04, 0x07, 0x08, 0x0d, 0x0a, 0x03, 0x0d, 0x0d, 0x0e, 0x0d, 0x0a, 0x09, 0x0a, 0x0a, 0x04, 0x0d, 0x0a, 0x0f, 0x08, 0x01, 0x06, 0x03, 0x06, 0x05, 0x06, 0x06, 0x01, 0x01, 0x02, 0x01, 0x04, 0x01, 0x06, 0x0f, 0x08, 0x08, 0x08, 0x0b, 0x08, 0x0d, 0x06, 0x0f, 0x08, 0x01, 0x0a, 0x0f, 0x0c, 0x0f, 0x0f, 0x0f}; // create Hamming(7,4) codec object fec fec_hamming74_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_HAMMING74; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_hamming74_encode; q->decode_func = &fec_hamming74_decode; q->decode_soft_func = &fec_hamming74_decode_soft; return q; } // destroy Hamming(7,4) object int fec_hamming74_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using Hamming(7,4) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: _dec_msg_len x 1] // _msg_enc : encoded message [size: ...] int fec_hamming74_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i; // input byte counter unsigned int k=0; // array bit index // compute encoded message length unsigned int enc_msg_len = fec_block_get_enc_msg_len(_dec_msg_len,4,7); unsigned char s0, s1; // decoded symbols unsigned char m0, m1; // encoded symbols for (i=0; i<_dec_msg_len; i++) { // strip two 4-bit symbols from input byte s0 = (_msg_dec[i] >> 4) & 0x0f; s1 = (_msg_dec[i] >> 0) & 0x0f; // encode two 7-bit symbols m0 = hamming74_enc_gentab[s0]; m1 = hamming74_enc_gentab[s1]; // pack encoded symbols into output array liquid_pack_array(_msg_enc, enc_msg_len, k, 7, m0); k += 7; liquid_pack_array(_msg_enc, enc_msg_len, k, 7, m1); k += 7; //printf(" %3u : 0x%.2x > 0x%.2x, 0x%.2x > 0x%.2x (k=%u)\n", i, s0, m0, s1, m1, k); } return LIQUID_OK; } // decode block of data using Hamming(7,4) decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: ...] // _msg_dec : decoded message [size: _dec_msg_len x 1] // //unsigned int int fec_hamming74_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i; unsigned int k=0; // array bit index // compute encoded message length unsigned int enc_msg_len = fec_block_get_enc_msg_len(_dec_msg_len,4,7); unsigned char r0, r1; // received 7-bit symbols unsigned char s0, s1; // decoded 4-bit symbols //unsigned char num_errors=0; for (i=0; i<_dec_msg_len; i++) { // strip two 7-bit symbols from liquid_unpack_array(_msg_enc, enc_msg_len, k, 7, &r0); k += 7; liquid_unpack_array(_msg_enc, enc_msg_len, k, 7, &r1); k += 7; s0 = hamming74_dec_gentab[r0]; s1 = hamming74_dec_gentab[r1]; _msg_dec[i] = (s0 << 4) | s1; //printf(" %3u : 0x%.2x > 0x%.2x, 0x%.2x > 0x%.2x (k=%u)\n", i, r0, s0, r1, s1, k); } return LIQUID_OK; } // decode block of data using Hamming(7,4) soft decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 8*_enc_msg_len x 1] // _msg_dec : decoded message [size: _dec_msg_len x 1] // //unsigned int int fec_hamming74_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i; unsigned int k=0; // array bit index // compute encoded message length unsigned int enc_msg_len = fec_block_get_enc_msg_len(_dec_msg_len,4,7); // decoded 4-bit symbols unsigned char s0; unsigned char s1; //unsigned char num_errors=0; for (i=0; i<_dec_msg_len; i++) { s0 = fecsoft_hamming74_decode(&_msg_enc[k ]); s1 = fecsoft_hamming74_decode(&_msg_enc[k+7]); k += 14; // pack two 4-bit symbols into one 8-bit byte _msg_dec[i] = (s0 << 4) | s1; //printf(" %3u : 0x%.2x > 0x%.2x, 0x%.2x > 0x%.2x (k=%u)\n", i, r0, s0, r1, s1, k); } assert(k == 8*enc_msg_len); return LIQUID_OK; } // // internal methods // // soft decoding of one symbol unsigned char fecsoft_hamming74_decode(unsigned char * _soft_bits) { // find symbol with minimum distance from all 2^4 possible unsigned int d; // distance metric unsigned int dmin = 0; // minimum distance unsigned char s_hat = 0; // estimated transmitted symbol unsigned char c; // encoded symbol unsigned char s; for (s=0; s<16; s++) { // encode symbol c = hamming74_enc_gentab[s]; // compute distance metric d = 0; d += (c & 0x40) ? 255 - _soft_bits[0] : _soft_bits[0]; d += (c & 0x20) ? 255 - _soft_bits[1] : _soft_bits[1]; d += (c & 0x10) ? 255 - _soft_bits[2] : _soft_bits[2]; d += (c & 0x08) ? 255 - _soft_bits[3] : _soft_bits[3]; d += (c & 0x04) ? 255 - _soft_bits[4] : _soft_bits[4]; d += (c & 0x02) ? 255 - _soft_bits[5] : _soft_bits[5]; d += (c & 0x01) ? 255 - _soft_bits[6] : _soft_bits[6]; if (d < dmin || s==0) { s_hat = s; dmin = d; } } return s_hat; } liquid-dsp-1.7.0/src/fec/src/fec_hamming84.c000066400000000000000000000173341474751757600205210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 1/2-rate (8,4) Hamming code // #include #include #include #include "liquid.internal.h" // encoder look-up table unsigned char hamming84_enc_gentab[16] = { 0x00, 0xd2, 0x55, 0x87, 0x99, 0x4b, 0xcc, 0x1e, 0xe1, 0x33, 0xb4, 0x66, 0x78, 0xaa, 0x2d, 0xff}; // decoder look-up table unsigned char hamming84_dec_gentab[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x05, 0x05, 0x0e, 0x0e, 0x07, 0x07, 0x00, 0x00, 0x09, 0x09, 0x02, 0x02, 0x07, 0x07, 0x04, 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 0x09, 0x09, 0x0e, 0x0e, 0x0b, 0x0b, 0x0e, 0x0e, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x09, 0x09, 0x0c, 0x0c, 0x09, 0x09, 0x0e, 0x0e, 0x07, 0x07, 0x00, 0x00, 0x05, 0x05, 0x02, 0x02, 0x0b, 0x0b, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x05, 0x05, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x0c, 0x0c, 0x05, 0x05, 0x02, 0x02, 0x07, 0x07, 0x08, 0x08, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x05, 0x05, 0x0e, 0x0e, 0x0b, 0x0b, 0x0c, 0x0c, 0x09, 0x09, 0x02, 0x02, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0f, 0x0f, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x0d, 0x0d, 0x06, 0x06, 0x03, 0x03, 0x04, 0x04, 0x01, 0x01, 0x0a, 0x0a, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0d, 0x0d, 0x0a, 0x0a, 0x03, 0x03, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0d, 0x0d, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x04, 0x04, 0x0d, 0x0d, 0x0a, 0x0a, 0x0f, 0x0f, 0x08, 0x08, 0x01, 0x01, 0x06, 0x06, 0x03, 0x03, 0x06, 0x06, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x06, 0x06, 0x0f, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0b, 0x0b, 0x08, 0x08, 0x0d, 0x0d, 0x06, 0x06, 0x0f, 0x0f, 0x08, 0x08, 0x01, 0x01, 0x0a, 0x0a, 0x0f, 0x0f, 0x0c, 0x0c, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f}; // create Hamming(8,4) codec object fec fec_hamming84_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_HAMMING84; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_hamming84_encode; q->decode_func = &fec_hamming84_decode; q->decode_soft_func = &fec_hamming84_decode_soft; return q; } // destroy Hamming(8,4) object int fec_hamming84_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using Hamming(8,4) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_hamming84_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i, j=0; unsigned char s0, s1; for (i=0; i<_dec_msg_len; i++) { s0 = (_msg_dec[i] >> 4) & 0x0f; s1 = (_msg_dec[i] >> 0) & 0x0f; _msg_enc[j+0] = hamming84_enc_gentab[s0]; _msg_enc[j+1] = hamming84_enc_gentab[s1]; j+=2; } return LIQUID_OK; } // decode block of data using Hamming(8,4) decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] // //unsigned int int fec_hamming84_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i; unsigned char r0, r1; // received 8-bit symbols unsigned char s0, s1; // decoded 4-bit symbols //unsigned char num_errors=0; for (i=0; i<_dec_msg_len; i++) { r0 = _msg_enc[2*i+0] & 0xff; r1 = _msg_enc[2*i+1] & 0xff; s0 = hamming84_dec_gentab[r0]; s1 = hamming84_dec_gentab[r1]; _msg_dec[i] = (s0 << 4) | s1; } return LIQUID_OK; } // decode block of data using Hamming(8,4) soft decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 8*_enc_msg_len x 1] // _msg_dec : decoded message [size: _dec_msg_len x 1] // //unsigned int int fec_hamming84_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i; unsigned int k=0; // array bit index // compute encoded message length unsigned int enc_msg_len = fec_block_get_enc_msg_len(_dec_msg_len,4,8); // decoded 4-bit symbols unsigned char s0; unsigned char s1; //unsigned char num_errors=0; for (i=0; i<_dec_msg_len; i++) { s0 = fecsoft_hamming84_decode(&_msg_enc[k ]); s1 = fecsoft_hamming84_decode(&_msg_enc[k+8]); k += 16; // pack two 4-bit symbols into one 8-bit byte _msg_dec[i] = (s0 << 4) | s1; //printf(" %3u : 0x%.2x > 0x%.2x, 0x%.2x > 0x%.2x (k=%u)\n", i, r0, s0, r1, s1, k); } assert(k == 8*enc_msg_len); return LIQUID_OK; } // // internal methods // // soft decoding of one symbol unsigned char fecsoft_hamming84_decode(unsigned char * _soft_bits) { // find symbol with minimum distance from all 2^4 possible unsigned int d; // distance metric unsigned int dmin = 0; // minimum distance unsigned char s_hat = 0; // estimated transmitted symbol unsigned char c; // encoded symbol unsigned char s; for (s=0; s<16; s++) { // encode symbol c = hamming84_enc_gentab[s]; // compute distance metric d = 0; d += (c & 0x80) ? 255 - _soft_bits[0] : _soft_bits[0]; d += (c & 0x40) ? 255 - _soft_bits[1] : _soft_bits[1]; d += (c & 0x20) ? 255 - _soft_bits[2] : _soft_bits[2]; d += (c & 0x10) ? 255 - _soft_bits[3] : _soft_bits[3]; d += (c & 0x08) ? 255 - _soft_bits[4] : _soft_bits[4]; d += (c & 0x04) ? 255 - _soft_bits[5] : _soft_bits[5]; d += (c & 0x02) ? 255 - _soft_bits[6] : _soft_bits[6]; d += (c & 0x01) ? 255 - _soft_bits[7] : _soft_bits[7]; if (d < dmin || s==0) { s_hat = s; dmin = d; } } return s_hat; } liquid-dsp-1.7.0/src/fec/src/fec_pass.c000066400000000000000000000040241474751757600176630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // FEC, none/pass // #include #include #include #include "liquid.internal.h" fec fec_pass_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = LIQUID_FEC_NONE; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_pass_encode; q->decode_func = &fec_pass_decode; q->decode_soft_func = NULL; return q; } int fec_pass_destroy(fec _q) { free(_q); return LIQUID_OK; } int fec_pass_print(fec _q) { printf("fec_pass [r: %3.2f]\n", _q->rate); return LIQUID_OK; } int fec_pass_encode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_dec, unsigned char *_msg_enc) { memmove(_msg_enc, _msg_dec, _dec_msg_len); return LIQUID_OK; } int fec_pass_decode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_enc, unsigned char *_msg_dec) { memmove(_msg_dec, _msg_enc, _dec_msg_len); return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/fec_rep3.c000066400000000000000000000113231474751757600175660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // FEC, repeat code // #include #include #include #include "liquid.internal.h" // create rep3 codec object fec fec_rep3_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = LIQUID_FEC_REP3; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_rep3_encode; q->decode_func = &fec_rep3_decode; q->decode_soft_func = &fec_rep3_decode_soft; return q; } // destroy rep3 object int fec_rep3_destroy(fec _q) { free(_q); return LIQUID_OK; } // print rep3 object int fec_rep3_print(fec _q) { printf("fec_rep3 [r: %3.2f]\n", _q->rate); return LIQUID_OK; } // encode block of data using rep3 encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 3*_dec_msg_len] int fec_rep3_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i; for (i=0; i<3; i++) { memcpy(&_msg_enc[i*_dec_msg_len], _msg_dec, _dec_msg_len); } return LIQUID_OK; } // decode block of data using rep3 decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 3*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] int fec_rep3_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned char s0, s1, s2; unsigned int i; //unsigned int num_errors=0; for (i=0; i<_dec_msg_len; i++) { s0 = _msg_enc[i]; s1 = _msg_enc[i + _dec_msg_len]; s2 = _msg_enc[i + 2*_dec_msg_len]; // s0 s1 s2 | y e // ------------+--------- // 0 0 0 | 0 0 // 0 0 1 | 0 1 // 0 1 0 | 0 1 // 0 1 1 | 1 1 // 1 0 0 | 0 1 // 1 0 1 | 1 1 // 1 1 0 | 1 1 // 1 1 1 | 1 0 _msg_dec[i] = (s0 & s1) | (s0 & s2) | (s1 & s2); //num_errors += (s0 ^ s1) | (s0 ^ s2) | (s1 ^ s2) ? 1 : 0; //num_errors += 0; } return LIQUID_OK; } // decode block of data using rep3 decoder (soft metrics) // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 3*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] int fec_rep3_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned char s0, s1, s2; unsigned int i; unsigned int j; unsigned int s_hat; //unsigned int num_errors=0; for (i=0; i<_dec_msg_len; i++) { // clear decoded message _msg_dec[i] = 0x00; for (j=0; j<8; j++) { s0 = _msg_enc[8*i + j]; s1 = _msg_enc[8*(i + _dec_msg_len) + j]; s2 = _msg_enc[8*(i + 2*_dec_msg_len) + j]; // average three symbols and make decision s_hat = (s0 + s1 + s2)/3; _msg_dec[i] |= (s_hat > LIQUID_SOFTBIT_ERASURE) ? (1 << (8-j-1)) : 0x00; } } return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/fec_rep5.c000066400000000000000000000117701474751757600175760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // FEC, repeat code // #include #include #include #include "liquid.internal.h" // create rep5 codec object fec fec_rep5_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = LIQUID_FEC_REP5; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_rep5_encode; q->decode_func = &fec_rep5_decode; q->decode_soft_func = &fec_rep5_decode_soft; return q; } // destroy rep5 object int fec_rep5_destroy(fec _q) { free(_q); return LIQUID_OK; } // print rep5 object int fec_rep5_print(fec _q) { printf("fec_rep5 [r: %3.2f]\n", _q->rate); return LIQUID_OK; } // encode block of data using rep5 encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 5*_dec_msg_len] int fec_rep5_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i; for (i=0; i<5; i++) { memcpy(&_msg_enc[i*_dec_msg_len], _msg_dec, _dec_msg_len); } return LIQUID_OK; } // decode block of data using rep5 decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 5*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] int fec_rep5_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned char s0, s1, s2, s3, s4; unsigned int i; //unsigned int num_errors=0; for (i=0; i<_dec_msg_len; i++) { s0 = _msg_enc[i ]; s1 = _msg_enc[i + _dec_msg_len]; s2 = _msg_enc[i + 2*_dec_msg_len]; s3 = _msg_enc[i + 3*_dec_msg_len]; s4 = _msg_enc[i + 4*_dec_msg_len]; // compute all triplet combinations _msg_dec[i] = (s0 & s1 & s2) | (s0 & s1 & s3) | (s0 & s1 & s4) | (s0 & s2 & s3) | (s0 & s2 & s4) | (s0 & s3 & s4) | (s1 & s2 & s3) | (s1 & s2 & s4) | (s1 & s3 & s4) | (s2 & s3 & s4); //num_errors += (s0 ^ s1) | (s0 ^ s2) | (s1 ^ s2) ? 1 : 0; //num_errors += 0; } return LIQUID_OK; } // decode block of data using rep5 decoder (soft metrics) // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 5*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] int fec_rep5_decode_soft(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned char s0, s1, s2, s3, s4; unsigned int i; unsigned int j; unsigned int s_hat; //unsigned int num_errors=0; for (i=0; i<_dec_msg_len; i++) { // clear decoded message _msg_dec[i] = 0x00; for (j=0; j<8; j++) { s0 = _msg_enc[8*i + j]; s1 = _msg_enc[8*(i + _dec_msg_len) + j]; s2 = _msg_enc[8*(i + 2*_dec_msg_len) + j]; s3 = _msg_enc[8*(i + 3*_dec_msg_len) + j]; s4 = _msg_enc[8*(i + 4*_dec_msg_len) + j]; // average three symbols and make decision s_hat = (s0 + s1 + s2 + s3 + s4)/5; _msg_dec[i] |= (s_hat > LIQUID_SOFTBIT_ERASURE) ? (1 << (8-j-1)) : 0x00; } } return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/fec_rs.c000066400000000000000000000230301474751757600173370ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Reed-Solomon (macros) // #include #include #include #include #include "liquid.internal.h" #define VERBOSE_FEC_RS 0 #if LIBFEC_ENABLED #include "fec.h" fec fec_rs_create(fec_scheme _fs) { fec q = (fec) malloc(sizeof(struct fec_s)); q->scheme = _fs; q->rate = fec_get_rate(q->scheme); q->encode_func = &fec_rs_encode; q->decode_func = &fec_rs_decode; q->decode_soft_func = NULL; switch (q->scheme) { case LIQUID_FEC_RS_M8: fec_rs_init_p8(q); break; default: return liquid_error_config("fec_rs_create(), invalid type"); } // initialize basic parameters q->nn = (1 << q->symsize) - 1; q->kk = q->nn - q->nroots; // lengths q->num_dec_bytes = 0; q->rs = NULL; // allocate memory for arrays q->tblock = (unsigned char*) malloc(q->nn*sizeof(unsigned char)); q->errlocs = (int *) malloc(q->nn*sizeof(int)); q->derrlocs = (int *) malloc(q->nn*sizeof(int)); return q; } int fec_rs_destroy(fec _q) { // delete internal Reed-Solomon decoder object if (_q->rs != NULL) { free_rs_char(_q->rs); } // delete internal memory arrays free(_q->tblock); free(_q->errlocs); free(_q->derrlocs); // delete fec object free(_q); return LIQUID_OK; } int fec_rs_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { // validate input if (_dec_msg_len == 0) return liquid_error(LIQUID_EICONFIG,"fec_rs_encode(), input length must be > 0"); // re-allocate resources if necessary fec_rs_setlength(_q, _dec_msg_len); unsigned int i; unsigned int n0=0; // input index unsigned int n1=0; // output index unsigned int block_size = _q->dec_block_len; for (i=0; i<_q->num_blocks; i++) { // the last block is smaller by the residual block length if (i == _q->num_blocks-1) block_size -= _q->res_block_len; // copy sequence memmove(_q->tblock, &_msg_dec[n0], block_size*sizeof(unsigned char)); // last block: we could pad end with zeros, but it's not really // necessary as these bits are going to be thrown away anyway // encode data, appending parity bits to end of sequence encode_rs_char(_q->rs, _q->tblock, &_q->tblock[_q->dec_block_len]); // copy result to output memmove(&_msg_enc[n1], _q->tblock, _q->enc_block_len*sizeof(unsigned char)); // increment counters n0 += block_size; n1 += _q->enc_block_len; } // sanity check assert( n0 == _q->num_dec_bytes ); assert( n1 == _q->num_enc_bytes ); return LIQUID_OK; } //unsigned int int fec_rs_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { // validate input if (_dec_msg_len == 0) return liquid_error(LIQUID_EICONFIG,"fec_rs_encode(), input length must be > 0"); // re-allocate resources if necessary fec_rs_setlength(_q, _dec_msg_len); // set erasures, error locations to zero memset(_q->errlocs, 0x00, _q->nn*sizeof(unsigned char)); memset(_q->derrlocs, 0x00, _q->nn*sizeof(unsigned char)); _q->erasures = 0; unsigned int i; unsigned int n0=0; unsigned int n1=0; unsigned int block_size = _q->dec_block_len; //int derrors; // number of decoder errors for (i=0; i<_q->num_blocks; i++) { // the last block is smaller by the residual block length if (i == _q->num_blocks-1) block_size -= _q->res_block_len; // copy sequence memmove(_q->tblock, &_msg_enc[n0], _q->enc_block_len*sizeof(unsigned char)); // decode block //derrors = decode_rs_char(_q->rs, _q->tblock, _q->derrlocs, _q->erasures); // copy result memmove(&_msg_dec[n1], _q->tblock, block_size*sizeof(unsigned char)); // increment counters n0 += _q->enc_block_len; n1 += block_size; } // sanity check assert( n0 == _q->num_enc_bytes ); assert( n1 == _q->num_dec_bytes ); return LIQUID_OK; } // Set dec_msg_len, re-allocating resources as necessary. Effectively, it // divides the input message into several blocks and allows the decoder to // pad each block appropriately. // // For example : if we are using the 8-bit code, // nroots = 32 // nn = 255 // kk = 223 // Let _dec_msg_len = 1024, then // num_blocks = ceil(1024/223) // = ceil(4.5919) // = 5 // dec_block_len = ceil(1024/num_blocks) // = ceil(204.8) // = 205 // enc_block_len = dec_block_len + nroots // = 237 // res_block_len = mod(num_blocks*dec_block_len,_dec_msg_len) // = mod(5*205,1024) // = mod(1025,1024) // = 1 (cannot evenly divide input sequence) // pad = kk - dec_block_len // = 223 - 205 // = 18 // // Thus, the 1024-byte input message is broken into 5 blocks, the first // four have a length 205, and the last block has a length 204 (which is // externally padded to 205, e.g. res_block_len = 1). This code adds 32 // parity symbols, so each block is extended to 237 bytes. libfec auto- // matically extends the internal data to 255 bytes by padding with 18 // symbols. Therefore, the final output length is 237 * 5 = 1185 symbols. int fec_rs_setlength(fec _q, unsigned int _dec_msg_len) { // return if length has not changed if (_dec_msg_len == _q->num_dec_bytes) return LIQUID_OK; // reset lengths _q->num_dec_bytes = _dec_msg_len; div_t d; // compute the total number of blocks necessary: ceil(num_dec_bytes / kk) d = div(_q->num_dec_bytes, _q->kk); _q->num_blocks = d.quot + (d.rem==0 ? 0 : 1); // compute the decoded block length: ceil(num_dec_bytes / num_blocks) d = div(_dec_msg_len, _q->num_blocks); _q->dec_block_len = d.quot + (d.rem == 0 ? 0 : 1); // compute the encoded block length: dec_block_len + nroots _q->enc_block_len = _q->dec_block_len + _q->nroots; // compute the residual padding symbols in the last block: // mod(num_blocks*dec_block_len, num_dec_bytes) _q->res_block_len = (_q->num_blocks*_q->dec_block_len) % _q->num_dec_bytes; // compute the internal libfec padding factor: kk - dec_block_len _q->pad = _q->kk - _q->dec_block_len; // compute the final encoded block length: enc_block_len * num_blocks _q->num_enc_bytes = _q->enc_block_len * _q->num_blocks; #if VERBOSE_FEC_RS printf("dec_msg_len : %u\n", _q->num_dec_bytes); printf("num_blocks : %u\n", _q->num_blocks); printf("dec_block_len : %u\n", _q->dec_block_len); printf("enc_block_len : %u\n", _q->enc_block_len); printf("res_block_len : %u\n", _q->res_block_len); printf("pad : %u\n", _q->pad); printf("enc_msg_len : %u\n", _q->num_enc_bytes); #endif // delete old decoder if necessary if (_q->rs != NULL) free_rs_char(_q->rs); // Reed-Solomon specific decoding _q->rs = init_rs_char(_q->symsize, _q->genpoly, _q->fcs, _q->prim, _q->nroots, _q->pad); return LIQUID_OK; } // // internal // int fec_rs_init_p8(fec _q) { _q->symsize = 8; _q->genpoly = 0x11d; _q->fcs = 1; _q->prim = 1; _q->nroots = 32; return LIQUID_OK; } #else // LIBFEC_ENABLED fec fec_rs_create(fec_scheme _fs) { return liquid_error_config("fec_rs_create(), libfec not installed"); } int fec_rs_destroy(fec _q) { return liquid_error(LIQUID_EUMODE,"fec_rs_destroy(), libfec not installed"); } int fec_rs_encode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_dec, unsigned char *_msg_enc) { return liquid_error(LIQUID_EUMODE,"fec_rs_encode(), libfec not installed"); } //unsigned int int fec_rs_decode(fec _q, unsigned int _dec_msg_len, unsigned char *_msg_enc, unsigned char *_msg_dec) { return liquid_error(LIQUID_EUMODE,"fec_rs_decode(), libfec not installed"); } #endif // LIBFEC_ENABLED liquid-dsp-1.7.0/src/fec/src/fec_secded2216.c000066400000000000000000000233141474751757600204620ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // SEC-DED (22,16) 8/11-rate forward error-correction block code // // References: // [Lin:2004] Lin, Shu and Costello, Daniel L. Jr., "Error Control // Coding," Prentice Hall, New Jersey, 2nd edition, 2004. // #include #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED2216 0 // P matrix [6 x 16 bits], [6 x 2 bytes] // 1001 1001 0011 1100 : // 0011 1110 1000 1010 : // 1110 1110 0110 0000 : // 1110 0001 1101 0001 : // 0001 0011 1100 0111 : // 0100 0100 0011 1111 : unsigned char secded2216_P[12] = { 0x99, 0x3c, 0x3e, 0x8a, 0xee, 0x60, 0xe1, 0xd1, 0x13, 0xc7, 0x44, 0x3f}; // syndrome vectors for errors of weight 1 unsigned char secded2216_syndrome_w1[22] = { 0x07, 0x13, 0x23, 0x31, 0x25, 0x29, 0x0e, 0x16, 0x26, 0x1a, 0x19, 0x38, 0x32, 0x1c, 0x0d, 0x2c, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20}; // compute parity on 16-bit input unsigned char fec_secded2216_compute_parity(unsigned char * _m) { // compute encoded/transmitted message: v = m*G unsigned char parity = 0x00; // TODO : unwrap this loop unsigned int i; for (i=0; i<6; i++) { parity <<= 1; unsigned int p = liquid_c_ones[ secded2216_P[2*i+0] & _m[0] ] + liquid_c_ones[ secded2216_P[2*i+1] & _m[1] ]; parity |= p & 0x01; } return parity; } // compute syndrome on 22-bit input unsigned char fec_secded2216_compute_syndrome(unsigned char * _v) { // TODO : unwrap this loop unsigned int i; unsigned char syndrome = 0x00; for (i=0; i<6; i++) { syndrome <<= 1; unsigned int p = ( (_v[0] & (1<<(6-i-1))) ? 1 : 0 )+ liquid_c_ones[ secded2216_P[2*i+0] & _v[1] ] + liquid_c_ones[ secded2216_P[2*i+1] & _v[2] ]; syndrome |= p & 0x01; } return syndrome; } // encode symbol // _sym_dec : decoded symbol [size: 2 x 1] // _sym_enc : encoded symbol [size: 3 x 1], _sym_enc[0] has only 6 bits int fec_secded2216_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc) { // first six bits is parity block _sym_enc[0] = fec_secded2216_compute_parity(_sym_dec); // copy last two values _sym_enc[1] = _sym_dec[0]; _sym_enc[2] = _sym_dec[1]; return LIQUID_OK; } // decode symbol, returning 0/1/2 for zero/one/multiple errors // detected, respectively // _sym_enc : encoded symbol [size: 3 x 1], _sym_enc[0] has only 6 bits // _sym_dec : decoded symbol [size: 2 x 1] int fec_secded2216_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec) { #if 0 // validate input if (_sym_enc[0] >= (1<<6)) { fprintf(stderr,"warning, fec_secded2216_decode_symbol(), input symbol too large\n"); } #endif // estimate error vector unsigned char e_hat[3] = {0,0,0}; int syndrome_flag = fec_secded2216_estimate_ehat(_sym_enc, e_hat); // compute estimated transmit vector (last 64 bits of encoded message) // NOTE: indices take into account first element in _sym_enc and e_hat // arrays holds the parity bits _sym_dec[0] = _sym_enc[1] ^ e_hat[1]; _sym_dec[1] = _sym_enc[2] ^ e_hat[2]; #if DEBUG_FEC_SECDED2216 if (syndrome_flag == 1) { printf("secded2216_decode_symbol(): single error detected!\n"); } else if (syndrome_flag == 2) { printf("secded2216_decode_symbol(): no match found (multiple errors detected)\n"); } #endif // return syndrome flag return syndrome_flag; } // estimate error vector, returning 0/1/2 for zero/one/multiple errors // detected, respectively // _sym_enc : encoded symbol [size: 3 x 1], _sym_enc[0] has only 6 bits // _e_hat : estimated error vector [size: 3 x 1] int fec_secded2216_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat) { // clear output array _e_hat[0] = 0x00; _e_hat[1] = 0x00; _e_hat[2] = 0x00; // compute syndrome vector, s = r*H^T = ( H*r^T )^T unsigned char s = fec_secded2216_compute_syndrome(_sym_enc); // compute weight of s unsigned int ws = liquid_c_ones[s]; if (ws == 0) { // no errors detected return 0; } else { // estimate error location; search for syndrome with error // vector of weight one unsigned int n; // estimate error location for (n=0; n<22; n++) { if (s == secded2216_syndrome_w1[n]) { // single error detected at location 'n' div_t d = div(n,8); _e_hat[3-d.quot-1] = 1 << d.rem; return 1; } } } // no syndrome match; multiple errors detected return 2; } // create SEC-DED (22,16) codec object fec fec_secded2216_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_SECDED2216; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_secded2216_encode; q->decode_func = &fec_secded2216_decode; q->decode_soft_func = NULL; return q; } // destroy SEC-DEC (22,16) object int fec_secded2216_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using SEC-DEC (22,16) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_secded2216_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter // determine remainder of input length / 8 unsigned int r = _dec_msg_len % 2; // for now simply encode as 2/3-rate codec (eat // 2 bits of parity) // TODO : make more efficient for (i=0; i<_dec_msg_len-r; i+=2) { // compute parity (6 bits) on two input bytes (16 bits) _msg_enc[j+0] = fec_secded2216_compute_parity(&_msg_dec[i]); // copy remaining two input bytes (16 bits) _msg_enc[j+1] = _msg_dec[i+0]; _msg_enc[j+2] = _msg_dec[i+1]; // increment output counter j += 3; } // if input length isn't divisible by 2, encode last few bytes if (r) { // one 16-bit symbol (decoded) unsigned char m[2] = {_msg_dec[i], 0x00}; // one 22-bit symbol (encoded) unsigned char v[3]; // encode fec_secded2216_encode_symbol(m, v); // there is no need to actually send all three bytes; // the last byte is zero and can be artificially // inserted at the decoder _msg_enc[j+0] = v[0]; _msg_enc[j+1] = v[1]; i += r; j += r+1; } assert( j == fec_get_enc_msg_length(LIQUID_FEC_SECDED2216,_dec_msg_len) ); assert( i == _dec_msg_len); return LIQUID_OK; } // decode block of data using SEC-DEC (22,16) decoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] // _msg_dec : decoded message [size: 1 x _dec_msg_len] // //unsigned int int fec_secded2216_decode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_enc, unsigned char * _msg_dec) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter // determine remainder of input length / 8 unsigned int r = _dec_msg_len % 2; for (i=0; i<_dec_msg_len-r; i+=2) { // decode straight to output fec_secded2216_decode_symbol(&_msg_enc[j], &_msg_dec[i]); j += 3; } // if input length isn't divisible by 2, decode last several bytes if (r) { // one 22-bit symbol (encoded), with last byte artificially // set to '00000000' unsigned char v[3] = {_msg_enc[j+0], _msg_enc[j+1], 0x00}; // one 16-bit symbol (decoded) unsigned char m_hat[2]; // decode symbol fec_secded2216_decode_symbol(v, m_hat); // copy just first byte to output _msg_dec[i] = m_hat[0]; i += r; j += r+1; } assert( j == fec_get_enc_msg_length(LIQUID_FEC_SECDED2216,_dec_msg_len) ); assert( i == _dec_msg_len); return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/fec_secded3932.c000066400000000000000000000255021474751757600204710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // SEC-DED (39,32) forward error-correction block code // // References: // [Lin:2004] Lin, Shu and Costello, Daniel L. Jr., "Error Control // Coding," Prentice Hall, New Jersey, 2nd edition, 2004. // #include #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED3932 0 // P matrix [7 x 32 bits], [7 x 4 bytes] // 1000 1010 1000 0010 0000 1111 0001 1011 // 0001 0000 0001 1111 0111 0001 0110 0001 // 0001 0110 1111 0000 1001 0010 1010 0110 // 1111 1111 0000 0001 1010 0100 0100 0100 // 0110 1100 1111 1111 0000 1000 0000 1000 // 0010 0001 0010 0100 1111 1111 1001 0000 // 1100 0001 0100 1000 0100 0000 1111 1111 unsigned char secded3932_P[28] = { 0x8a, 0x82, 0x0f, 0x1b, 0x10, 0x1f, 0x71, 0x61, 0x16, 0xf0, 0x92, 0xa6, 0xff, 0x01, 0xa4, 0x44, 0x6c, 0xff, 0x08, 0x08, 0x21, 0x24, 0xff, 0x90, 0xc1, 0x48, 0x40, 0xff}; // syndrome vectors for errors of weight 1 unsigned char secded3932_syndrome_w1[39] = { 0x61, 0x51, 0x19, 0x45, 0x43, 0x31, 0x29, 0x13, 0x62, 0x52, 0x4a, 0x46, 0x32, 0x2a, 0x23, 0x1a, 0x2c, 0x64, 0x26, 0x25, 0x34, 0x16, 0x15, 0x54, 0x0b, 0x58, 0x1c, 0x4c, 0x38, 0x0e, 0x0d, 0x49, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40}; // compute parity on 32-bit input unsigned char fec_secded3932_compute_parity(unsigned char * _m) { // compute encoded/transmitted message: v = m*G unsigned char parity = 0x00; // TODO : unwrap this loop unsigned int i; for (i=0; i<7; i++) { parity <<= 1; unsigned int p = liquid_c_ones[ secded3932_P[4*i+0] & _m[0] ] + liquid_c_ones[ secded3932_P[4*i+1] & _m[1] ] + liquid_c_ones[ secded3932_P[4*i+2] & _m[2] ] + liquid_c_ones[ secded3932_P[4*i+3] & _m[3] ]; parity |= p & 0x01; } return parity; } // compute syndrome on 39-bit input unsigned char fec_secded3932_compute_syndrome(unsigned char * _v) { // TODO : unwrap this loop unsigned int i; unsigned char syndrome = 0x00; for (i=0; i<7; i++) { syndrome <<= 1; unsigned int p = ( (_v[0] & (1<<(7-i-1))) ? 1 : 0 )+ liquid_c_ones[ secded3932_P[4*i+0] & _v[1] ] + liquid_c_ones[ secded3932_P[4*i+1] & _v[2] ] + liquid_c_ones[ secded3932_P[4*i+2] & _v[3] ] + liquid_c_ones[ secded3932_P[4*i+3] & _v[4] ]; syndrome |= p & 0x01; } return syndrome; } // encode symbol // _sym_dec : decoded symbol [size: 4 x 1] // _sym_enc : encoded symbol [size: 5 x 1], _sym_enc[0] has only 7 bits int fec_secded3932_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc) { // first six bits is parity block _sym_enc[0] = fec_secded3932_compute_parity(_sym_dec); // concatenate original message _sym_enc[1] = _sym_dec[0]; _sym_enc[2] = _sym_dec[1]; _sym_enc[3] = _sym_dec[2]; _sym_enc[4] = _sym_dec[3]; return LIQUID_OK; } // decode symbol, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol [size: 5 x 1], _sym_enc[0] has only 7 bits // _sym_dec : decoded symbol [size: 4 x 1] int fec_secded3932_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec) { #if 0 // validate input if (_sym_enc[0] >= (1<<7)) { fprintf(stderr,"warning, fec_secded3932_decode_symbol(), input symbol too large\n"); } #endif // estimate error vector unsigned char e_hat[5] = {0,0,0,0,0}; // estimated error vector int syndrome_flag = fec_secded3932_estimate_ehat(_sym_enc, e_hat); // compute estimated transmit vector (last 64 bits of encoded message) // NOTE: indices take into account first element in _sym_enc and e_hat // arrays holds the parity bits _sym_dec[0] = _sym_enc[1] ^ e_hat[1]; _sym_dec[1] = _sym_enc[2] ^ e_hat[2]; _sym_dec[2] = _sym_enc[3] ^ e_hat[3]; _sym_dec[3] = _sym_enc[4] ^ e_hat[4]; #if DEBUG_FEC_SECDED3932 if (syndrome_flag == 1) { printf("secded3932_decode_symbol(): single error detected!\n"); } else if (syndrome_flag == 2) { printf("secded3932_decode_symbol(): no match found (multiple errors detected)\n"); } #endif // return syndrome flag return syndrome_flag; } // estimate error vector, returning 0/1/2 for zero/one/multiple errors // detected, respectively // _sym_enc : encoded symbol [size: 5 x 1], _sym_enc[0] has only 6 bits // _e_hat : estimated error vector [size: 5 x 1] int fec_secded3932_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat) { // clear output array _e_hat[0] = 0x00; _e_hat[1] = 0x00; _e_hat[2] = 0x00; _e_hat[3] = 0x00; _e_hat[4] = 0x00; // compute syndrome vector, s = r*H^T = ( H*r^T )^T unsigned char s = fec_secded3932_compute_syndrome(_sym_enc); // compute weight of s unsigned int ws = liquid_c_ones[s]; if (ws == 0) { // no errors detected return 0; } else { // estimate error location; search for syndrome with error // vector of weight one unsigned int n; // estimate error location for (n=0; n<39; n++) { if (s == secded3932_syndrome_w1[n]) { // single error detected at location 'n' div_t d = div(n,8); _e_hat[5-d.quot-1] = 1 << d.rem; return 1; } } } // no syndrome match; multiple errors detected return 2; } // create SEC-DED (39,32) codec object fec fec_secded3932_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_SECDED3932; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_secded3932_encode; q->decode_func = &fec_secded3932_decode; q->decode_soft_func = NULL; return q; } // destroy SEC-DEC (39,32) object int fec_secded3932_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using SEC-DEC (39,32) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_secded3932_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter // determine remainder of input length / 4 unsigned int r = _dec_msg_len % 4; // for now simply encode as 4/5-rate codec (eat // last parity bit) // TODO : make more efficient for (i=0; i<_dec_msg_len-r; i+=4) { // compute parity (7 bits) on two input bytes (32 bits) _msg_enc[j+0] = fec_secded3932_compute_parity(&_msg_dec[i]); // copy remaining two input bytes (32 bits) _msg_enc[j+1] = _msg_dec[i+0]; _msg_enc[j+2] = _msg_dec[i+1]; _msg_enc[j+3] = _msg_dec[i+2]; _msg_enc[j+4] = _msg_dec[i+3]; // increment output counter j += 5; } // if input length isn't divisible by 4, encode last few bytes if (r) { // one 32-bit symbol (decoded) unsigned char m[4] = {0,0,0,0}; unsigned int n; for (n=0; n #include #include #include #include "liquid.internal.h" #define DEBUG_FEC_SECDED7264 0 // P matrix [8 x 64] // 11111111 00001111 00001111 00001100 01101000 10001000 10001000 10000000 : // 11110000 11111111 00000000 11110011 01100100 01000100 01000100 01000000 : // 00110000 11110000 11111111 00001111 00000010 00100010 00100010 00100110 : // 11001111 00000000 11110000 11111111 00000001 00010001 00010001 00010110 : // 01101000 10001000 10001000 10000000 11111111 00001111 00000000 11110011 : // 01100100 01000100 01000100 01000000 11110000 11111111 00001111 00001100 : // 00000010 00100010 00100010 00100110 11001111 00000000 11111111 00001111 : // 00000001 00010001 00010001 00010110 00110000 11110000 11110000 11111111 : unsigned char secded7264_P[64] = { 0xFF, 0x0F, 0x0F, 0x0C, 0x68, 0x88, 0x88, 0x80, 0xF0, 0xFF, 0x00, 0xF3, 0x64, 0x44, 0x44, 0x40, 0x30, 0xF0, 0xFF, 0x0F, 0x02, 0x22, 0x22, 0x26, 0xCF, 0x00, 0xF0, 0xFF, 0x01, 0x11, 0x11, 0x16, 0x68, 0x88, 0x88, 0x80, 0xFF, 0x0F, 0x00, 0xF3, 0x64, 0x44, 0x44, 0x40, 0xF0, 0xFF, 0x0F, 0x0C, 0x02, 0x22, 0x22, 0x26, 0xCF, 0x00, 0xFF, 0x0F, 0x01, 0x11, 0x11, 0x16, 0x30, 0xF0, 0xF0, 0xFF}; // syndrome vectors for errors of weight 1 unsigned char secded7264_syndrome_w1[72] = { 0x0b, 0x3b, 0x37, 0x07, 0x19, 0x29, 0x49, 0x89, 0x16, 0x26, 0x46, 0x86, 0x13, 0x23, 0x43, 0x83, 0x1c, 0x2c, 0x4c, 0x8c, 0x15, 0x25, 0x45, 0x85, 0x1a, 0x2a, 0x4a, 0x8a, 0x0d, 0xcd, 0xce, 0x0e, 0x70, 0x73, 0xb3, 0xb0, 0x51, 0x52, 0x54, 0x58, 0xa1, 0xa2, 0xa4, 0xa8, 0x31, 0x32, 0x34, 0x38, 0xc1, 0xc2, 0xc4, 0xc8, 0x61, 0x62, 0x64, 0x68, 0x91, 0x92, 0x94, 0x98, 0xe0, 0xec, 0xdc, 0xd0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; // compute parity byte on 64-byte input unsigned char fec_secded7264_compute_parity(unsigned char * _v) { // compute parity byte on message unsigned int i; unsigned char parity = 0x00; for (i=0; i<8; i++) { parity <<= 1; unsigned int p = liquid_c_ones[ secded7264_P[8*i+0] & _v[0] ] + liquid_c_ones[ secded7264_P[8*i+1] & _v[1] ] + liquid_c_ones[ secded7264_P[8*i+2] & _v[2] ] + liquid_c_ones[ secded7264_P[8*i+3] & _v[3] ] + liquid_c_ones[ secded7264_P[8*i+4] & _v[4] ] + liquid_c_ones[ secded7264_P[8*i+5] & _v[5] ] + liquid_c_ones[ secded7264_P[8*i+6] & _v[6] ] + liquid_c_ones[ secded7264_P[8*i+7] & _v[7] ]; parity |= p & 0x01; } // return parity byte return parity; } // compute syndrome on 72-bit input unsigned char fec_secded7264_compute_syndrome(unsigned char * _v) { // TODO : unwrap this loop unsigned int i; unsigned char syndrome = 0x00; for (i=0; i<8; i++) { syndrome <<= 1; // compute parity bit unsigned int p = ( (_v[0] & (1<<(8-i-1))) ? 1 : 0 ) + liquid_c_ones[ secded7264_P[8*i+0] & _v[1] ] + liquid_c_ones[ secded7264_P[8*i+1] & _v[2] ] + liquid_c_ones[ secded7264_P[8*i+2] & _v[3] ] + liquid_c_ones[ secded7264_P[8*i+3] & _v[4] ] + liquid_c_ones[ secded7264_P[8*i+4] & _v[5] ] + liquid_c_ones[ secded7264_P[8*i+5] & _v[6] ] + liquid_c_ones[ secded7264_P[8*i+6] & _v[7] ] + liquid_c_ones[ secded7264_P[8*i+7] & _v[8] ]; syndrome |= p & 0x01; } return syndrome; } int fec_secded7264_encode_symbol(unsigned char * _sym_dec, unsigned char * _sym_enc) { // compute parity on input _sym_enc[0] = fec_secded7264_compute_parity(_sym_dec); // copy input to output _sym_enc[1] = _sym_dec[0]; _sym_enc[2] = _sym_dec[1]; _sym_enc[3] = _sym_dec[2]; _sym_enc[4] = _sym_dec[3]; _sym_enc[5] = _sym_dec[4]; _sym_enc[6] = _sym_dec[5]; _sym_enc[7] = _sym_dec[6]; _sym_enc[8] = _sym_dec[7]; return LIQUID_OK; } // decode symbol, returning 0/1/2 for zero/one/multiple errors detected // _sym_enc : encoded symbol [size: 9 x 1] // _sym_dec : decoded symbol [size: 8 x 1] int fec_secded7264_decode_symbol(unsigned char * _sym_enc, unsigned char * _sym_dec) { // estimate error vector unsigned char e_hat[9] = {0,0,0,0,0,0,0,0,0}; int syndrome_flag = fec_secded7264_estimate_ehat(_sym_enc, e_hat); // compute estimated transmit vector (last 64 bits of encoded message) // NOTE: indices take into account first element in _sym_enc and e_hat // arrays holds the parity bits _sym_dec[0] = _sym_enc[1] ^ e_hat[1]; _sym_dec[1] = _sym_enc[2] ^ e_hat[2]; _sym_dec[2] = _sym_enc[3] ^ e_hat[3]; _sym_dec[3] = _sym_enc[4] ^ e_hat[4]; _sym_dec[4] = _sym_enc[5] ^ e_hat[5]; _sym_dec[5] = _sym_enc[6] ^ e_hat[6]; _sym_dec[6] = _sym_enc[7] ^ e_hat[7]; _sym_dec[7] = _sym_enc[8] ^ e_hat[8]; #if DEBUG_FEC_SECDED7264 if (syndrome_flag == 1) { printf("secded7264_decode_symbol(): single error detected!\n"); } else if (syndrome_flag == 2) { printf("secded7264_decode_symbol(): no match found (multiple errors detected)\n"); } #endif // return syndrome flag return syndrome_flag; } // estimate error vector, returning 0/1/2 for zero/one/multiple errors // detected, respectively // _sym_enc : encoded symbol [size: 9 x 1], // _e_hat : estimated error vector [size: 9 x 1] int fec_secded7264_estimate_ehat(unsigned char * _sym_enc, unsigned char * _e_hat) { // clear output array memset(_e_hat, 0x00, 9*sizeof(unsigned char)); // compute syndrome vector, s = r*H^T = ( H*r^T )^T unsigned char s = fec_secded7264_compute_syndrome(_sym_enc); // compute weight of s unsigned int ws = liquid_c_ones[s]; if (ws == 0) { // no errors detected return 0; } else { // estimate error location; search for syndrome with error // vector of weight one unsigned int n; // estimate error location for (n=0; n<72; n++) { if (s == secded7264_syndrome_w1[n]) { // single error detected at location 'n' div_t d = div(n,8); _e_hat[9-d.quot-1] = 1 << d.rem; return 1; } } } // no syndrome match; multiple errors detected return 2; } // create SEC-DED (72,64) codec object fec fec_secded7264_create(void * _opts) { fec q = (fec) malloc(sizeof(struct fec_s)); // set scheme q->scheme = LIQUID_FEC_SECDED7264; q->rate = fec_get_rate(q->scheme); // set internal function pointers q->encode_func = &fec_secded7264_encode; q->decode_func = &fec_secded7264_decode; q->decode_soft_func = NULL; return q; } // destroy SEC-DEC (72,64) object int fec_secded7264_destroy(fec _q) { free(_q); return LIQUID_OK; } // encode block of data using SEC-DEC (72,64) encoder // // _q : encoder/decoder object // _dec_msg_len : decoded message length (number of bytes) // _msg_dec : decoded message [size: 1 x _dec_msg_len] // _msg_enc : encoded message [size: 1 x 2*_dec_msg_len] int fec_secded7264_encode(fec _q, unsigned int _dec_msg_len, unsigned char * _msg_dec, unsigned char * _msg_enc) { unsigned int i=0; // decoded byte counter unsigned int j=0; // encoded byte counter unsigned char parity; // parity byte // determine remainder of input length / 8 unsigned int r = _dec_msg_len % 8; // TODO : devise more efficient way of doing this for (i=0; i<_dec_msg_len-r; i+=8) { // encode directly to output fec_secded7264_encode_symbol(&_msg_dec[i], &_msg_enc[j]); j += 9; } // if input length isn't divisible by 8, encode last few bytes if (r) { unsigned char v[8] = {0,0,0,0,0,0,0,0}; unsigned int n; for (n=0; n #include #include #include #include "liquid.internal.h" // // internal methods // // permute one iteration int interleaver_permute(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N); // permute one iteration (soft bit input) int interleaver_permute_soft(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N); // permute one iteration with mask int interleaver_permute_mask(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N, unsigned char _mask); // permute one iteration (soft bit input) with mask int interleaver_permute_mask_soft(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N, unsigned char _mask); // structured interleaver object struct interleaver_s { unsigned int n; // number of bytes unsigned int M; // row dimension unsigned int N; // col dimension // interleaving depth (number of permutations) unsigned int depth; }; // create interleaver of length _n input/output bytes interleaver interleaver_create(unsigned int _n) { interleaver q = (interleaver) malloc(sizeof(struct interleaver_s)); q->n = _n; // set internal properties q->depth = 4; // default depth to maximum // compute block dimensions q->M = 1 + (unsigned int) floorf(sqrtf(q->n)); q->N = q->n / q->M; while (q->n >= (q->M*q->N)) q->N++; // ensures M*N >= n return q; } // copy interleaver object interleaver interleaver_copy(interleaver q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("interleaver_copy(), object cannot be NULL"); return interleaver_create(q_orig->n); } // destroy interleaver object int interleaver_destroy(interleaver _q) { // free main object memory free(_q); return LIQUID_OK; } // print interleaver internals int interleaver_print(interleaver _q) { printf("interleaver [block, %u bytes] :\n", _q->n); printf(" M : %u\n", _q->M); printf(" N : %u\n", _q->N); printf(" depth : %u\n", _q->depth); return LIQUID_OK; } // set depth (number of internal iterations) int interleaver_set_depth(interleaver _q, unsigned int _depth) { _q->depth = _depth; return LIQUID_OK; } // execute forward interleaver (encoder) // _q : interleaver object // _msg_dec : decoded (un-interleaved) message // _msg_enc : encoded (interleaved) message int interleaver_encode(interleaver _q, unsigned char * _msg_dec, unsigned char * _msg_enc) { // copy data to output memmove(_msg_enc, _msg_dec, _q->n); if (_q->depth > 0) interleaver_permute(_msg_enc, _q->n, _q->M, _q->N); if (_q->depth > 1) interleaver_permute_mask(_msg_enc, _q->n, _q->M, _q->N+2, 0x0f); if (_q->depth > 2) interleaver_permute_mask(_msg_enc, _q->n, _q->M, _q->N+4, 0x55); if (_q->depth > 3) interleaver_permute_mask(_msg_enc, _q->n, _q->M, _q->N+8, 0x33); return LIQUID_OK; } // execute forward interleaver (encoder) on soft bits // _q : interleaver object // _msg_dec : decoded (un-interleaved) message // _msg_enc : encoded (interleaved) message int interleaver_encode_soft(interleaver _q, unsigned char * _msg_dec, unsigned char * _msg_enc) { // copy data to output memmove(_msg_enc, _msg_dec, 8*_q->n); if (_q->depth > 0) interleaver_permute_soft(_msg_enc, _q->n, _q->M, _q->N); if (_q->depth > 1) interleaver_permute_mask_soft(_msg_enc, _q->n, _q->M, _q->N+2, 0x0f); if (_q->depth > 2) interleaver_permute_mask_soft(_msg_enc, _q->n, _q->M, _q->N+4, 0x55); if (_q->depth > 3) interleaver_permute_mask_soft(_msg_enc, _q->n, _q->M, _q->N+8, 0x33); return LIQUID_OK; } // execute reverse interleaver (decoder) // _q : interleaver object // _msg_enc : encoded (interleaved) message // _msg_dec : decoded (un-interleaved) message int interleaver_decode(interleaver _q, unsigned char * _msg_enc, unsigned char * _msg_dec) { // copy data to output memmove(_msg_dec, _msg_enc, _q->n); if (_q->depth > 3) interleaver_permute_mask(_msg_dec, _q->n, _q->M, _q->N+8, 0x33); if (_q->depth > 2) interleaver_permute_mask(_msg_dec, _q->n, _q->M, _q->N+4, 0x55); if (_q->depth > 1) interleaver_permute_mask(_msg_dec, _q->n, _q->M, _q->N+2, 0x0f); if (_q->depth > 0) interleaver_permute(_msg_dec, _q->n, _q->M, _q->N); return LIQUID_OK; } // execute reverse interleaver (decoder) on soft bits // _q : interleaver object // _msg_enc : encoded (interleaved) message // _msg_dec : decoded (un-interleaved) message int interleaver_decode_soft(interleaver _q, unsigned char * _msg_enc, unsigned char * _msg_dec) { // copy data to output memmove(_msg_dec, _msg_enc, 8*_q->n); if (_q->depth > 3) interleaver_permute_mask_soft(_msg_dec, _q->n, _q->M, _q->N+8, 0x33); if (_q->depth > 2) interleaver_permute_mask_soft(_msg_dec, _q->n, _q->M, _q->N+4, 0x55); if (_q->depth > 1) interleaver_permute_mask_soft(_msg_dec, _q->n, _q->M, _q->N+2, 0x0f); if (_q->depth > 0) interleaver_permute_soft(_msg_dec, _q->n, _q->M, _q->N); return LIQUID_OK; } // // internal permutation methods // // permute one iteration int interleaver_permute(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N) { unsigned int i; unsigned int j; unsigned int m=0; unsigned int n=_n/3; unsigned int n2=_n/2; unsigned char tmp; for (i=0; i=n2); // swap indices tmp = _x[2*j+1]; _x[2*j+1] = _x[2*i+0]; _x[2*i+0] = tmp; } return LIQUID_OK; } // permute one iteration (soft bit input) int interleaver_permute_soft(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N) { unsigned int i; unsigned int j; unsigned int m=0; unsigned int n=_n/3; unsigned int n2=_n/2; unsigned char tmp[8]; for (i=0; i=n2); // swap soft bits at indices memmove( tmp, &_x[8*(2*j+1)], 8); memmove( &_x[8*(2*j+1)], &_x[8*(2*i+0)], 8); memmove( &_x[8*(2*i+0)], tmp, 8); } //printf("\n"); return LIQUID_OK; } // permute one iteration with mask int interleaver_permute_mask(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N, unsigned char _mask) { unsigned int i; unsigned int j; unsigned int m=0; unsigned int n=_n/3; unsigned int n2=_n/2; unsigned char tmp0; unsigned char tmp1; for (i=0; i=n2); // swap indices, applying mask tmp0 = (_x[2*i+0] & (~_mask)) | (_x[2*j+1] & ( _mask)); tmp1 = (_x[2*i+0] & ( _mask)) | (_x[2*j+1] & (~_mask)); _x[2*i+0] = tmp0; _x[2*j+1] = tmp1; } return LIQUID_OK; } // permute one iteration (soft bit input) int interleaver_permute_mask_soft(unsigned char * _x, unsigned int _n, unsigned int _M, unsigned int _N, unsigned char _mask) { unsigned int i; unsigned int j; unsigned int k; unsigned int m=0; unsigned int n=_n/3; unsigned int n2=_n/2; unsigned char tmp; for (i=0; i=n2); // swap bits matching the mask for (k=0; k<8; k++) { if ( (_mask >> (8-k-1)) & 0x01 ) { tmp = _x[8*(2*j+1)+k]; _x[8*(2*j+1)+k] = _x[8*(2*i+0)+k]; _x[8*(2*i+0)+k] = tmp; } } } //printf("\n"); return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/packetizer.c000066400000000000000000000335771474751757600202600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Packetizer // #include #include #include #include "liquid.internal.h" // fec/interleaver plan struct fecintlv_plan { unsigned int dec_msg_len; // decoded message length unsigned int enc_msg_len; // encoded message length fec_scheme fs; // error-correction scheme fec f; // error-correction object interleaver q; // interleaver object }; // packetizer object struct packetizer_s { unsigned int msg_len; // original message length [bytes] unsigned int packet_len; // output packet length [bytes] crc_scheme check; // check scheme unsigned int crc_length; // check object struct fecintlv_plan* plan; // array of fec/interleaver plans unsigned int plan_len; // number of steps in plan // buffers (ping-pong) unsigned int buffer_len; // length of each buffer unsigned char * buffer_0; unsigned char * buffer_1; }; // reallocate memory for buffers int packetizer_realloc_buffers(packetizer _p, unsigned int _len); // computes the number of encoded bytes after packetizing // // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code unsigned int packetizer_compute_enc_msg_len(unsigned int _n, int _crc, int _fec0, int _fec1) { unsigned int k = _n + crc_get_length(_crc); unsigned int n0 = fec_get_enc_msg_length(_fec0, k); unsigned int n1 = fec_get_enc_msg_length(_fec1, n0); return n1; } // computes the number of decoded bytes before packetizing // // _k : number of encoded bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code unsigned int packetizer_compute_dec_msg_len(unsigned int _k, int _crc, int _fec0, int _fec1) { unsigned int n_hat = 0; unsigned int k_hat = 0; // check for zero-length packet // TODO : implement faster method while (k_hat < _k) { // compute encoded packet length k_hat = packetizer_compute_enc_msg_len(n_hat, _crc, _fec0, _fec1); // if (k_hat == _k) return n_hat; else if (k_hat > _k) return n_hat; // TODO : check this special condition else n_hat++; } return 0; } // create packetizer object // // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code packetizer packetizer_create(unsigned int _n, int _crc, int _fec0, int _fec1) { packetizer p = (packetizer) malloc(sizeof(struct packetizer_s)); p->msg_len = _n; p->packet_len = packetizer_compute_enc_msg_len(_n, _crc, _fec0, _fec1); p->check = _crc; p->crc_length = crc_get_length(p->check); // allocate memory for buffers (scale by 8 for soft decoding) p->buffer_len = p->packet_len; p->buffer_0 = (unsigned char*) malloc(8*p->buffer_len); p->buffer_1 = (unsigned char*) malloc(8*p->buffer_len); // create plan p->plan_len = 2; p->plan = (struct fecintlv_plan*) malloc((p->plan_len)*sizeof(struct fecintlv_plan)); // set schemes unsigned int i; unsigned int n0 = _n + p->crc_length; for (i=0; iplan_len; i++) { // set schemes p->plan[i].fs = (i==0) ? _fec0 : _fec1; // compute lengths p->plan[i].dec_msg_len = n0; p->plan[i].enc_msg_len = fec_get_enc_msg_length(p->plan[i].fs, p->plan[i].dec_msg_len); // create objects p->plan[i].f = fec_create(p->plan[i].fs, NULL); p->plan[i].q = interleaver_create(p->plan[i].enc_msg_len); // set interleaver depth to zero if no error correction scheme // is applied to this plan if (p->plan[i].fs == LIQUID_FEC_NONE) interleaver_set_depth(p->plan[i].q, 0); // update length n0 = p->plan[i].enc_msg_len; } return p; } // re-create packetizer object // // _p : initialz packetizer object // _n : number of uncoded input bytes // _crc : error-detecting scheme // _fec0 : inner forward error-correction code // _fec1 : outer forward error-correction code packetizer packetizer_recreate(packetizer _p, unsigned int _n, int _crc, int _fec0, int _fec1) { if (_p == NULL) { // packetizer was never created return packetizer_create(_n, _crc, _fec0, _fec1); } // check values if (_p->msg_len == _n && _p->check == _crc && _p->plan[0].fs == _fec0 && _p->plan[1].fs == _fec1 ) { // no change; return input pointer return _p; } // something has changed; destroy old object and create new one // TODO : rather than completely destroying object, only change values that are necessary packetizer_destroy(_p); return packetizer_create(_n,_crc,_fec0,_fec1); } // destroy packetizer object packetizer packetizer_copy(packetizer q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("packetizer_copy(), object cannot be NULL"); // strip parameters and create new object from them // TODO: handle case where plan_len != 2 unsigned int n = q_orig->msg_len; int crc = q_orig->check; int fec0 = q_orig->plan[0].fs; int fec1 = q_orig->plan[1].fs; return packetizer_create(n, crc, fec0, fec1); } // destroy packetizer object int packetizer_destroy(packetizer _p) { if (!_p) return liquid_error(LIQUID_EIOBJ,"packetizer_destroy(), input is a NULL pointer"); // free fec, interleaver objects unsigned int i; for (i=0; i<_p->plan_len; i++) { fec_destroy(_p->plan[i].f); interleaver_destroy(_p->plan[i].q); }; // free plan free(_p->plan); // free buffers free(_p->buffer_0); free(_p->buffer_1); // free packetizer object free(_p); return LIQUID_OK; } // print packetizer object internals int packetizer_print(packetizer _p) { printf("packetizer [dec: %u, enc: %u]\n", _p->msg_len, _p->packet_len); printf(" : crc %-10u %-10u %-16s\n", _p->msg_len, _p->msg_len + _p->crc_length, crc_scheme_str[_p->check][0]); unsigned int i; for (i=0; i<_p->plan_len; i++) { printf("%4u : fec %-10u %-10u %-16s\n", i, _p->plan[i].dec_msg_len, _p->plan[i].enc_msg_len, fec_scheme_str[_p->plan[i].fs][1]); } return LIQUID_OK; } // get decoded message length unsigned int packetizer_get_dec_msg_len(packetizer _p) { return _p->msg_len; } // get encoded message length unsigned int packetizer_get_enc_msg_len(packetizer _p) { return _p->packet_len; } crc_scheme packetizer_get_crc(packetizer _p) { return _p->check; } fec_scheme packetizer_get_fec0(packetizer _p) { return _p->plan[0].fs; } fec_scheme packetizer_get_fec1(packetizer _p) { return _p->plan[1].fs; } // Execute the packetizer on an input message // // _p : packetizer object // _msg : input message (uncoded bytes) // _pkt : encoded output message int packetizer_encode(packetizer _p, const unsigned char * _msg, unsigned char * _pkt) { unsigned int i; // copy input message to internal buffer[0] (or initialize to zeros) if (_msg != NULL) { // copy user-defined input memmove(_p->buffer_0, _msg, _p->msg_len); } else { // initialize with zeros memset(_p->buffer_0, 0x00, _p->msg_len); } // compute crc, append to buffer unsigned int key = crc_generate_key(_p->check, _p->buffer_0, _p->msg_len); for (i=0; i<_p->crc_length; i++) { // append byte to buffer _p->buffer_0[_p->msg_len+_p->crc_length-i-1] = key & 0xff; // shift key by 8 bits key >>= 8; } // whiten input sequence scramble_data(_p->buffer_0, _p->msg_len + _p->crc_length); // execute fec/interleaver plans for (i=0; i<_p->plan_len; i++) { // run the encoder: buffer[0] > buffer[1] fec_encode(_p->plan[i].f, _p->plan[i].dec_msg_len, _p->buffer_0, _p->buffer_1); // run the interleaver: buffer[1] > buffer[0] interleaver_encode(_p->plan[i].q, _p->buffer_1, _p->buffer_0); } // copy result to output memmove(_pkt, _p->buffer_0, _p->packet_len); return LIQUID_OK; } // Execute the packetizer to decode an input message, return validity // check of resulting data // // _p : packetizer object // _pkt : input message (coded bytes) // _msg : decoded output message int packetizer_decode(packetizer _p, const unsigned char * _pkt, unsigned char * _msg) { // copy coded message to internal buffer[0] memmove(_p->buffer_0, _pkt, _p->packet_len); // execute fec/interleaver plans unsigned int i; for (i=_p->plan_len; i>0; i--) { // run the de-interleaver: buffer[0] > buffer[1] interleaver_decode(_p->plan[i-1].q, _p->buffer_0, _p->buffer_1); // run the decoder: buffer[1] > buffer[0] fec_decode(_p->plan[i-1].f, _p->plan[i-1].dec_msg_len, _p->buffer_1, _p->buffer_0); } // remove sequence whitening unscramble_data(_p->buffer_0, _p->msg_len + _p->crc_length); // strip crc, validate message unsigned int key = 0; for (i=0; i<_p->crc_length; i++) { key <<= 8; key |= _p->buffer_0[_p->msg_len+i]; } // copy result to output memmove(_msg, _p->buffer_0, _p->msg_len); // return crc validity return crc_validate_message(_p->check, _p->buffer_0, _p->msg_len, key); } // Execute the packetizer to decode an input message, return validity // check of resulting data // // _p : packetizer object // _pkt : input message (coded soft bits) // _msg : decoded output message int packetizer_decode_soft(packetizer _p, const unsigned char * _pkt, unsigned char * _msg) { // copy coded message to internal buffer[0] memmove(_p->buffer_0, _pkt, 8*_p->packet_len); // // decode outer level using soft decoding // // run the de-interleaver: buffer[0] > buffer[1] interleaver_decode_soft(_p->plan[1].q, _p->buffer_0, _p->buffer_1); // run the decoder: buffer[1] > buffer[0] fec_decode_soft(_p->plan[1].f, _p->plan[1].dec_msg_len, _p->buffer_1, _p->buffer_0); // // decode inner level using hard decoding // // run the de-interleaver: buffer[0] > buffer[1] interleaver_decode(_p->plan[0].q, _p->buffer_0, _p->buffer_1); // run the decoder: buffer[1] > buffer[0] fec_decode(_p->plan[0].f, _p->plan[0].dec_msg_len, _p->buffer_1, _p->buffer_0); // remove sequence whitening unscramble_data(_p->buffer_0, _p->msg_len + _p->crc_length); // strip crc, validate message unsigned int key = 0; unsigned int i; for (i=0; i<_p->crc_length; i++) { key <<= 8; key |= _p->buffer_0[_p->msg_len+i]; } // copy result to output memmove(_msg, _p->buffer_0, _p->msg_len); // return crc validity return crc_validate_message(_p->check, _p->buffer_0, _p->msg_len, key); } // // internal methods // int packetizer_realloc_buffers(packetizer _p, unsigned int _len) { _p->buffer_len = _len; _p->buffer_0 = (unsigned char*) realloc(_p->buffer_0, _p->buffer_len); _p->buffer_1 = (unsigned char*) realloc(_p->buffer_1, _p->buffer_len); return LIQUID_OK; } liquid-dsp-1.7.0/src/fec/src/sumproduct.c000066400000000000000000000150101474751757600203020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sumproduct.c // // floating-point implementation of the sum-product algorithm // #include #include #include #include "liquid.internal.h" #define DEBUG_SUMPRODUCT 0 // phi(x) = -logf( tanhf( x/2 ) ) float sumproduct_phi(float _x) { return -logf(tanhf(_x/2.0f + 1e-12)); } // iterate over the sum-product algorithm: // returns 1 if parity checks, 0 otherwise // _m : rows // _n : cols // _H : sparse binary parity check matrix [size: _m x _n] // _LLR : received signal (soft bits, LLR) [size: _n x 1] // _c_hat : estimated transmitted signal [size: _n x 1] // _max_steps : maximum number of steps before bailing int fec_sumproduct(unsigned int _m, unsigned int _n, smatrixb _H, float * _LLR, unsigned char * _c_hat, unsigned int _max_steps) { // TODO : validate input if (_n == 0 || _m == 0) return liquid_error(LIQUID_EICONFIG,"fec_sumproduct(), matrix dimensions cannot be zero"); // internal variables unsigned int num_iterations = 0; float Lq[_m*_n]; float Lr[_m*_n]; float Lc[_n]; float LQ[_n]; unsigned char parity[_m]; unsigned int i; unsigned int j; int parity_pass; int continue_running = 1; // initialize Lq with log-likelihood values for (i=0; i<_n; i++) Lc[i] = _LLR[i]; //Lc[i] = 2.0f * _y[i] / (sigma*sigma); for (j=0; j<_m; j++) { for (i=0; i<_n; i++) { Lq[j*_n+i] = smatrixb_get(_H,j,i) ? Lc[i] : 0.0f; } } #if DEBUG_SUMPRODUCT // print Lc matrixf_print(Lc,1,_n); #endif // TODO : run multiple iterations while (continue_running) { #if DEBUG_SUMPRODUCT // printf("\n"); printf("************* iteration %u ****************\n", num_iterations); #endif // step sum-product algorithm //parity_pass = fec_sumproduct_step(_H,_m,_n,_c_hat,Lq,Lr,Lc,LQ,parity); parity_pass = fec_sumproduct_step(_m,_n,_H,_c_hat,Lq,Lr,Lc,LQ,parity); // update... num_iterations++; if (parity_pass || num_iterations == _max_steps) continue_running = 0; } return parity_pass; } // sum-product algorithm, returns 1 if parity checks, 0 otherwise // _m : rows // _n : cols // _H : sparse binary parity check matrix [size: _m x _n] // _c_hat : estimated transmitted signal [size: _n x 1] // // internal state arrays // _Lq : [size: _m x _n] // _Lr : [size: _m x _n] // _Lc : [size: _n x 1] // _LQ : [size: _n x 1] // _parity : _H * _c_hat [size: _m x 1] int fec_sumproduct_step(unsigned int _m, unsigned int _n, smatrixb _H, unsigned char * _c_hat, float * _Lq, float * _Lr, float * _Lc, float * _LQ, unsigned char * _parity) { unsigned int i; unsigned int j; unsigned int ip; unsigned int jp; float alpha_prod; float phi_sum; int parity_pass; // compute Lr for (i=0; i<_n; i++) { for (j=0; j<_m; j++) { alpha_prod = 1.0f; phi_sum = 0.0f; for (ip=0; ip<_n; ip++) { //if (_H[j*_n+ip]==1 && i != ip) { if (smatrixb_get(_H,j,ip)==1 && i != ip) { float alpha = _Lq[j*_n+ip] > 0.0f ? 1.0f : -1.0f; float beta = fabsf(_Lq[j*_n+ip]); phi_sum += sumproduct_phi(beta); alpha_prod *= alpha; } } _Lr[j*_n+i] = alpha_prod * sumproduct_phi(phi_sum); } } #if DEBUG_SUMPRODUCT // print Lq matrixf_print(_Lq,_m,_n); // print Lr matrixf_print(_Lr,_m,_n); #endif // compute next iteration of Lq for (i=0; i<_n; i++) { for (j=0; j<_m; j++) { // initialize with LLR _Lq[j*_n+i] = _Lc[i]; for (jp=0; jp<_m; jp++) { //if (_H[jp*_n+i]==1 && j != jp) if (smatrixb_get(_H,jp,i)==1 && j != jp) _Lq[j*_n+i] += _Lr[jp*_n+i]; } } } #if DEBUG_SUMPRODUCT // print Lq matrixf_print(_Lq,_m,_n); #endif // compute LQ for (i=0; i<_n; i++) { _LQ[i] = _Lc[i]; // initialize with LLR value for (j=0; j<_m; j++) { //if (_H[j*_n+i]==1) if (smatrixb_get(_H,j,i)==1) _LQ[i] += _Lr[j*_n+i]; } } #if DEBUG_SUMPRODUCT // print LQ matrixf_print(_LQ,1,_n); #endif // compute hard-decoded value for (i=0; i<_n; i++) _c_hat[i] = _LQ[i] < 0.0f ? 1 : 0; // compute parity check: p = H*c_hat smatrixb_vmul(_H, _c_hat, _parity); // check parity parity_pass = 1; for (j=0; j<_m; j++) { if (_parity[j]) parity_pass = 0; } #if DEBUG_SUMPRODUCT // print hard-decision output printf(" : c hat = ["); for (i=0; i<_n; i++) printf(" %1u", _c_hat[i]); printf(" ], "); // print parity printf("parity = ["); for (j=0; j<_m; j++) printf(" %1u", _parity[j]); printf(" ], "); printf(" (%s)\n", parity_pass ? "pass" : "FAIL"); #endif return parity_pass; } liquid-dsp-1.7.0/src/fec/tests/000077500000000000000000000000001474751757600163075ustar00rootroot00000000000000liquid-dsp-1.7.0/src/fec/tests/crc_autotest.c000066400000000000000000000114611474751757600211550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: reverse byte // void autotest_reverse_byte() { // 0110 0010 unsigned char b = 0x62; // 0100 0110 unsigned char r = 0x46; // CONTEND_EQUALITY(liquid_reverse_byte(b),r); } // // AUTOTEST: reverse uint16_t // void autotest_reverse_uint16() { // 1111 0111 0101 1001 unsigned int b = 0xF759; // 1001 1010 1110 1111 unsigned int r = 0x9AEF; // CONTEND_EQUALITY(liquid_reverse_uint16(b),r); } // AUTOTEST: reverse uint32_t void autotest_reverse_uint32() { // 0110 0010 1101 1001 0011 1011 1111 0000 unsigned int b = 0x62D93BF0; // 0000 1111 1101 1100 1001 1011 0100 0110 unsigned int r = 0x0FDC9B46; // CONTEND_EQUALITY(liquid_reverse_uint32(b),r); } // autotest helper function void testbench_autotest_crc(crc_scheme _check, unsigned int _n) { unsigned int i; // generate pseudo-random data unsigned char data[_n]; msequence ms = msequence_create_default(9); for (i=0; i<_n; i++) data[i] = msequence_generate_symbol(ms,8); msequence_destroy(ms); // generate key unsigned int key = crc_generate_key(_check, data, _n); // contend data/key are valid CONTEND_EXPRESSION(crc_validate_message(_check, data, _n, key)); // test flipping bit value at each location in message and confirm check fails unsigned char data_corrupt[_n]; unsigned int j; for (i=0; i<_n; i++) { for (j=0; j<8; j++) { // copy original data sequence memmove(data_corrupt, data, _n*sizeof(unsigned char)); // flip bit j at byte i data[i] ^= (1 << j); // contend data/key are invalid CONTEND_EXPRESSION(crc_validate_message(_check, data, _n, key)==0); } } } // validate error-detection tests void autotest_checksum() { testbench_autotest_crc(LIQUID_CRC_CHECKSUM, 16); } void autotest_crc8() { testbench_autotest_crc(LIQUID_CRC_8, 16); } void autotest_crc16() { testbench_autotest_crc(LIQUID_CRC_16, 64); } void autotest_crc24() { testbench_autotest_crc(LIQUID_CRC_24, 64); } void autotest_crc32() { testbench_autotest_crc(LIQUID_CRC_32, 64); } void autotest_crc_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping crc config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif CONTEND_EQUALITY(LIQUID_OK, liquid_print_crc_schemes()) CONTEND_EQUALITY(LIQUID_CRC_UNKNOWN, liquid_getopt_str2crc("unknown")) CONTEND_EQUALITY(LIQUID_CRC_UNKNOWN, liquid_getopt_str2crc("rosebud")) CONTEND_EQUALITY(LIQUID_CRC_NONE, liquid_getopt_str2crc("none")) CONTEND_EQUALITY(LIQUID_CRC_CHECKSUM, liquid_getopt_str2crc("checksum")) CONTEND_EQUALITY(LIQUID_CRC_8, liquid_getopt_str2crc("crc8")) CONTEND_EQUALITY(LIQUID_CRC_16, liquid_getopt_str2crc("crc16")) CONTEND_EQUALITY(LIQUID_CRC_24, liquid_getopt_str2crc("crc24")) CONTEND_EQUALITY(LIQUID_CRC_32, liquid_getopt_str2crc("crc32")) // check length CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_UNKNOWN), 0); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_NONE), 0); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_CHECKSUM), 1); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_8), 1); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_16), 2); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_24), 3); CONTEND_EQUALITY(crc_get_length(LIQUID_CRC_32), 4); CONTEND_EQUALITY(crc_get_length(-1), 0); } liquid-dsp-1.7.0/src/fec/tests/fec_autotest.c000066400000000000000000000121031474751757600211350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // Helper function to keep code base small void fec_test_codec(fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED switch (_fs) { case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; default:; } #endif // generate fec object fec q = fec_create(_fs,_opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,_n); unsigned char msg[_n]; // original message unsigned char msg_enc[n_enc]; // encoded message unsigned char msg_dec[_n]; // decoded message // initialize message unsigned int i; for (i=0; i<_n; i++) { msg[i] = rand() & 0xff; msg_dec[i] = 0; } // encode message fec_encode(q,_n,msg,msg_enc); // channel: add single error msg_enc[0] ^= 0x01; // decode message fec_decode(q,_n,msg_enc,msg_dec); // validate output CONTEND_SAME_DATA(msg,msg_dec,_n); // clean up objects fec_destroy(q); } // // AUTOTESTS: basic encode/decode functionality // // repeat codes void autotest_fec_r3() { fec_test_codec(LIQUID_FEC_REP3, 64, NULL); } void autotest_fec_r5() { fec_test_codec(LIQUID_FEC_REP5, 64, NULL); } // Hamming block codes void autotest_fec_h74() { fec_test_codec(LIQUID_FEC_HAMMING74, 64, NULL); } void autotest_fec_h84() { fec_test_codec(LIQUID_FEC_HAMMING84, 64, NULL); } void autotest_fec_h128() { fec_test_codec(LIQUID_FEC_HAMMING128, 64, NULL); } // Golay block codes void autotest_fec_g2412() { fec_test_codec(LIQUID_FEC_GOLAY2412, 64, NULL); } // SEC-DED block codecs void autotest_fec_secded2216() { fec_test_codec(LIQUID_FEC_SECDED2216, 64, NULL); } void autotest_fec_secded3932() { fec_test_codec(LIQUID_FEC_SECDED3932, 64, NULL); } void autotest_fec_secded7264() { fec_test_codec(LIQUID_FEC_SECDED7264, 64, NULL); } // convolutional codes void autotest_fec_v27() { fec_test_codec(LIQUID_FEC_CONV_V27, 64, NULL); } void autotest_fec_v29() { fec_test_codec(LIQUID_FEC_CONV_V29, 64, NULL); } void autotest_fec_v39() { fec_test_codec(LIQUID_FEC_CONV_V39, 64, NULL); } void autotest_fec_v615() { fec_test_codec(LIQUID_FEC_CONV_V615, 64, NULL); } // convolutional codes (punctured) void autotest_fec_v27p23() { fec_test_codec(LIQUID_FEC_CONV_V27P23, 64, NULL); } void autotest_fec_v27p34() { fec_test_codec(LIQUID_FEC_CONV_V27P34, 64, NULL); } void autotest_fec_v27p45() { fec_test_codec(LIQUID_FEC_CONV_V27P45, 64, NULL); } void autotest_fec_v27p56() { fec_test_codec(LIQUID_FEC_CONV_V27P56, 64, NULL); } void autotest_fec_v27p67() { fec_test_codec(LIQUID_FEC_CONV_V27P67, 64, NULL); } void autotest_fec_v27p78() { fec_test_codec(LIQUID_FEC_CONV_V27P78, 64, NULL); } void autotest_fec_v29p23() { fec_test_codec(LIQUID_FEC_CONV_V29P23, 64, NULL); } void autotest_fec_v29p34() { fec_test_codec(LIQUID_FEC_CONV_V29P34, 64, NULL); } void autotest_fec_v29p45() { fec_test_codec(LIQUID_FEC_CONV_V29P45, 64, NULL); } void autotest_fec_v29p56() { fec_test_codec(LIQUID_FEC_CONV_V29P56, 64, NULL); } void autotest_fec_v29p67() { fec_test_codec(LIQUID_FEC_CONV_V29P67, 64, NULL); } void autotest_fec_v29p78() { fec_test_codec(LIQUID_FEC_CONV_V29P78, 64, NULL); } // Reed-Solomon block codes void autotest_fec_rs8() { fec_test_codec(LIQUID_FEC_RS_M8, 64, NULL); } liquid-dsp-1.7.0/src/fec/tests/fec_config_autotest.c000066400000000000000000000237571474751757600225030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.internal.h" void autotest_fec_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping fec_hamming3126 config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // symbols too large CONTEND_EQUALITY(fec_golay2412_encode_symbol(1u<<12), 0) CONTEND_EQUALITY(fec_golay2412_decode_symbol(1u<<24), 0) CONTEND_EQUALITY(fec_hamming3126_encode_symbol(1u<<26), 0) CONTEND_EQUALITY(fec_hamming3126_decode_symbol(1u<<31), 0) CONTEND_EQUALITY(fec_hamming1511_encode_symbol(1u<<11), 0) CONTEND_EQUALITY(fec_hamming1511_decode_symbol(1u<<15), 0) CONTEND_EQUALITY(fec_hamming128_encode_symbol(1u<<8), 0) CONTEND_EQUALITY(fec_hamming128_decode_symbol(1u<<12), 0) // check printing schemes CONTEND_EQUALITY(liquid_print_fec_schemes(), LIQUID_OK); } void autotest_fec_str2fec() { // start with invalid case fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); CONTEND_EQUALITY(liquid_getopt_str2fec("invalid scheme"), LIQUID_MODEM_UNKNOWN); // check normal cases CONTEND_EQUALITY( liquid_getopt_str2fec("none"), LIQUID_FEC_NONE); CONTEND_EQUALITY( liquid_getopt_str2fec("rep3"), LIQUID_FEC_REP3); CONTEND_EQUALITY( liquid_getopt_str2fec("rep5"), LIQUID_FEC_REP5); CONTEND_EQUALITY( liquid_getopt_str2fec("h74"), LIQUID_FEC_HAMMING74); CONTEND_EQUALITY( liquid_getopt_str2fec("h84"), LIQUID_FEC_HAMMING84); CONTEND_EQUALITY( liquid_getopt_str2fec("h128"), LIQUID_FEC_HAMMING128); CONTEND_EQUALITY( liquid_getopt_str2fec("g2412"), LIQUID_FEC_GOLAY2412); CONTEND_EQUALITY( liquid_getopt_str2fec("secded2216"), LIQUID_FEC_SECDED2216); CONTEND_EQUALITY( liquid_getopt_str2fec("secded3932"), LIQUID_FEC_SECDED3932); CONTEND_EQUALITY( liquid_getopt_str2fec("secded7264"), LIQUID_FEC_SECDED7264); CONTEND_EQUALITY( liquid_getopt_str2fec("v27"), LIQUID_FEC_CONV_V27); CONTEND_EQUALITY( liquid_getopt_str2fec("v29"), LIQUID_FEC_CONV_V29); CONTEND_EQUALITY( liquid_getopt_str2fec("v39"), LIQUID_FEC_CONV_V39); CONTEND_EQUALITY( liquid_getopt_str2fec("v615"), LIQUID_FEC_CONV_V615); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p23"), LIQUID_FEC_CONV_V27P23); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p34"), LIQUID_FEC_CONV_V27P34); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p45"), LIQUID_FEC_CONV_V27P45); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p56"), LIQUID_FEC_CONV_V27P56); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p67"), LIQUID_FEC_CONV_V27P67); CONTEND_EQUALITY( liquid_getopt_str2fec("v27p78"), LIQUID_FEC_CONV_V27P78); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p23"), LIQUID_FEC_CONV_V29P23); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p34"), LIQUID_FEC_CONV_V29P34); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p45"), LIQUID_FEC_CONV_V29P45); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p56"), LIQUID_FEC_CONV_V29P56); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p67"), LIQUID_FEC_CONV_V29P67); CONTEND_EQUALITY( liquid_getopt_str2fec("v29p78"), LIQUID_FEC_CONV_V29P78); CONTEND_EQUALITY( liquid_getopt_str2fec("rs8"), LIQUID_FEC_RS_M8); } void autotest_fec_is_convolutional() { CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_NONE), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_REP3), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_REP5), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING74), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING84), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_HAMMING128), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_GOLAY2412), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED2216), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED3932), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_SECDED7264), 0 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V39), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V615), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P23), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P34), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P45), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P56), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P67), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V27P78), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P23), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P34), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P45), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P56), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P67), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_CONV_V29P78), 1 ); CONTEND_EQUALITY( fec_scheme_is_convolutional(LIQUID_FEC_RS_M8), 0 ); } void autotest_fec_is_punctured() { CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_NONE), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_REP3), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_REP5), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING74), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING84), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_HAMMING128), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_GOLAY2412), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED2216), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED3932), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_SECDED7264), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V39), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V615), 0 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P23), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P34), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P45), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P56), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P67), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V27P78), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P23), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P34), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P45), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P56), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P67), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_CONV_V29P78), 1 ); CONTEND_EQUALITY( fec_scheme_is_punctured(LIQUID_FEC_RS_M8), 0 ); } void autotest_fec_is_reedsolomon() { CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_NONE), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_REP3), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_HAMMING74), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_GOLAY2412), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_SECDED2216), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_CONV_V27), 0 ); CONTEND_EQUALITY( fec_scheme_is_reedsolomon(LIQUID_FEC_RS_M8), 1 ); } void autotest_fec_is_hamming() { CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_NONE), 0 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_REP3), 0 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING74), 1 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING84), 1 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_HAMMING128), 1 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_GOLAY2412), 0 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_SECDED2216), 0 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_CONV_V27), 0 ); CONTEND_EQUALITY( fec_scheme_is_hamming(LIQUID_FEC_RS_M8), 0 ); } liquid-dsp-1.7.0/src/fec/tests/fec_copy_autotest.c000066400000000000000000000126131474751757600221750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // Helper function to keep code base small void fec_test_copy(fec_scheme _fs) { #if !LIBFEC_ENABLED switch (_fs) { case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; default:; } #endif unsigned int n_dec = 64; void * opts = NULL; // generate fec object fec q0 = fec_create(_fs,opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,n_dec); unsigned char msg_org[n_dec]; // original message unsigned char msg_enc_0[n_enc]; // encoded message (orig) unsigned char msg_enc_1[n_enc]; // encoded message (copy) unsigned char msg_dec_0[n_dec]; // decoded message (orig) unsigned char msg_dec_1[n_dec]; // decoded message (copy) // initialize random message bits unsigned int i; for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" // generate random error vector with 'n' ones; // maybe not efficient but effective unsigned int golay2412_generate_error_vector(unsigned int _n) { if (_n > 24) { liquid_error(LIQUID_EINT,"golay2412_generate_error_vector(), cannot generate more than 24 errors"); return 0; } unsigned int i; unsigned int error_locations[24]; for (i=0; i<24; i++) error_locations[i] = 0; unsigned int t=0; for (i=0; i<_n; i++) { do { // generate random error location t = rand() % 24; // check error location } while (error_locations[t]); error_locations[t] = 1; } // generate error vector unsigned int e = 0; for (i=0; i<24; i++) e |= error_locations[i] ? (1 << i) : 0; return e; } // // AUTOTEST: Golay(24,12) codec // void autotest_golay2412_codec() { unsigned int num_trials=50; // number of symbol trials unsigned int num_errors; // number of errors unsigned int i; for (num_errors=0; num_errors<=3; num_errors++) { for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: Hamming (12,8) codec // void autotest_hamming128_codec() { unsigned int n=8; // unsigned int k=12; // unsigned int i; // index of bit to corrupt for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: Hamming (15,11) codec // void autotest_hamming1511_codec() { unsigned int n=11; // unsigned int k=15; // unsigned int i; // index of bit to corrupt for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: Hamming (31,26) codec // void autotest_hamming3126_codec() { unsigned int n=26; // unsigned int k=31; // unsigned int i; // index of bit to corrupt for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: Reed-Solomon codecs // void autotest_reedsolomon_223_255() { #if !LIBFEC_ENABLED liquid_error(LIQUID_EUMODE,"Reed-Solomon codes unavailable (install libfec)"); return; #endif unsigned int dec_msg_len = 223; // compute and test encoded message length unsigned int enc_msg_len = fec_get_enc_msg_length(LIQUID_FEC_RS_M8,dec_msg_len); CONTEND_EQUALITY( enc_msg_len, 255 ); // create arrays unsigned char msg_org[dec_msg_len]; // original message unsigned char msg_enc[enc_msg_len]; // encoded message unsigned char msg_rec[enc_msg_len]; // received message unsigned char msg_dec[dec_msg_len]; // decoded message // initialize original message unsigned int i; for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: SEC-DEC (22,16) codec (no errors) // void autotest_secded2216_codec_e0() { // generate symbol unsigned char sym_org[2]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[3]; fec_secded2216_encode_symbol(sym_org, sym_enc); // decoded symbol unsigned char sym_dec[2]; fec_secded2216_decode_symbol(sym_enc, sym_dec); // validate data are the same CONTEND_EQUALITY(sym_org[0], sym_dec[0]); CONTEND_EQUALITY(sym_org[1], sym_dec[1]); } // // AUTOTEST: SEC-DEC (22,16) codec (single error) // void autotest_secded2216_codec_e1() { unsigned int k; // error location for (k=0; k<22; k++) { // generate symbol unsigned char sym_org[2]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[3]; fec_secded2216_encode_symbol(sym_org, sym_enc); // generate error vector (single error) unsigned char e[3] = {0,0,0}; div_t d = div(k,8); e[3-d.quot-1] = 1 << d.rem; // received symbol unsigned char sym_rec[3]; sym_rec[0] = sym_enc[0] ^ e[0]; sym_rec[1] = sym_enc[1] ^ e[1]; sym_rec[2] = sym_enc[2] ^ e[2]; // decoded symbol unsigned char sym_dec[2]; fec_secded2216_decode_symbol(sym_rec, sym_dec); // validate data are the same CONTEND_EQUALITY(sym_org[0], sym_dec[0]); CONTEND_EQUALITY(sym_org[1], sym_dec[1]); } } // // AUTOTEST: SEC-DEC (22,16) codec (double error detection) // void autotest_secded2216_codec_e2() { // total combinations of double errors: nchoosek(22,2) = 231 unsigned int j; unsigned int k; for (j=0; j<21; j++) { if (liquid_autotest_verbose) printf("***** %2u *****\n", j); for (k=0; k<22-j-1; k++) { // generate symbol unsigned char sym_org[2]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[3]; fec_secded2216_encode_symbol(sym_org, sym_enc); // generate error vector (single error) unsigned char e[3] = {0,0,0}; div_t dj = div(j,8); e[3-dj.quot-1] |= 1 << dj.rem; div_t dk = div(k+j+1,8); e[3-dk.quot-1] |= 1 << dk.rem; // received symbol unsigned char sym_rec[3]; sym_rec[0] = sym_enc[0] ^ e[0]; sym_rec[1] = sym_enc[1] ^ e[1]; sym_rec[2] = sym_enc[2] ^ e[2]; // decoded symbol unsigned char sym_dec[2]; int syndrome_flag = fec_secded2216_decode_symbol(sym_rec, sym_dec); if (liquid_autotest_verbose) { // print error vector printf("%3u, e = ", k); liquid_print_bitstring(e[0], 6); liquid_print_bitstring(e[1], 8); liquid_print_bitstring(e[2], 8); printf(" flag=%2d\n", syndrome_flag); } // validate syndrome flag is '2' CONTEND_EQUALITY(syndrome_flag, 2); } } } liquid-dsp-1.7.0/src/fec/tests/fec_secded3932_autotest.c000066400000000000000000000121051474751757600227670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: SEC-DEC (39,32) codec (no errors) // void autotest_secded3932_codec_e0() { // generate symbol unsigned char sym_org[4]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; sym_org[2] = rand() & 0xffff; sym_org[3] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[5]; fec_secded3932_encode_symbol(sym_org, sym_enc); // decoded symbol unsigned char sym_dec[4]; fec_secded3932_decode_symbol(sym_enc, sym_dec); // validate data are the same CONTEND_EQUALITY(sym_org[0], sym_dec[0]); CONTEND_EQUALITY(sym_org[1], sym_dec[1]); CONTEND_EQUALITY(sym_org[2], sym_dec[2]); CONTEND_EQUALITY(sym_org[3], sym_dec[3]); } // // AUTOTEST: SEC-DEC (39,32) codec (single error) // void autotest_secded3932_codec_e1() { unsigned int k; // error location for (k=0; k<39; k++) { // generate symbol unsigned char sym_org[4]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; sym_org[2] = rand() & 0xffff; sym_org[3] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[5]; fec_secded3932_encode_symbol(sym_org, sym_enc); // generate error vector (single error) unsigned char e[5] = {0,0,0,0,0}; div_t d = div(k,8); e[5-d.quot-1] = 1 << d.rem; // received symbol unsigned char sym_rec[5]; sym_rec[0] = sym_enc[0] ^ e[0]; sym_rec[1] = sym_enc[1] ^ e[1]; sym_rec[2] = sym_enc[2] ^ e[2]; sym_rec[3] = sym_enc[3] ^ e[3]; sym_rec[4] = sym_enc[4] ^ e[4]; // decoded symbol unsigned char sym_dec[4]; fec_secded3932_decode_symbol(sym_rec, sym_dec); // validate data are the same CONTEND_EQUALITY(sym_org[0], sym_dec[0]); CONTEND_EQUALITY(sym_org[1], sym_dec[1]); CONTEND_EQUALITY(sym_org[2], sym_dec[2]); CONTEND_EQUALITY(sym_org[3], sym_dec[3]); } } // // AUTOTEST: SEC-DEC (39,32) codec (double error detection) // void autotest_secded3932_codec_e2() { // total combinations of double errors: nchoosek(39,2) = 741 unsigned int j; unsigned int k; for (j=0; j<39-1; j++) { if (liquid_autotest_verbose) printf("***** %2u *****\n", j); for (k=0; k<39-1-j; k++) { // generate symbol unsigned char sym_org[4]; sym_org[0] = rand() & 0xffff; sym_org[1] = rand() & 0xffff; sym_org[2] = rand() & 0xffff; sym_org[3] = rand() & 0xffff; // encoded symbol unsigned char sym_enc[5]; fec_secded3932_encode_symbol(sym_org, sym_enc); // generate error vector (single error) unsigned char e[5] = {0,0,0,0,0}; div_t dj = div(j,8); e[5-dj.quot-1] |= 1 << dj.rem; div_t dk = div(k+j+1,8); e[5-dk.quot-1] |= 1 << dk.rem; // received symbol unsigned char sym_rec[5]; sym_rec[0] = sym_enc[0] ^ e[0]; sym_rec[1] = sym_enc[1] ^ e[1]; sym_rec[2] = sym_enc[2] ^ e[2]; sym_rec[3] = sym_enc[3] ^ e[3]; sym_rec[4] = sym_enc[4] ^ e[4]; // decoded symbol unsigned char sym_dec[4]; int syndrome_flag = fec_secded3932_decode_symbol(sym_rec, sym_dec); if (liquid_autotest_verbose) { // print error vector printf("%3u, e = ", k); liquid_print_bitstring(e[0], 7); liquid_print_bitstring(e[1], 8); liquid_print_bitstring(e[2], 8); liquid_print_bitstring(e[3], 8); liquid_print_bitstring(e[4], 8); printf(" flag=%2d\n", syndrome_flag); } // validate syndrome flag is '2' CONTEND_EQUALITY(syndrome_flag, 2); } } } liquid-dsp-1.7.0/src/fec/tests/fec_secded7264_autotest.c000066400000000000000000000126641474751757600230030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: SEC-DEC (72,64) codec (no errors) // void autotest_secded7264_codec_e0() { // arrays unsigned char sym_org[8]; // original symbol unsigned char sym_enc[9]; // encoded symbol unsigned char sym_dec[8]; // decoded symbol // generate symbol sym_org[0] = rand() & 0xff; sym_org[1] = rand() & 0xff; sym_org[2] = rand() & 0xff; sym_org[3] = rand() & 0xff; sym_org[4] = rand() & 0xff; sym_org[5] = rand() & 0xff; sym_org[6] = rand() & 0xff; sym_org[7] = rand() & 0xff; // encoded symbol fec_secded7264_encode_symbol(sym_org, sym_enc); // decoded symbol fec_secded7264_decode_symbol(sym_enc, sym_dec); // validate data are the same CONTEND_EQUALITY(sym_org[0], sym_dec[0]); CONTEND_EQUALITY(sym_org[1], sym_dec[1]); CONTEND_EQUALITY(sym_org[2], sym_dec[2]); CONTEND_EQUALITY(sym_org[3], sym_dec[3]); CONTEND_EQUALITY(sym_org[4], sym_dec[4]); CONTEND_EQUALITY(sym_org[5], sym_dec[5]); CONTEND_EQUALITY(sym_org[6], sym_dec[6]); CONTEND_EQUALITY(sym_org[7], sym_dec[7]); } // // AUTOTEST: SEC-DEC (72,64) codec (single error) // void autotest_secded7264_codec_e1() { // arrays unsigned char sym_org[8]; // original symbol unsigned char sym_enc[9]; // encoded symbol unsigned char e[9]; // error vector unsigned char sym_rec[9]; // received symbol unsigned char sym_dec[8]; // decoded symbol unsigned int i; unsigned int k; // error location for (k=0; k<72; k++) { // generate symbol for (i=0; i<8; i++) sym_org[i] = rand() & 0xff; // encoded symbol fec_secded7264_encode_symbol(sym_org, sym_enc); // generate error vector (single error) for (i=0; i<9; i++) e[i] = 0; div_t d = div(k,8); e[9-d.quot-1] = 1 << d.rem; // flip bit at index k // received symbol for (i=0; i<9; i++) sym_rec[i] = sym_enc[i] ^ e[i]; // decoded symbol fec_secded7264_decode_symbol(sym_rec, sym_dec); // validate data are the same for (i=0; i<8; i++) CONTEND_EQUALITY(sym_org[i], sym_dec[i]); } } // // AUTOTEST: SEC-DEC (72,64) codec (double error detection) // void autotest_secded7264_codec_e2() { // total combinations of double errors: nchoosek(72,2) = 2556 // arrays unsigned char sym_org[8]; // original symbol unsigned char sym_enc[9]; // encoded symbol unsigned char e[9]; // error vector unsigned char sym_rec[9]; // received symbol unsigned char sym_dec[8]; // decoded symbol unsigned int i; unsigned int j; unsigned int k; for (j=0; j<72-1; j++) { #if 0 if (liquid_autotest_verbose) printf("***** %2u *****\n", j); #endif for (k=0; k<72-1-j; k++) { // generate symbol for (i=0; i<8; i++) sym_org[i] = rand() & 0xff; // encoded symbol fec_secded7264_encode_symbol(sym_org, sym_enc); // generate error vector (single error) for (i=0; i<9; i++) e[i] = 0; div_t dj = div(j,8); e[9-dj.quot-1] |= 1 << dj.rem; div_t dk = div(k+j+1,8); e[9-dk.quot-1] |= 1 << dk.rem; // received symbol for (i=0; i<9; i++) sym_rec[i] = sym_enc[i] ^ e[i]; // decoded symbol int syndrome_flag = fec_secded7264_decode_symbol(sym_rec, sym_dec); #if 0 if (liquid_autotest_verbose) { // print error vector printf("%3u, e = ", k); liquid_print_bitstring(e[0], 8); liquid_print_bitstring(e[1], 8); liquid_print_bitstring(e[2], 8); liquid_print_bitstring(e[3], 8); liquid_print_bitstring(e[4], 8); liquid_print_bitstring(e[5], 8); liquid_print_bitstring(e[6], 8); liquid_print_bitstring(e[7], 8); liquid_print_bitstring(e[8], 8); printf(" flag=%2d\n", syndrome_flag); } #endif // validate syndrome flag is '2' CONTEND_EQUALITY(syndrome_flag, 2); } } } liquid-dsp-1.7.0/src/fec/tests/fec_soft_autotest.c000066400000000000000000000130521474751757600221740ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // Test soft-decoding of a particular coding scheme // (helper function to keep code base small) void fec_test_soft_codec(fec_scheme _fs, unsigned int _n, void * _opts) { #if !LIBFEC_ENABLED switch (_fs) { case LIQUID_FEC_CONV_V27: case LIQUID_FEC_CONV_V29: case LIQUID_FEC_CONV_V39: case LIQUID_FEC_CONV_V615: case LIQUID_FEC_CONV_V27P23: case LIQUID_FEC_CONV_V27P34: case LIQUID_FEC_CONV_V27P45: case LIQUID_FEC_CONV_V27P56: case LIQUID_FEC_CONV_V27P67: case LIQUID_FEC_CONV_V27P78: case LIQUID_FEC_CONV_V29P23: case LIQUID_FEC_CONV_V29P34: case LIQUID_FEC_CONV_V29P45: case LIQUID_FEC_CONV_V29P56: case LIQUID_FEC_CONV_V29P67: case LIQUID_FEC_CONV_V29P78: case LIQUID_FEC_RS_M8: AUTOTEST_WARN("convolutional, Reed-Solomon codes unavailable (install libfec)"); return; default:; } #endif // generate fec object fec q = fec_create(_fs,_opts); // create arrays unsigned int n_enc = fec_get_enc_msg_length(_fs,_n); unsigned char msg[_n]; // original message unsigned char msg_enc[n_enc]; // encoded message unsigned char msg_soft[8*n_enc]; // encoded message (soft bits) unsigned char msg_dec[_n]; // decoded message // initialize message unsigned int i; for (i=0; i<_n; i++) { msg[i] = rand() & 0xff; msg_dec[i] = 0; } // encode message fec_encode(q, _n, msg, msg_enc); // convert to soft bits for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // // AUTOTESTS: interleave/deinterleave // void interleaver_test_hard(unsigned int _n) { unsigned int i; unsigned char x[_n]; unsigned char y[_n]; unsigned char z[_n]; for (i=0; i<_n; i++) x[i] = rand() & 0xFF; // create interleaver object interleaver q = interleaver_create(_n); interleaver_encode(q,x,y); interleaver_decode(q,y,z); CONTEND_SAME_DATA(x, z, _n); // destroy interleaver object interleaver_destroy(q); } // // AUTOTESTS: interleave/deinterleave (soft) // void interleaver_test_soft(unsigned int _n) { unsigned int i; unsigned char x[8*_n]; unsigned char y[8*_n]; unsigned char z[8*_n]; for (i=0; i<8*_n; i++) x[i] = rand() & 0xFF; // create interleaver object interleaver q = interleaver_create(_n); interleaver_encode_soft(q,x,y); interleaver_decode_soft(q,y,z); CONTEND_SAME_DATA(x, z, 8*_n); // destroy interleaver object interleaver_destroy(q); } void autotest_interleaver_hard_8() { interleaver_test_hard(8 ); } void autotest_interleaver_hard_16() { interleaver_test_hard(16 ); } void autotest_interleaver_hard_64() { interleaver_test_hard(64 ); } void autotest_interleaver_hard_256() { interleaver_test_hard(256 ); } void autotest_interleaver_soft_8() { interleaver_test_soft(8 ); } void autotest_interleaver_soft_16() { interleaver_test_soft(16 ); } void autotest_interleaver_soft_64() { interleaver_test_soft(64 ); } void autotest_interleaver_soft_256() { interleaver_test_soft(256 ); } liquid-dsp-1.7.0/src/fec/tests/packetizer_autotest.c000066400000000000000000000047011474751757600225460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small void packetizer_test_codec(unsigned int _n, crc_scheme _crc, fec_scheme _fec0, fec_scheme _fec1) { unsigned char msg_tx[_n]; unsigned char msg_rx[_n]; unsigned int pkt_len = packetizer_compute_enc_msg_len(_n,_crc,_fec0,_fec1); unsigned char packet[pkt_len]; // create object packetizer p = packetizer_create(_n,_crc,_fec0,_fec1); if (liquid_autotest_verbose) packetizer_print(p); // initialize data unsigned int i; for (i=0; i<_n; i++) { msg_tx[i] = i % 256; msg_rx[i] = 0; } // encode/decode packet packetizer_encode(p, msg_tx, packet); int crc_pass = packetizer_decode(p, packet, msg_rx); CONTEND_SAME_DATA(msg_tx, msg_rx, _n); CONTEND_EQUALITY(crc_pass, 1); // clean up objects packetizer_destroy(p); } // // AUTOTESTS // void autotest_packetizer_n16_0_0() { packetizer_test_codec(16, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_NONE); } void autotest_packetizer_n16_0_1() { packetizer_test_codec(16, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_REP3); } void autotest_packetizer_n16_0_2() { packetizer_test_codec(16, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING74); } liquid-dsp-1.7.0/src/fec/tests/packetizer_copy_autotest.c000066400000000000000000000056621474751757600236070ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" void autotest_packetizer_copy() { unsigned int msg_len_dec = 57; crc_scheme crc = LIQUID_CRC_32; fec_scheme fec0 = LIQUID_FEC_HAMMING128; fec_scheme fec1 = LIQUID_FEC_GOLAY2412; // compute encoded message length unsigned int msg_len_enc = packetizer_compute_enc_msg_len(msg_len_dec,crc,fec0,fec1); // allocate arrays for testing unsigned char msg_org [msg_len_dec]; // original message unsigned char msg_enc_0[msg_len_enc]; // encoded (original object) unsigned char msg_enc_1[msg_len_enc]; // encoded (copy object) unsigned char msg_dec_0[msg_len_dec]; // decoded (original object) unsigned char msg_dec_1[msg_len_dec]; // encoded (copy object) // create object packetizer q0 = packetizer_create(msg_len_dec,crc,fec0,fec1); // initialize random data unsigned int i; for (i=0; i #include #include #include "liquid.h" #include "src/fft/bench/fft_runbench.h" // composite numbers void benchmark_fft_6 LIQUID_FFT_BENCHMARK_API( 6, LIQUID_FFT_FORWARD) void benchmark_fft_9 LIQUID_FFT_BENCHMARK_API( 9, LIQUID_FFT_FORWARD) void benchmark_fft_10 LIQUID_FFT_BENCHMARK_API( 10, LIQUID_FFT_FORWARD) void benchmark_fft_12 LIQUID_FFT_BENCHMARK_API( 12, LIQUID_FFT_FORWARD) void benchmark_fft_14 LIQUID_FFT_BENCHMARK_API( 14, LIQUID_FFT_FORWARD) void benchmark_fft_15 LIQUID_FFT_BENCHMARK_API( 15, LIQUID_FFT_FORWARD) void benchmark_fft_18 LIQUID_FFT_BENCHMARK_API( 18, LIQUID_FFT_FORWARD) void benchmark_fft_20 LIQUID_FFT_BENCHMARK_API( 20, LIQUID_FFT_FORWARD) void benchmark_fft_21 LIQUID_FFT_BENCHMARK_API( 21, LIQUID_FFT_FORWARD) void benchmark_fft_22 LIQUID_FFT_BENCHMARK_API( 22, LIQUID_FFT_FORWARD) void benchmark_fft_24 LIQUID_FFT_BENCHMARK_API( 24, LIQUID_FFT_FORWARD) void benchmark_fft_25 LIQUID_FFT_BENCHMARK_API( 25, LIQUID_FFT_FORWARD) void benchmark_fft_26 LIQUID_FFT_BENCHMARK_API( 26, LIQUID_FFT_FORWARD) void benchmark_fft_27 LIQUID_FFT_BENCHMARK_API( 27, LIQUID_FFT_FORWARD) void benchmark_fft_28 LIQUID_FFT_BENCHMARK_API( 28, LIQUID_FFT_FORWARD) void benchmark_fft_30 LIQUID_FFT_BENCHMARK_API( 30, LIQUID_FFT_FORWARD) void benchmark_fft_33 LIQUID_FFT_BENCHMARK_API( 33, LIQUID_FFT_FORWARD) void benchmark_fft_34 LIQUID_FFT_BENCHMARK_API( 34, LIQUID_FFT_FORWARD) void benchmark_fft_35 LIQUID_FFT_BENCHMARK_API( 35, LIQUID_FFT_FORWARD) void benchmark_fft_36 LIQUID_FFT_BENCHMARK_API( 36, LIQUID_FFT_FORWARD) void benchmark_fft_38 LIQUID_FFT_BENCHMARK_API( 38, LIQUID_FFT_FORWARD) void benchmark_fft_39 LIQUID_FFT_BENCHMARK_API( 39, LIQUID_FFT_FORWARD) void benchmark_fft_40 LIQUID_FFT_BENCHMARK_API( 40, LIQUID_FFT_FORWARD) void benchmark_fft_42 LIQUID_FFT_BENCHMARK_API( 42, LIQUID_FFT_FORWARD) void benchmark_fft_44 LIQUID_FFT_BENCHMARK_API( 44, LIQUID_FFT_FORWARD) void benchmark_fft_45 LIQUID_FFT_BENCHMARK_API( 45, LIQUID_FFT_FORWARD) void benchmark_fft_46 LIQUID_FFT_BENCHMARK_API( 46, LIQUID_FFT_FORWARD) void benchmark_fft_48 LIQUID_FFT_BENCHMARK_API( 48, LIQUID_FFT_FORWARD) void benchmark_fft_49 LIQUID_FFT_BENCHMARK_API( 49, LIQUID_FFT_FORWARD) void benchmark_fft_50 LIQUID_FFT_BENCHMARK_API( 50, LIQUID_FFT_FORWARD) void benchmark_fft_51 LIQUID_FFT_BENCHMARK_API( 51, LIQUID_FFT_FORWARD) void benchmark_fft_52 LIQUID_FFT_BENCHMARK_API( 52, LIQUID_FFT_FORWARD) void benchmark_fft_54 LIQUID_FFT_BENCHMARK_API( 54, LIQUID_FFT_FORWARD) void benchmark_fft_55 LIQUID_FFT_BENCHMARK_API( 55, LIQUID_FFT_FORWARD) void benchmark_fft_56 LIQUID_FFT_BENCHMARK_API( 56, LIQUID_FFT_FORWARD) void benchmark_fft_57 LIQUID_FFT_BENCHMARK_API( 57, LIQUID_FFT_FORWARD) void benchmark_fft_58 LIQUID_FFT_BENCHMARK_API( 58, LIQUID_FFT_FORWARD) void benchmark_fft_60 LIQUID_FFT_BENCHMARK_API( 60, LIQUID_FFT_FORWARD) void benchmark_fft_62 LIQUID_FFT_BENCHMARK_API( 62, LIQUID_FFT_FORWARD) void benchmark_fft_63 LIQUID_FFT_BENCHMARK_API( 63, LIQUID_FFT_FORWARD) void benchmark_fft_65 LIQUID_FFT_BENCHMARK_API( 65, LIQUID_FFT_FORWARD) void benchmark_fft_66 LIQUID_FFT_BENCHMARK_API( 66, LIQUID_FFT_FORWARD) void benchmark_fft_68 LIQUID_FFT_BENCHMARK_API( 68, LIQUID_FFT_FORWARD) void benchmark_fft_69 LIQUID_FFT_BENCHMARK_API( 69, LIQUID_FFT_FORWARD) void benchmark_fft_70 LIQUID_FFT_BENCHMARK_API( 70, LIQUID_FFT_FORWARD) void benchmark_fft_72 LIQUID_FFT_BENCHMARK_API( 72, LIQUID_FFT_FORWARD) void benchmark_fft_74 LIQUID_FFT_BENCHMARK_API( 74, LIQUID_FFT_FORWARD) void benchmark_fft_75 LIQUID_FFT_BENCHMARK_API( 75, LIQUID_FFT_FORWARD) void benchmark_fft_76 LIQUID_FFT_BENCHMARK_API( 76, LIQUID_FFT_FORWARD) void benchmark_fft_77 LIQUID_FFT_BENCHMARK_API( 77, LIQUID_FFT_FORWARD) void benchmark_fft_78 LIQUID_FFT_BENCHMARK_API( 78, LIQUID_FFT_FORWARD) void benchmark_fft_80 LIQUID_FFT_BENCHMARK_API( 80, LIQUID_FFT_FORWARD) void benchmark_fft_81 LIQUID_FFT_BENCHMARK_API( 81, LIQUID_FFT_FORWARD) void benchmark_fft_82 LIQUID_FFT_BENCHMARK_API( 82, LIQUID_FFT_FORWARD) void benchmark_fft_84 LIQUID_FFT_BENCHMARK_API( 84, LIQUID_FFT_FORWARD) void benchmark_fft_85 LIQUID_FFT_BENCHMARK_API( 85, LIQUID_FFT_FORWARD) void benchmark_fft_86 LIQUID_FFT_BENCHMARK_API( 86, LIQUID_FFT_FORWARD) void benchmark_fft_87 LIQUID_FFT_BENCHMARK_API( 87, LIQUID_FFT_FORWARD) void benchmark_fft_88 LIQUID_FFT_BENCHMARK_API( 88, LIQUID_FFT_FORWARD) void benchmark_fft_90 LIQUID_FFT_BENCHMARK_API( 90, LIQUID_FFT_FORWARD) void benchmark_fft_91 LIQUID_FFT_BENCHMARK_API( 91, LIQUID_FFT_FORWARD) void benchmark_fft_92 LIQUID_FFT_BENCHMARK_API( 92, LIQUID_FFT_FORWARD) void benchmark_fft_93 LIQUID_FFT_BENCHMARK_API( 93, LIQUID_FFT_FORWARD) void benchmark_fft_94 LIQUID_FFT_BENCHMARK_API( 94, LIQUID_FFT_FORWARD) void benchmark_fft_95 LIQUID_FFT_BENCHMARK_API( 95, LIQUID_FFT_FORWARD) void benchmark_fft_96 LIQUID_FFT_BENCHMARK_API( 96, LIQUID_FFT_FORWARD) void benchmark_fft_98 LIQUID_FFT_BENCHMARK_API( 98, LIQUID_FFT_FORWARD) void benchmark_fft_99 LIQUID_FFT_BENCHMARK_API( 99, LIQUID_FFT_FORWARD) void benchmark_fft_100 LIQUID_FFT_BENCHMARK_API( 100, LIQUID_FFT_FORWARD) void benchmark_fft_102 LIQUID_FFT_BENCHMARK_API( 102, LIQUID_FFT_FORWARD) void benchmark_fft_104 LIQUID_FFT_BENCHMARK_API( 104, LIQUID_FFT_FORWARD) void benchmark_fft_105 LIQUID_FFT_BENCHMARK_API( 105, LIQUID_FFT_FORWARD) void benchmark_fft_106 LIQUID_FFT_BENCHMARK_API( 106, LIQUID_FFT_FORWARD) void benchmark_fft_108 LIQUID_FFT_BENCHMARK_API( 108, LIQUID_FFT_FORWARD) void benchmark_fft_110 LIQUID_FFT_BENCHMARK_API( 110, LIQUID_FFT_FORWARD) void benchmark_fft_111 LIQUID_FFT_BENCHMARK_API( 111, LIQUID_FFT_FORWARD) void benchmark_fft_112 LIQUID_FFT_BENCHMARK_API( 112, LIQUID_FFT_FORWARD) void benchmark_fft_114 LIQUID_FFT_BENCHMARK_API( 114, LIQUID_FFT_FORWARD) void benchmark_fft_115 LIQUID_FFT_BENCHMARK_API( 115, LIQUID_FFT_FORWARD) void benchmark_fft_116 LIQUID_FFT_BENCHMARK_API( 116, LIQUID_FFT_FORWARD) void benchmark_fft_117 LIQUID_FFT_BENCHMARK_API( 117, LIQUID_FFT_FORWARD) void benchmark_fft_118 LIQUID_FFT_BENCHMARK_API( 118, LIQUID_FFT_FORWARD) void benchmark_fft_119 LIQUID_FFT_BENCHMARK_API( 119, LIQUID_FFT_FORWARD) void benchmark_fft_120 LIQUID_FFT_BENCHMARK_API( 120, LIQUID_FFT_FORWARD) void benchmark_fft_121 LIQUID_FFT_BENCHMARK_API( 121, LIQUID_FFT_FORWARD) void benchmark_fft_122 LIQUID_FFT_BENCHMARK_API( 122, LIQUID_FFT_FORWARD) void benchmark_fft_123 LIQUID_FFT_BENCHMARK_API( 123, LIQUID_FFT_FORWARD) void benchmark_fft_124 LIQUID_FFT_BENCHMARK_API( 124, LIQUID_FFT_FORWARD) void benchmark_fft_125 LIQUID_FFT_BENCHMARK_API( 125, LIQUID_FFT_FORWARD) void benchmark_fft_126 LIQUID_FFT_BENCHMARK_API( 126, LIQUID_FFT_FORWARD) void benchmark_fft_129 LIQUID_FFT_BENCHMARK_API( 129, LIQUID_FFT_FORWARD) void benchmark_fft_130 LIQUID_FFT_BENCHMARK_API( 130, LIQUID_FFT_FORWARD) void benchmark_fft_132 LIQUID_FFT_BENCHMARK_API( 132, LIQUID_FFT_FORWARD) void benchmark_fft_133 LIQUID_FFT_BENCHMARK_API( 133, LIQUID_FFT_FORWARD) void benchmark_fft_134 LIQUID_FFT_BENCHMARK_API( 134, LIQUID_FFT_FORWARD) void benchmark_fft_135 LIQUID_FFT_BENCHMARK_API( 135, LIQUID_FFT_FORWARD) void benchmark_fft_136 LIQUID_FFT_BENCHMARK_API( 136, LIQUID_FFT_FORWARD) void benchmark_fft_138 LIQUID_FFT_BENCHMARK_API( 138, LIQUID_FFT_FORWARD) void benchmark_fft_140 LIQUID_FFT_BENCHMARK_API( 140, LIQUID_FFT_FORWARD) void benchmark_fft_141 LIQUID_FFT_BENCHMARK_API( 141, LIQUID_FFT_FORWARD) void benchmark_fft_142 LIQUID_FFT_BENCHMARK_API( 142, LIQUID_FFT_FORWARD) void benchmark_fft_143 LIQUID_FFT_BENCHMARK_API( 143, LIQUID_FFT_FORWARD) void benchmark_fft_144 LIQUID_FFT_BENCHMARK_API( 144, LIQUID_FFT_FORWARD) void benchmark_fft_145 LIQUID_FFT_BENCHMARK_API( 145, LIQUID_FFT_FORWARD) void benchmark_fft_146 LIQUID_FFT_BENCHMARK_API( 146, LIQUID_FFT_FORWARD) void benchmark_fft_147 LIQUID_FFT_BENCHMARK_API( 147, LIQUID_FFT_FORWARD) void benchmark_fft_148 LIQUID_FFT_BENCHMARK_API( 148, LIQUID_FFT_FORWARD) void benchmark_fft_150 LIQUID_FFT_BENCHMARK_API( 150, LIQUID_FFT_FORWARD) void benchmark_fft_152 LIQUID_FFT_BENCHMARK_API( 152, LIQUID_FFT_FORWARD) void benchmark_fft_153 LIQUID_FFT_BENCHMARK_API( 153, LIQUID_FFT_FORWARD) void benchmark_fft_154 LIQUID_FFT_BENCHMARK_API( 154, LIQUID_FFT_FORWARD) void benchmark_fft_155 LIQUID_FFT_BENCHMARK_API( 155, LIQUID_FFT_FORWARD) void benchmark_fft_156 LIQUID_FFT_BENCHMARK_API( 156, LIQUID_FFT_FORWARD) void benchmark_fft_158 LIQUID_FFT_BENCHMARK_API( 158, LIQUID_FFT_FORWARD) void benchmark_fft_159 LIQUID_FFT_BENCHMARK_API( 159, LIQUID_FFT_FORWARD) void benchmark_fft_160 LIQUID_FFT_BENCHMARK_API( 160, LIQUID_FFT_FORWARD) void benchmark_fft_161 LIQUID_FFT_BENCHMARK_API( 161, LIQUID_FFT_FORWARD) void benchmark_fft_162 LIQUID_FFT_BENCHMARK_API( 162, LIQUID_FFT_FORWARD) void benchmark_fft_164 LIQUID_FFT_BENCHMARK_API( 164, LIQUID_FFT_FORWARD) void benchmark_fft_165 LIQUID_FFT_BENCHMARK_API( 165, LIQUID_FFT_FORWARD) void benchmark_fft_166 LIQUID_FFT_BENCHMARK_API( 166, LIQUID_FFT_FORWARD) void benchmark_fft_168 LIQUID_FFT_BENCHMARK_API( 168, LIQUID_FFT_FORWARD) void benchmark_fft_169 LIQUID_FFT_BENCHMARK_API( 169, LIQUID_FFT_FORWARD) void benchmark_fft_170 LIQUID_FFT_BENCHMARK_API( 170, LIQUID_FFT_FORWARD) void benchmark_fft_171 LIQUID_FFT_BENCHMARK_API( 171, LIQUID_FFT_FORWARD) void benchmark_fft_172 LIQUID_FFT_BENCHMARK_API( 172, LIQUID_FFT_FORWARD) void benchmark_fft_174 LIQUID_FFT_BENCHMARK_API( 174, LIQUID_FFT_FORWARD) void benchmark_fft_175 LIQUID_FFT_BENCHMARK_API( 175, LIQUID_FFT_FORWARD) void benchmark_fft_176 LIQUID_FFT_BENCHMARK_API( 176, LIQUID_FFT_FORWARD) void benchmark_fft_177 LIQUID_FFT_BENCHMARK_API( 177, LIQUID_FFT_FORWARD) void benchmark_fft_178 LIQUID_FFT_BENCHMARK_API( 178, LIQUID_FFT_FORWARD) void benchmark_fft_180 LIQUID_FFT_BENCHMARK_API( 180, LIQUID_FFT_FORWARD) void benchmark_fft_182 LIQUID_FFT_BENCHMARK_API( 182, LIQUID_FFT_FORWARD) void benchmark_fft_183 LIQUID_FFT_BENCHMARK_API( 183, LIQUID_FFT_FORWARD) void benchmark_fft_184 LIQUID_FFT_BENCHMARK_API( 184, LIQUID_FFT_FORWARD) void benchmark_fft_185 LIQUID_FFT_BENCHMARK_API( 185, LIQUID_FFT_FORWARD) void benchmark_fft_186 LIQUID_FFT_BENCHMARK_API( 186, LIQUID_FFT_FORWARD) void benchmark_fft_187 LIQUID_FFT_BENCHMARK_API( 187, LIQUID_FFT_FORWARD) void benchmark_fft_188 LIQUID_FFT_BENCHMARK_API( 188, LIQUID_FFT_FORWARD) void benchmark_fft_189 LIQUID_FFT_BENCHMARK_API( 189, LIQUID_FFT_FORWARD) void benchmark_fft_190 LIQUID_FFT_BENCHMARK_API( 190, LIQUID_FFT_FORWARD) void benchmark_fft_192 LIQUID_FFT_BENCHMARK_API( 192, LIQUID_FFT_FORWARD) void benchmark_fft_194 LIQUID_FFT_BENCHMARK_API( 194, LIQUID_FFT_FORWARD) void benchmark_fft_195 LIQUID_FFT_BENCHMARK_API( 195, LIQUID_FFT_FORWARD) void benchmark_fft_196 LIQUID_FFT_BENCHMARK_API( 196, LIQUID_FFT_FORWARD) void benchmark_fft_198 LIQUID_FFT_BENCHMARK_API( 198, LIQUID_FFT_FORWARD) void benchmark_fft_200 LIQUID_FFT_BENCHMARK_API( 200, LIQUID_FFT_FORWARD) void benchmark_fft_201 LIQUID_FFT_BENCHMARK_API( 201, LIQUID_FFT_FORWARD) void benchmark_fft_202 LIQUID_FFT_BENCHMARK_API( 202, LIQUID_FFT_FORWARD) void benchmark_fft_203 LIQUID_FFT_BENCHMARK_API( 203, LIQUID_FFT_FORWARD) void benchmark_fft_204 LIQUID_FFT_BENCHMARK_API( 204, LIQUID_FFT_FORWARD) void benchmark_fft_205 LIQUID_FFT_BENCHMARK_API( 205, LIQUID_FFT_FORWARD) void benchmark_fft_206 LIQUID_FFT_BENCHMARK_API( 206, LIQUID_FFT_FORWARD) void benchmark_fft_207 LIQUID_FFT_BENCHMARK_API( 207, LIQUID_FFT_FORWARD) void benchmark_fft_208 LIQUID_FFT_BENCHMARK_API( 208, LIQUID_FFT_FORWARD) void benchmark_fft_209 LIQUID_FFT_BENCHMARK_API( 209, LIQUID_FFT_FORWARD) void benchmark_fft_210 LIQUID_FFT_BENCHMARK_API( 210, LIQUID_FFT_FORWARD) void benchmark_fft_212 LIQUID_FFT_BENCHMARK_API( 212, LIQUID_FFT_FORWARD) void benchmark_fft_213 LIQUID_FFT_BENCHMARK_API( 213, LIQUID_FFT_FORWARD) void benchmark_fft_214 LIQUID_FFT_BENCHMARK_API( 214, LIQUID_FFT_FORWARD) void benchmark_fft_215 LIQUID_FFT_BENCHMARK_API( 215, LIQUID_FFT_FORWARD) void benchmark_fft_216 LIQUID_FFT_BENCHMARK_API( 216, LIQUID_FFT_FORWARD) void benchmark_fft_217 LIQUID_FFT_BENCHMARK_API( 217, LIQUID_FFT_FORWARD) void benchmark_fft_218 LIQUID_FFT_BENCHMARK_API( 218, LIQUID_FFT_FORWARD) void benchmark_fft_219 LIQUID_FFT_BENCHMARK_API( 219, LIQUID_FFT_FORWARD) void benchmark_fft_220 LIQUID_FFT_BENCHMARK_API( 220, LIQUID_FFT_FORWARD) void benchmark_fft_221 LIQUID_FFT_BENCHMARK_API( 221, LIQUID_FFT_FORWARD) void benchmark_fft_222 LIQUID_FFT_BENCHMARK_API( 222, LIQUID_FFT_FORWARD) void benchmark_fft_224 LIQUID_FFT_BENCHMARK_API( 224, LIQUID_FFT_FORWARD) void benchmark_fft_225 LIQUID_FFT_BENCHMARK_API( 225, LIQUID_FFT_FORWARD) void benchmark_fft_226 LIQUID_FFT_BENCHMARK_API( 226, LIQUID_FFT_FORWARD) void benchmark_fft_228 LIQUID_FFT_BENCHMARK_API( 228, LIQUID_FFT_FORWARD) void benchmark_fft_230 LIQUID_FFT_BENCHMARK_API( 230, LIQUID_FFT_FORWARD) void benchmark_fft_231 LIQUID_FFT_BENCHMARK_API( 231, LIQUID_FFT_FORWARD) void benchmark_fft_232 LIQUID_FFT_BENCHMARK_API( 232, LIQUID_FFT_FORWARD) void benchmark_fft_234 LIQUID_FFT_BENCHMARK_API( 234, LIQUID_FFT_FORWARD) void benchmark_fft_235 LIQUID_FFT_BENCHMARK_API( 235, LIQUID_FFT_FORWARD) void benchmark_fft_236 LIQUID_FFT_BENCHMARK_API( 236, LIQUID_FFT_FORWARD) void benchmark_fft_237 LIQUID_FFT_BENCHMARK_API( 237, LIQUID_FFT_FORWARD) void benchmark_fft_238 LIQUID_FFT_BENCHMARK_API( 238, LIQUID_FFT_FORWARD) void benchmark_fft_240 LIQUID_FFT_BENCHMARK_API( 240, LIQUID_FFT_FORWARD) void benchmark_fft_242 LIQUID_FFT_BENCHMARK_API( 242, LIQUID_FFT_FORWARD) void benchmark_fft_243 LIQUID_FFT_BENCHMARK_API( 243, LIQUID_FFT_FORWARD) void benchmark_fft_244 LIQUID_FFT_BENCHMARK_API( 244, LIQUID_FFT_FORWARD) void benchmark_fft_245 LIQUID_FFT_BENCHMARK_API( 245, LIQUID_FFT_FORWARD) void benchmark_fft_246 LIQUID_FFT_BENCHMARK_API( 246, LIQUID_FFT_FORWARD) void benchmark_fft_247 LIQUID_FFT_BENCHMARK_API( 247, LIQUID_FFT_FORWARD) void benchmark_fft_248 LIQUID_FFT_BENCHMARK_API( 248, LIQUID_FFT_FORWARD) void benchmark_fft_249 LIQUID_FFT_BENCHMARK_API( 249, LIQUID_FFT_FORWARD) void benchmark_fft_250 LIQUID_FFT_BENCHMARK_API( 250, LIQUID_FFT_FORWARD) void benchmark_fft_252 LIQUID_FFT_BENCHMARK_API( 252, LIQUID_FFT_FORWARD) void benchmark_fft_253 LIQUID_FFT_BENCHMARK_API( 253, LIQUID_FFT_FORWARD) void benchmark_fft_254 LIQUID_FFT_BENCHMARK_API( 254, LIQUID_FFT_FORWARD) void benchmark_fft_255 LIQUID_FFT_BENCHMARK_API( 255, LIQUID_FFT_FORWARD) liquid-dsp-1.7.0/src/fft/bench/fft_prime_benchmark.c000066400000000000000000000213321474751757600224000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_prime_benchmark.c : benchmark FFTs of prime length // #include #include #include #include "liquid.h" #include "src/fft/bench/fft_runbench.h" // prime numbers void benchmark_fft_3 LIQUID_FFT_BENCHMARK_API( 3, LIQUID_FFT_FORWARD) void benchmark_fft_5 LIQUID_FFT_BENCHMARK_API( 5, LIQUID_FFT_FORWARD) void benchmark_fft_7 LIQUID_FFT_BENCHMARK_API( 7, LIQUID_FFT_FORWARD) void benchmark_fft_11 LIQUID_FFT_BENCHMARK_API( 11, LIQUID_FFT_FORWARD) void benchmark_fft_13 LIQUID_FFT_BENCHMARK_API( 13, LIQUID_FFT_FORWARD) void benchmark_fft_17 LIQUID_FFT_BENCHMARK_API( 17, LIQUID_FFT_FORWARD) void benchmark_fft_19 LIQUID_FFT_BENCHMARK_API( 19, LIQUID_FFT_FORWARD) void benchmark_fft_23 LIQUID_FFT_BENCHMARK_API( 23, LIQUID_FFT_FORWARD) void benchmark_fft_29 LIQUID_FFT_BENCHMARK_API( 29, LIQUID_FFT_FORWARD) void benchmark_fft_31 LIQUID_FFT_BENCHMARK_API( 31, LIQUID_FFT_FORWARD) void benchmark_fft_37 LIQUID_FFT_BENCHMARK_API( 37, LIQUID_FFT_FORWARD) void benchmark_fft_41 LIQUID_FFT_BENCHMARK_API( 41, LIQUID_FFT_FORWARD) void benchmark_fft_43 LIQUID_FFT_BENCHMARK_API( 43, LIQUID_FFT_FORWARD) void benchmark_fft_47 LIQUID_FFT_BENCHMARK_API( 47, LIQUID_FFT_FORWARD) void benchmark_fft_53 LIQUID_FFT_BENCHMARK_API( 53, LIQUID_FFT_FORWARD) void benchmark_fft_59 LIQUID_FFT_BENCHMARK_API( 59, LIQUID_FFT_FORWARD) void benchmark_fft_61 LIQUID_FFT_BENCHMARK_API( 61, LIQUID_FFT_FORWARD) void benchmark_fft_67 LIQUID_FFT_BENCHMARK_API( 67, LIQUID_FFT_FORWARD) void benchmark_fft_71 LIQUID_FFT_BENCHMARK_API( 71, LIQUID_FFT_FORWARD) void benchmark_fft_73 LIQUID_FFT_BENCHMARK_API( 73, LIQUID_FFT_FORWARD) void benchmark_fft_79 LIQUID_FFT_BENCHMARK_API( 79, LIQUID_FFT_FORWARD) void benchmark_fft_83 LIQUID_FFT_BENCHMARK_API( 83, LIQUID_FFT_FORWARD) void benchmark_fft_89 LIQUID_FFT_BENCHMARK_API( 89, LIQUID_FFT_FORWARD) void benchmark_fft_97 LIQUID_FFT_BENCHMARK_API( 97, LIQUID_FFT_FORWARD) void benchmark_fft_101 LIQUID_FFT_BENCHMARK_API( 101, LIQUID_FFT_FORWARD) void benchmark_fft_103 LIQUID_FFT_BENCHMARK_API( 103, LIQUID_FFT_FORWARD) void benchmark_fft_107 LIQUID_FFT_BENCHMARK_API( 107, LIQUID_FFT_FORWARD) void benchmark_fft_109 LIQUID_FFT_BENCHMARK_API( 109, LIQUID_FFT_FORWARD) void benchmark_fft_113 LIQUID_FFT_BENCHMARK_API( 113, LIQUID_FFT_FORWARD) void benchmark_fft_127 LIQUID_FFT_BENCHMARK_API( 127, LIQUID_FFT_FORWARD) void benchmark_fft_131 LIQUID_FFT_BENCHMARK_API( 131, LIQUID_FFT_FORWARD) void benchmark_fft_137 LIQUID_FFT_BENCHMARK_API( 137, LIQUID_FFT_FORWARD) void benchmark_fft_139 LIQUID_FFT_BENCHMARK_API( 139, LIQUID_FFT_FORWARD) void benchmark_fft_149 LIQUID_FFT_BENCHMARK_API( 149, LIQUID_FFT_FORWARD) void benchmark_fft_151 LIQUID_FFT_BENCHMARK_API( 151, LIQUID_FFT_FORWARD) void benchmark_fft_157 LIQUID_FFT_BENCHMARK_API( 157, LIQUID_FFT_FORWARD) void benchmark_fft_163 LIQUID_FFT_BENCHMARK_API( 163, LIQUID_FFT_FORWARD) void benchmark_fft_167 LIQUID_FFT_BENCHMARK_API( 167, LIQUID_FFT_FORWARD) void benchmark_fft_173 LIQUID_FFT_BENCHMARK_API( 173, LIQUID_FFT_FORWARD) void benchmark_fft_179 LIQUID_FFT_BENCHMARK_API( 179, LIQUID_FFT_FORWARD) void benchmark_fft_181 LIQUID_FFT_BENCHMARK_API( 181, LIQUID_FFT_FORWARD) void benchmark_fft_191 LIQUID_FFT_BENCHMARK_API( 191, LIQUID_FFT_FORWARD) void benchmark_fft_193 LIQUID_FFT_BENCHMARK_API( 193, LIQUID_FFT_FORWARD) void benchmark_fft_197 LIQUID_FFT_BENCHMARK_API( 197, LIQUID_FFT_FORWARD) void benchmark_fft_199 LIQUID_FFT_BENCHMARK_API( 199, LIQUID_FFT_FORWARD) void benchmark_fft_211 LIQUID_FFT_BENCHMARK_API( 211, LIQUID_FFT_FORWARD) void benchmark_fft_223 LIQUID_FFT_BENCHMARK_API( 223, LIQUID_FFT_FORWARD) void benchmark_fft_227 LIQUID_FFT_BENCHMARK_API( 227, LIQUID_FFT_FORWARD) void benchmark_fft_229 LIQUID_FFT_BENCHMARK_API( 229, LIQUID_FFT_FORWARD) void benchmark_fft_233 LIQUID_FFT_BENCHMARK_API( 233, LIQUID_FFT_FORWARD) void benchmark_fft_239 LIQUID_FFT_BENCHMARK_API( 239, LIQUID_FFT_FORWARD) void benchmark_fft_241 LIQUID_FFT_BENCHMARK_API( 241, LIQUID_FFT_FORWARD) void benchmark_fft_251 LIQUID_FFT_BENCHMARK_API( 251, LIQUID_FFT_FORWARD) void benchmark_fft_257 LIQUID_FFT_BENCHMARK_API( 257, LIQUID_FFT_FORWARD) void benchmark_fft_263 LIQUID_FFT_BENCHMARK_API( 263, LIQUID_FFT_FORWARD) void benchmark_fft_269 LIQUID_FFT_BENCHMARK_API( 269, LIQUID_FFT_FORWARD) void benchmark_fft_271 LIQUID_FFT_BENCHMARK_API( 271, LIQUID_FFT_FORWARD) void benchmark_fft_277 LIQUID_FFT_BENCHMARK_API( 277, LIQUID_FFT_FORWARD) void benchmark_fft_281 LIQUID_FFT_BENCHMARK_API( 281, LIQUID_FFT_FORWARD) void benchmark_fft_283 LIQUID_FFT_BENCHMARK_API( 283, LIQUID_FFT_FORWARD) void benchmark_fft_293 LIQUID_FFT_BENCHMARK_API( 293, LIQUID_FFT_FORWARD) void benchmark_fft_307 LIQUID_FFT_BENCHMARK_API( 307, LIQUID_FFT_FORWARD) void benchmark_fft_311 LIQUID_FFT_BENCHMARK_API( 311, LIQUID_FFT_FORWARD) void benchmark_fft_313 LIQUID_FFT_BENCHMARK_API( 313, LIQUID_FFT_FORWARD) void benchmark_fft_317 LIQUID_FFT_BENCHMARK_API( 317, LIQUID_FFT_FORWARD) void benchmark_fft_331 LIQUID_FFT_BENCHMARK_API( 331, LIQUID_FFT_FORWARD) void benchmark_fft_337 LIQUID_FFT_BENCHMARK_API( 337, LIQUID_FFT_FORWARD) void benchmark_fft_347 LIQUID_FFT_BENCHMARK_API( 347, LIQUID_FFT_FORWARD) void benchmark_fft_349 LIQUID_FFT_BENCHMARK_API( 349, LIQUID_FFT_FORWARD) void benchmark_fft_353 LIQUID_FFT_BENCHMARK_API( 353, LIQUID_FFT_FORWARD) void benchmark_fft_359 LIQUID_FFT_BENCHMARK_API( 359, LIQUID_FFT_FORWARD) void benchmark_fft_367 LIQUID_FFT_BENCHMARK_API( 367, LIQUID_FFT_FORWARD) void benchmark_fft_373 LIQUID_FFT_BENCHMARK_API( 373, LIQUID_FFT_FORWARD) void benchmark_fft_379 LIQUID_FFT_BENCHMARK_API( 379, LIQUID_FFT_FORWARD) void benchmark_fft_383 LIQUID_FFT_BENCHMARK_API( 383, LIQUID_FFT_FORWARD) void benchmark_fft_389 LIQUID_FFT_BENCHMARK_API( 389, LIQUID_FFT_FORWARD) void benchmark_fft_397 LIQUID_FFT_BENCHMARK_API( 397, LIQUID_FFT_FORWARD) void benchmark_fft_401 LIQUID_FFT_BENCHMARK_API( 401, LIQUID_FFT_FORWARD) void benchmark_fft_409 LIQUID_FFT_BENCHMARK_API( 409, LIQUID_FFT_FORWARD) void benchmark_fft_419 LIQUID_FFT_BENCHMARK_API( 419, LIQUID_FFT_FORWARD) void benchmark_fft_421 LIQUID_FFT_BENCHMARK_API( 421, LIQUID_FFT_FORWARD) void benchmark_fft_431 LIQUID_FFT_BENCHMARK_API( 431, LIQUID_FFT_FORWARD) void benchmark_fft_433 LIQUID_FFT_BENCHMARK_API( 433, LIQUID_FFT_FORWARD) void benchmark_fft_439 LIQUID_FFT_BENCHMARK_API( 439, LIQUID_FFT_FORWARD) void benchmark_fft_443 LIQUID_FFT_BENCHMARK_API( 443, LIQUID_FFT_FORWARD) void benchmark_fft_449 LIQUID_FFT_BENCHMARK_API( 449, LIQUID_FFT_FORWARD) void benchmark_fft_457 LIQUID_FFT_BENCHMARK_API( 457, LIQUID_FFT_FORWARD) void benchmark_fft_461 LIQUID_FFT_BENCHMARK_API( 461, LIQUID_FFT_FORWARD) void benchmark_fft_463 LIQUID_FFT_BENCHMARK_API( 463, LIQUID_FFT_FORWARD) void benchmark_fft_467 LIQUID_FFT_BENCHMARK_API( 467, LIQUID_FFT_FORWARD) void benchmark_fft_479 LIQUID_FFT_BENCHMARK_API( 479, LIQUID_FFT_FORWARD) void benchmark_fft_487 LIQUID_FFT_BENCHMARK_API( 487, LIQUID_FFT_FORWARD) void benchmark_fft_491 LIQUID_FFT_BENCHMARK_API( 491, LIQUID_FFT_FORWARD) void benchmark_fft_499 LIQUID_FFT_BENCHMARK_API( 499, LIQUID_FFT_FORWARD) void benchmark_fft_503 LIQUID_FFT_BENCHMARK_API( 503, LIQUID_FFT_FORWARD) void benchmark_fft_509 LIQUID_FFT_BENCHMARK_API( 509, LIQUID_FFT_FORWARD) liquid-dsp-1.7.0/src/fft/bench/fft_r2r_benchmark.c000066400000000000000000000074051474751757600217760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_r2r_benchmark.h // // Real even/odd FFT benchmarks (discrete cosine/sine transforms) // #include #include "liquid.h" #define LIQUID_FFT_R2R_BENCH_API(N,K) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { fft_r2r_bench(_start, _finish, _num_iterations, N, K); } // Helper function to keep code base small void fft_r2r_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n, int _kind) { // initialize arrays, plan float x[_n], y[_n]; int _flags = 0; fftplan p = fft_create_plan_r2r_1d(_n, x, y, _kind, _flags); unsigned long int i; // initialize input with random values for (i=0; i<_n; i++) x[i] = randnf(); // scale number of iterations to keep execution time // relatively linear *_num_iterations /= _n * _n; *_num_iterations *= 10; *_num_iterations += 1; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fft_execute(p); fft_execute(p); fft_execute(p); fft_execute(p); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; fft_destroy_plan(p); } // Radix-2 void benchmark_fft_REDFT00_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_REDFT00) void benchmark_fft_REDFT01_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_REDFT01) void benchmark_fft_REDFT10_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_REDFT10) void benchmark_fft_REDFT11_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_REDFT11) void benchmark_fft_RODFT00_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_RODFT00) void benchmark_fft_RODFT01_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_RODFT01) void benchmark_fft_RODFT10_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_RODFT10) void benchmark_fft_RODFT11_128 LIQUID_FFT_R2R_BENCH_API(128, LIQUID_FFT_RODFT11) // prime number void benchmark_fft_REDFT00_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_REDFT00) void benchmark_fft_REDFT01_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_REDFT01) void benchmark_fft_REDFT10_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_REDFT10) void benchmark_fft_REDFT11_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_REDFT11) void benchmark_fft_RODFT00_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_RODFT00) void benchmark_fft_RODFT01_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_RODFT01) void benchmark_fft_RODFT10_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_RODFT10) void benchmark_fft_RODFT11_127 LIQUID_FFT_R2R_BENCH_API(127, LIQUID_FFT_RODFT11) liquid-dsp-1.7.0/src/fft/bench/fft_radix2_benchmark.c000066400000000000000000000047631474751757600224660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_radix2_benchmark.c : benchmark FFTs of length 2^m // #include #include #include #include "liquid.h" #include "src/fft/bench/fft_runbench.h" // power-of-two transforms void benchmark_fft_2 LIQUID_FFT_BENCHMARK_API(2, LIQUID_FFT_FORWARD) void benchmark_fft_4 LIQUID_FFT_BENCHMARK_API(4, LIQUID_FFT_FORWARD) void benchmark_fft_8 LIQUID_FFT_BENCHMARK_API(8, LIQUID_FFT_FORWARD) void benchmark_fft_16 LIQUID_FFT_BENCHMARK_API(16, LIQUID_FFT_FORWARD) void benchmark_fft_32 LIQUID_FFT_BENCHMARK_API(32, LIQUID_FFT_FORWARD) void benchmark_fft_64 LIQUID_FFT_BENCHMARK_API(64, LIQUID_FFT_FORWARD) void benchmark_fft_128 LIQUID_FFT_BENCHMARK_API(128, LIQUID_FFT_FORWARD) void benchmark_fft_256 LIQUID_FFT_BENCHMARK_API(256, LIQUID_FFT_FORWARD) void benchmark_fft_512 LIQUID_FFT_BENCHMARK_API(512, LIQUID_FFT_FORWARD) void benchmark_fft_1024 LIQUID_FFT_BENCHMARK_API(1024, LIQUID_FFT_FORWARD) void benchmark_fft_2048 LIQUID_FFT_BENCHMARK_API(2048, LIQUID_FFT_FORWARD) void benchmark_fft_4096 LIQUID_FFT_BENCHMARK_API(4096, LIQUID_FFT_FORWARD) void benchmark_fft_8192 LIQUID_FFT_BENCHMARK_API(8192, LIQUID_FFT_FORWARD) void benchmark_fft_16384 LIQUID_FFT_BENCHMARK_API(16384, LIQUID_FFT_FORWARD) void benchmark_fft_32768 LIQUID_FFT_BENCHMARK_API(32768, LIQUID_FFT_FORWARD) liquid-dsp-1.7.0/src/fft/bench/fft_runbench.c000066400000000000000000000046021474751757600210570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_runbench.c : benchmark execution program // #include #include #include #include "liquid.h" // Helper function to keep code base small void fft_runbench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _nfft, int _direction) { // initialize arrays, plan float complex * x = (float complex *) fft_malloc(_nfft*sizeof(float complex)); float complex * y = (float complex *) fft_malloc(_nfft*sizeof(float complex)); int _method = 0; fftplan q = fft_create_plan(_nfft, x, y, _direction, _method); unsigned long int i; // initialize input with random values for (i=0; i<_nfft; i++) x[i] = randnf() + randnf()*_Complex_I; // scale number of iterations to keep execution time // relatively linear *_num_iterations /= _nfft; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fft_execute(q); fft_execute(q); fft_execute(q); fft_execute(q); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; fft_destroy_plan(q); fft_free(x); fft_free(y); } liquid-dsp-1.7.0/src/fft/bench/fft_runbench.h000066400000000000000000000034611474751757600210660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_runbench.h : benchmark execution program declaration // #ifndef __FFT_RUNBENCH_H__ #define __FFT_RUNBENCH_H__ #include #define LIQUID_FFT_BENCHMARK_API(NFFT,D) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { fft_runbench(_start, _finish, _num_iterations, NFFT, D); } // Helper function to keep code base small void fft_runbench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _nfft, int _direction); #endif // __FFT_RUNBENCH_H__ liquid-dsp-1.7.0/src/fft/bench/spgramcf_benchmark.c000066400000000000000000000060401474751757600222260ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // benchmark spgram objects #include #include #include #include "liquid.h" // Helper function to keep code base small void spgramcf_runbench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _nfft) { // scale number of iterations to keep execution time // relatively linear *_num_iterations = (*_num_iterations) * liquid_nextpow2(1+_nfft) / _nfft; // create object spgramcf q = spgramcf_create_default(_nfft); // initialize buffer with random values unsigned long int i; unsigned int buf_len = 2400; float complex * buf = (float complex*) malloc(buf_len*sizeof(float complex)); for (i=0; i #include #include #include #include #include "liquid.internal.h" struct ASGRAM(_s) { unsigned int nfft; // transform size (display) unsigned int nfftp; // transform size (processing) unsigned int p; // over-sampling rate SPGRAM() periodogram; // spectral periodogram object TC * X; // spectral periodogram output float * psd; // power spectral density float levels[10]; // threshold for signal levels char levelchar[10]; // characters representing levels unsigned int num_levels; // number of levels float div; // dB per division float ref; // dB reference value }; // create asgram object with size _nfft ASGRAM() ASGRAM(_create)(unsigned int _nfft) { // validate input if (_nfft < 2) return liquid_error_config("asgram%s_create(), fft size must be at least 2", EXTENSION); // create main object ASGRAM() q = (ASGRAM()) malloc(sizeof(struct ASGRAM(_s))); q->nfft = _nfft; // derived values q->p = 4; // over-sampling rate q->nfftp = q->nfft * q->p; // allocate memory for PSD estimate q->X = (TC * ) malloc((q->nfftp)*sizeof(TC) ); q->psd = (float *) malloc((q->nfftp)*sizeof(float)); // create spectral periodogram object q->periodogram = SPGRAM(_create)(q->nfftp,LIQUID_WINDOW_HANN,q->nfft,q->nfft/2); // power spectral density levels q->num_levels = 10; ASGRAM(_set_display)(q," .,-+*&NM#"); ASGRAM(_set_scale)(q, 0.0f, 10.0f); return q; } // copy object ASGRAM() ASGRAM(_copy)(ASGRAM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("spgram%s_copy(), object cannot be NULL", EXTENSION); // allocate memory for main object ASGRAM() q_copy = (ASGRAM()) malloc(sizeof(struct ASGRAM(_s))); // copy all internal memory memmove(q_copy, q_orig, sizeof(struct ASGRAM(_s))); // create periodogram object q_copy->periodogram = SPGRAM(_copy)(q_orig->periodogram); // allocate and copy memory arrays q_copy->X = (TC * ) malloc((q_copy->nfftp)*sizeof(TC) ); q_copy->psd = (float *) malloc((q_copy->nfftp)*sizeof(float)); memmove(q_copy->X, q_orig->X, q_copy->nfftp*sizeof(TC)); memmove(q_copy->psd, q_orig->psd, q_copy->nfftp*sizeof(float)); // return copied object return q_copy; } // destroy asgram object int ASGRAM(_destroy)(ASGRAM() _q) { // destroy spectral periodogram object SPGRAM(_destroy)(_q->periodogram); // free PSD estimate array free(_q->X); free(_q->psd); // free main object memory free(_q); return LIQUID_OK; } // resets the internal state of the asgram object int ASGRAM(_reset)(ASGRAM() _q) { return SPGRAM(_reset)(_q->periodogram); } // set scale and offset for spectrogram // _q : asgram object // _ref : signal reference level [dB] // _div : signal division [dB] int ASGRAM(_set_scale)(ASGRAM() _q, float _ref, float _div) { if (_div <= 0.0f) return liquid_error(LIQUID_EICONFIG,"asgram%s_set_scale(), div must be greater than zero", EXTENSION); _q->ref = _ref; _q->div = _div; unsigned int i; for (i=0; i<_q->num_levels; i++) _q->levels[i] = _q->ref + i*_q->div; return LIQUID_OK; } // set display characters for output string // _q : asgram object // _ascii : 10-character display, default: " .,-+*&NM#" int ASGRAM(_set_display)(ASGRAM() _q, const char * _ascii) { unsigned int i; for (i=0; i<10; i++) { if (_ascii[i] == '\0') { liquid_error(LIQUID_EICONFIG,"asgram%s_display(), invalid use of null character", EXTENSION); _q->levelchar[i] = '?'; } else { _q->levelchar[i] = _ascii[i]; } } return LIQUID_OK; } // push a single sample into the asgram object // _q : asgram object // _x : input buffer [size: _n x 1] // _n : input buffer length int ASGRAM(_push)(ASGRAM() _q, TI _x) { // push sample into internal spectral periodogram return SPGRAM(_push)(_q->periodogram, _x); } // write a block of samples to the asgram object // _q : asgram object // _x : input buffer [size: _n x 1] // _n : input buffer length int ASGRAM(_write)(ASGRAM() _q, TI * _x, unsigned int _n) { // write samples to internal spectral periodogram return SPGRAM(_write)(_q->periodogram, _x, _n); } // compute spectral periodogram output from current buffer contents // _q : ascii spectrogram object // _ascii : output ASCII string [size: _nfft x 1] // _peakval : value at peak (returned value) // _peakfreq : frequency at peak (returned value) int ASGRAM(_execute)(ASGRAM() _q, char * _ascii, float * _peakval, float * _peakfreq) { // check number of transforms if (SPGRAM(_get_num_transforms)(_q->periodogram)==0) { memset(_ascii,' ',_q->nfft); *_peakval = 0.0f; *_peakfreq = 0.0f; return LIQUID_OK; } // execute spectral periodogram SPGRAM(_get_psd)(_q->periodogram, _q->psd); SPGRAM(_reset)(_q->periodogram); unsigned int i; unsigned int j; // find peak for (i=0; i<_q->nfftp; i++) { if (i==0 || _q->psd[i] > *_peakval) { *_peakval = _q->psd[i]; *_peakfreq = (float)(i) / (float)(_q->nfftp) - 0.5f; } } // down-sample from nfft*p frequency bins to just nfft by retaining // one value (e.g. maximum or average) over range. for (i=0; i<_q->nfft; i++) { #if 0 // find maximum within 'p' samples float psd_val = 0.0f; for (j=0; j<_q->p; j++) { unsigned int index = (_q->p*i) + j; psd_val = (j==0 || _q->psd[index] > psd_val) ? _q->psd[index] : psd_val; } #else // find average over 'p' samples float psd_val = 0.0f; for (j=0; j<_q->p; j++) psd_val += _q->psd[(_q->p*i) + j]; psd_val /= (float)(_q->p); #endif // determine ascii level (which character to use) _ascii[i] = _q->levelchar[0]; for (j=0; j<_q->num_levels; j++) { if ( psd_val > _q->levels[j] ) _ascii[i] = _q->levelchar[j]; } } // append null character to end of string //_ascii[i] = '\0'; return LIQUID_OK; } // compute spectral periodogram output from current buffer // contents and print standard format to stdout int ASGRAM(_print)(ASGRAM() _q) { float maxval; float maxfreq; char ascii[_q->nfft+1]; memset(ascii, '\0', _q->nfft+1); // fill buffer with null characters // execute the spectrogram ASGRAM(_execute)(_q, ascii, &maxval, &maxfreq); // print the spectrogram to stdout printf(" > %s < pk%5.1f dB [%5.2f]\n", ascii, maxval, maxfreq); return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/dct_execute.proto.c000066400000000000000000000061351474751757600215650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // DCT : Discrete Cosine Transforms // #include #include #include "liquid.internal.h" // DCT-I void FFT(_execute_REDFT00)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft-1); float phi; for (i=0; i<_q->nfft; i++) { T x0 = _q->xr[0]; // first element T xn = _q->xr[_q->nfft-1]; // last element _q->yr[i] = 0.5f*( x0 + (i%2 ? -xn : xn)); for (k=1; k<_q->nfft-1; k++) { phi = M_PI*n_inv*((float)k)*((float)i); _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } } // DCT-II (regular 'dct') void FFT(_execute_REDFT10)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)_q->nfft; float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k + 0.5f)*i; _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } } // DCT-III (regular 'idct') void FFT(_execute_REDFT01)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)_q->nfft; float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = _q->xr[0]*0.5f; for (k=1; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)i + 0.5f)*k; _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } } // DCT-IV void FFT(_execute_REDFT11)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k+0.5f)*((float)i+0.5f); _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } } liquid-dsp-1.7.0/src/fft/src/fct_execute.proto.c000066400000000000000000000063031474751757600215640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fct_exeucte.c // // FCT : Fast (Discrete) Cosine Transforms // #include #include #include "liquid.internal.h" // // DCT-I // // // DCT-II (regular 'dct') // void FFT(_execute_REDFT10_fftn)(FFT(plan) _p) { unsigned int i; unsigned int r = _p->n % 2; unsigned int L = (_p->n - r)/2; // precondition fft for (i=0; ixc[i] = _p->xr[2*i+0]; _p->xc[_p->n-i-1] = _p->xr[2*i+1]; } // check for odd condition if (r==1) _p->xc[L] = _p->xr[2*L]; // execute fft, storing result in _p->yc FFT(_execute)(_p->internal_plan); // post-condition output for (i=0; i<_p->n; i++) _p->yr[i] = 2.0f*crealf(_p->yc[i]*cexpf(-_Complex_I*0.5f*M_PI*i/((float)_p->n))); } // // DCT-III (regular 'idct') // void FFT(_execute_REDFT01_fftn)(FFT(plan) _p) { unsigned int i; unsigned int r = _p->n % 2; unsigned int L = (_p->n - r)/2; // precondition fft for (i=0; i<_p->n; i++) _p->xc[i] = _p->xr[i] * cexpf(_Complex_I*0.5f*M_PI*i/((float)_p->n)); // execute fft, storing result in _p->yc FFT(_execute)(_p->internal_plan); // post-condition output for (i=0; iyr[2*i ] = 2.0f * crealf( _p->yc[i] ); _p->yr[2*i+1] = 2.0f * crealf( _p->yc[_p->n-i-1] ); } // check for odd condition if (r==1) _p->yr[2*L] = 2.0f * crealf( _p->yc[L] ); } // // DCT-IV // void FFT(_execute_REDFT11_fft4n)(FFT(plan) _p) { // NOTE: this method is only faster if n >= 64 and is radix-2 unsigned int i; // precondition fft for (i=0; i<_p->n; i++) { _p->xc[0*(_p->n) + i] = _p->xr[i]; _p->xc[1*(_p->n) + i] = -_p->xr[_p->n-i-1]; _p->xc[2*(_p->n) + i] = -_p->xr[i]; _p->xc[3*(_p->n) + i] = _p->xr[_p->n-i-1]; } // execute fft, storing result in _p->yc FFT(_execute)(_p->internal_plan); // post-condition output for (i=0; i<_p->n; i++) { float theta = 0.5 * M_PI * ((float)i + 0.5) / ((float)_p->n); _p->yr[i] = 0.5f*crealf(_p->yc[2*i+1]*cexpf(-_Complex_I*theta)); } } liquid-dsp-1.7.0/src/fft/src/fft_common.proto.c000066400000000000000000000277511474751757600214270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_common.c : common utilities specific to precision // #include #include #include "liquid.internal.h" struct FFT(plan_s) { // common data unsigned int nfft; // fft size TC * x; // input array pointer (not allocated) TC * y; // output array pointer (not allocated) int direction; // forward/reverse int flags; liquid_fft_type type; // type of transform liquid_fft_method method; // transform method // 'execute' function pointer FFT(_execute_t) * execute; // real even/odd DFT parameters (DCT/DST) T * xr; // input array (real) T * yr; // output array (real) // common data structure shared between specific FFT algorithms union { // DFT struct { TC * twiddle; // twiddle factors DOTPROD() * dotprod; // inner dot products } dft; // radix-2 transform data struct { unsigned int m; // log2(nfft) unsigned int * index_rev; // reversed indices TC * twiddle; // twiddle factors } radix2; // recursive mixed-radix transform data: // - compute 'Q' FFTs of size 'P' // - apply twiddle factors // - compute 'P' FFTs of size 'Q' // - transpose result struct { unsigned int P; // first FFT size unsigned int Q; // second FFT size TC * x; // input buffer (copied) TC * t0; // temporary buffer (small FFT input) TC * t1; // temporary buffer (small FFT output) TC * twiddle; // twiddle factors FFT(plan) fft_P; // sub-transform of size P FFT(plan) fft_Q; // sub-transform of size Q } mixedradix; // Rader's algorithm for computing FFTs of prime length struct { unsigned int * seq; // transformation sequence, size: nfft-1 TC * R; // DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft-1 TC * x_prime; // sub-transform time-domain buffer TC * X_prime; // sub-transform freq-domain buffer FFT(plan) fft; // sub-FFT of size nfft-1 FFT(plan) ifft; // sub-IFFT of size nfft-1 } rader; // Rader's alternate algorithm for computing FFTs of prime length struct { unsigned int nfft_prime; unsigned int * seq; // transformation sequence, size: nfft_prime TC * R; // DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft_prime TC * x_prime; // sub-transform time-domain buffer TC * X_prime; // sub-transform freq-domain buffer FFT(plan) fft; // sub-FFT of size nfft_prime FFT(plan) ifft; // sub-IFFT of size nfft_prime } rader2; } data; }; // allocate one-dimensional array // _n : array size void * FFT(_malloc)(unsigned int _n) { return FFT_MALLOC(_n); } // allocate one-dimensional array allocated by fft_malloc // _x : pointer to array void FFT(_free)(void * _x) { FFT_FREE(_x); } // create FFT plan, regular complex one-dimensional transform // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _flags : fft method FFT(plan) FFT(_create_plan)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // determine best method for execution // TODO : check flags and allow user override liquid_fft_method method = liquid_fft_estimate_method(_nfft); // initialize fft based on method switch (method) { case LIQUID_FFT_METHOD_RADIX2: // use radix-2 decimation-in-time method return FFT(_create_plan_radix2)(_nfft, _x, _y, _dir, _flags); case LIQUID_FFT_METHOD_MIXED_RADIX: // use Cooley-Tukey mixed-radix algorithm return FFT(_create_plan_mixed_radix)(_nfft, _x, _y, _dir, _flags); case LIQUID_FFT_METHOD_RADER: // use Rader's algorithm for FFTs of prime length return FFT(_create_plan_rader)(_nfft, _x, _y, _dir, _flags); case LIQUID_FFT_METHOD_RADER2: // use Rader's algorithm for FFTs of prime length return FFT(_create_plan_rader2)(_nfft, _x, _y, _dir, _flags); case LIQUID_FFT_METHOD_DFT: // use slow DFT return FFT(_create_plan_dft)(_nfft, _x, _y, _dir, _flags); case LIQUID_FFT_METHOD_UNKNOWN: default:; } return liquid_error_config("fft_create_plan(), unknown/invalid fft method (%u)", method); } // destroy FFT plan int FFT(_destroy_plan)(FFT(plan) _q) { switch (_q->type) { // complex one-dimensional transforms case LIQUID_FFT_FORWARD: case LIQUID_FFT_BACKWARD: switch (_q->method) { case LIQUID_FFT_METHOD_DFT: return FFT(_destroy_plan_dft)(_q); case LIQUID_FFT_METHOD_RADIX2: return FFT(_destroy_plan_radix2)(_q); case LIQUID_FFT_METHOD_MIXED_RADIX: return FFT(_destroy_plan_mixed_radix)(_q); case LIQUID_FFT_METHOD_RADER: return FFT(_destroy_plan_rader)(_q); case LIQUID_FFT_METHOD_RADER2: return FFT(_destroy_plan_rader2)(_q); case LIQUID_FFT_METHOD_UNKNOWN: default:; } return liquid_error(LIQUID_EIMODE,"fft_destroy_plan(), unknown/invalid fft method (%u)", _q->method); // discrete cosine transforms case LIQUID_FFT_REDFT00: case LIQUID_FFT_REDFT10: case LIQUID_FFT_REDFT01: case LIQUID_FFT_REDFT11: // discrete sine transforms case LIQUID_FFT_RODFT00: case LIQUID_FFT_RODFT10: case LIQUID_FFT_RODFT01: case LIQUID_FFT_RODFT11: return FFT(_destroy_plan_r2r_1d)(_q); // modified discrete cosine transform case LIQUID_FFT_MDCT: return LIQUID_OK; case LIQUID_FFT_IMDCT: return LIQUID_OK; case LIQUID_FFT_UNKNOWN: default:; } return liquid_error(LIQUID_EIMODE,"fft_destroy_plan(), unknown/invalid fft type (%u)", _q->type); } // print FFT plan int FFT(_print_plan)(FFT(plan) _q) { switch (_q->type) { // complex one-dimensional transforms case LIQUID_FFT_FORWARD: case LIQUID_FFT_BACKWARD: printf("fft plan [%s], n=%u, ", _q->direction == LIQUID_FFT_FORWARD ? "forward" : "reverse", _q->nfft); switch (_q->method) { case LIQUID_FFT_METHOD_DFT: printf("DFT\n"); break; case LIQUID_FFT_METHOD_RADIX2: printf("Radix-2\n"); break; case LIQUID_FFT_METHOD_MIXED_RADIX: printf("Cooley-Tukey\n"); break; case LIQUID_FFT_METHOD_RADER: printf("Rader (Type I)\n"); break; case LIQUID_FFT_METHOD_RADER2: printf("Rader (Type II)\n"); break; case LIQUID_FFT_METHOD_UNKNOWN: default: return liquid_error(LIQUID_EIMODE,"fft_print_plan(), unknown/invalid fft method (%u)", _q->method); } // print recursive plan return FFT(_print_plan_recursive)(_q, 0); // discrete cosine transforms case LIQUID_FFT_REDFT00: case LIQUID_FFT_REDFT10: case LIQUID_FFT_REDFT01: case LIQUID_FFT_REDFT11: // discrete sine transforms case LIQUID_FFT_RODFT00: case LIQUID_FFT_RODFT10: case LIQUID_FFT_RODFT01: case LIQUID_FFT_RODFT11: return FFT(_print_plan)(_q); // modified discrete cosine transform case LIQUID_FFT_MDCT: return LIQUID_OK; case LIQUID_FFT_IMDCT: return LIQUID_OK; case LIQUID_FFT_UNKNOWN: default:; } return liquid_error(LIQUID_EIMODE,"fft_print_plan(), unknown/invalid fft type (%u)", _q->type); } // print FFT plan (recursively) int FFT(_print_plan_recursive)(FFT(plan) _q, unsigned int _level) { // print indentation based on recursion level unsigned int i; for (i=0; i<_level; i++) printf(" "); printf("%u, ", _q->nfft); switch (_q->method) { case LIQUID_FFT_METHOD_DFT: printf("DFT\n"); break; case LIQUID_FFT_METHOD_RADIX2: printf("Radix-2\n"); break; case LIQUID_FFT_METHOD_MIXED_RADIX: // two internal transforms printf("Cooley-Tukey mixed radix, Q=%u, P=%u\n", _q->data.mixedradix.Q, _q->data.mixedradix.P); FFT(_print_plan_recursive)(_q->data.mixedradix.fft_Q, _level+1); FFT(_print_plan_recursive)(_q->data.mixedradix.fft_P, _level+1); break; case LIQUID_FFT_METHOD_RADER: printf("Rader (Type-II), nfft-prime=%u\n", _q->nfft-1); FFT(_print_plan_recursive)(_q->data.rader.fft, _level+1); break; case LIQUID_FFT_METHOD_RADER2: printf("Rader (Type-II), nfft-prime=%u\n", _q->data.rader2.nfft_prime); FFT(_print_plan_recursive)(_q->data.rader2.fft, _level+1); break; case LIQUID_FFT_METHOD_UNKNOWN: printf("(unknown)\n"); break; default: printf("(unknown)\n"); break; } return LIQUID_OK; } // execute fft int FFT(_execute)(FFT(plan) _q) { // invoke internal function pointer return _q->execute(_q); } // perform n-point FFT allocating plan internally // _nfft : fft size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: LIQUID_FFT_{FORWARD,BACKWARD} // _flags : fft flags int FFT(_run)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // create plan FFT(plan) plan = FFT(_create_plan)(_nfft, _x, _y, _dir, _flags); // execute fft FFT(_execute)(plan); // destroy plan FFT(_destroy_plan)(plan); return LIQUID_OK; } // perform real n-point FFT allocating plan internally // _nfft : fft size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _type : fft type, e.g. LIQUID_FFT_REDFT10 // _flags : fft flags int FFT(_r2r_1d_run)(unsigned int _nfft, T * _x, T * _y, int _type, int _flags) { // create plan FFT(plan) plan = FFT(_create_plan_r2r_1d)(_nfft, _x, _y, _type, _flags); // execute fft FFT(_execute)(plan); // destroy plan FFT(_destroy_plan)(plan); return LIQUID_OK; } // perform _n-point FFT shift int FFT(_shift)(TC *_x, unsigned int _n) { unsigned int i, n2; if (_n%2) n2 = (_n-1)/2; else n2 = _n/2; TC tmp; for (i=0; i #include #include #include "liquid.internal.h" // create FFT plan for regular DFT // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_dft)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_DFT; q->data.dft.twiddle = NULL; q->data.dft.dotprod = NULL; // check size, use specific codelet for small DFTs if (q->nfft == 2) q->execute = FFT(_execute_dft_2); else if (q->nfft == 3) q->execute = FFT(_execute_dft_3); else if (q->nfft == 4) q->execute = FFT(_execute_dft_4); else if (q->nfft == 5) q->execute = FFT(_execute_dft_5); else if (q->nfft == 6) q->execute = FFT(_execute_dft_6); else if (q->nfft == 7) q->execute = FFT(_execute_dft_7); else if (q->nfft == 8) q->execute = FFT(_execute_dft_8); else if (q->nfft ==16) q->execute = FFT(_execute_dft_16); else { q->execute = FFT(_execute_dft); // initialize twiddle factors q->data.dft.twiddle = (TC *) malloc(q->nfft * sizeof(TC)); // create dotprod objects q->data.dft.dotprod = (DOTPROD()*) malloc(q->nfft * sizeof(DOTPROD())); // create dotprod objects // twiddles: exp(-j*2*pi*W/n), W= // 0 0 0 0 0... // 0 1 2 3 4... // 0 2 4 6 8... // 0 3 6 9 12... // ... // Note that first row/column is zero, no multiplication necessary. // Create dotprod for first row anyway because it's still faster... unsigned int i; unsigned int k; T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; infft; i++) { // initialize twiddle factors // NOTE: no need to compute first twiddle because exp(-j*2*pi*0) = 1 for (k=1; knfft; k++) q->data.dft.twiddle[k-1] = cexpf(_Complex_I*d*2*M_PI*(T)(k*i) / (T)(q->nfft)); // create dotprod object q->data.dft.dotprod[i] = DOTPROD(_create)(q->data.dft.twiddle, q->nfft-1); } } return q; } // destroy FFT plan int FFT(_destroy_plan_dft)(FFT(plan) _q) { // free twiddle factors if (_q->data.dft.twiddle != NULL) free(_q->data.dft.twiddle); // free dotprod objects if (_q->data.dft.dotprod != NULL) { unsigned int i; for (i=0; i<_q->nfft; i++) DOTPROD(_destroy)(_q->data.dft.dotprod[i]); // free dotprod array free(_q->data.dft.dotprod); } // free main object memory free(_q); return LIQUID_OK; } // execute DFT (slow but functionally correct) int FFT(_execute_dft)(FFT(plan) _q) { unsigned int i; unsigned int nfft = _q->nfft; #if 0 // DC value is sum of input _q->y[0] = _q->x[0]; for (i=1; iy[0] += _q->x[i]; // compute remaining DFT values unsigned int k; for (i=1; iy[i] = _q->x[0]; for (k=1; ky[i] += _q->x[k] * _q->data.dft.twiddle[(i*k)%_q->nfft]; } } #else // use vector dot products // NOTE: no need to compute first multiplication because exp(-j*2*pi*0) = 1 for (i=0; idata.dft.dotprod[i], &_q->x[1], &_q->y[i]); _q->y[i] += _q->x[0]; } #endif return LIQUID_OK; } // // codelets for small DFTs // // int FFT(_execute_dft_2)(FFT(plan) _q) { _q->y[0] = _q->x[0] + _q->x[1]; _q->y[1] = _q->x[0] - _q->x[1]; return LIQUID_OK; } // int FFT(_execute_dft_3)(FFT(plan) _q) { #if 0 // NOTE: not as fast as other method, but perhaps useful for // fixed-point algorithm // x = a + jb // y = c + jd // We want to compute both x*y and x*conj(y) with as few // multiplications as possible. If we define // k1 = a*(c+d); // k2 = d*(a+b); // k3 = c*(b-a); // k4 = b*(c+d); // then // x*y = (k1-k2) + j(k1+k3) // x*conj(y) = (k4-k3) + j(k4-k2) T a, b; // c=real(g)=-0.5, d=imag(g)=-sqrt(3)/2 T k1, k2, k3, k4; // compute both _q->x[1]*g and _q->x[1]*conj(g) with only 4 real multiplications a = crealf(_q->x[1]); b = cimagf(_q->x[1]); //k1 = a*(-0.5f + -0.866025403784439f); k1 = -1.36602540378444f*a; k2 = -0.866025403784439f*( a + b); k3 = -0.5f*( b - a); //k4 = b*(-0.5f + -0.866025403784439f); k4 = -1.36602540378444f*b; TC ta1 = (k1-k2) + _Complex_I*(k1+k3); // TC tb1 = (k4-k3) + _Complex_I*(k4-k2); // // compute both _q->x[2]*g and _q->x[2]*conj(g) with only 4 real multiplications a = crealf(_q->x[2]); b = cimagf(_q->x[2]); //k1 = a*(-0.5f + -0.866025403784439f); k1 = -1.36602540378444f*a; k2 = -0.866025403784439f*( a + b); k3 = -0.5f*( b - a); //k4 = b*(-0.5f + -0.866025403784439f); k4 = -1.36602540378444f*b; TC ta2 = (k1-k2) + _Complex_I*(k1+k3); // TC tb2 = (k4-k3) + _Complex_I*(k4-k2); // // set return values _q->y[0] = _q->x[0] + _q->x[1] + _q->x[2]; if (_q->direction == LIQUID_FFT_FORWARD) { _q->y[1] = _q->x[0] + ta1 + tb2; _q->y[2] = _q->x[0] + tb1 + ta2; } else { _q->y[1] = _q->x[0] + tb1 + ta2; _q->y[2] = _q->x[0] + ta1 + tb2; } #else TC g = -0.5f - _Complex_I*0.866025403784439; // sqrt(3)/2 _q->y[0] = _q->x[0] + _q->x[1] + _q->x[2]; TC ta = _q->x[0] + _q->x[1]*g + _q->x[2]*conjf(g); TC tb = _q->x[0] + _q->x[1]*conjf(g) + _q->x[2]*g; // set return values if (_q->direction == LIQUID_FFT_FORWARD) { _q->y[1] = ta; _q->y[2] = tb; } else { _q->y[1] = tb; _q->y[2] = ta; } #endif return LIQUID_OK; } // int FFT(_execute_dft_4)(FFT(plan) _q) { TC yp; TC * x = _q->x; TC * y = _q->y; // index reversal y[0] = x[0]; y[1] = x[2]; y[2] = x[1]; y[3] = x[3]; // k0 = 0, k1=1 yp = y[1]; y[1] = y[0] - yp; y[0] = y[0] + yp; // k0 = 2, k1=3 yp = y[3]; y[3] = y[2] - yp; y[2] = y[2] + yp; // k0 = 0, k1=2 yp = y[2]; y[2] = y[0] - yp; y[0] = y[0] + yp; // k0 = 1, k1=3 yp = cimagf(y[3]) - _Complex_I*crealf(y[3]); if (_q->direction == LIQUID_FFT_BACKWARD) yp = -yp; y[3] = y[1] - yp; y[1] = y[1] + yp; return LIQUID_OK; } // int FFT(_execute_dft_5)(FFT(plan) _q) { TC * x = _q->x; TC * y = _q->y; // DC value is sum of inputs y[0] = x[0] + x[1] + x[2] + x[3] + x[4]; // exp(-j*2*pi*1/5) TC g0 = 0.309016994374947 - 0.951056516295154*_Complex_I; // exp(-j*2*pi*2/5) TC g1 = -0.809016994374947 - 0.587785252292473*_Complex_I; if (_q->direction == LIQUID_FFT_BACKWARD) { g0 = conjf(g0); g1 = conjf(g1); } TC g0_conj = conjf(g0); TC g1_conj = conjf(g1); y[1] = x[0] + x[1]*g0 + x[2]*g1 + x[3]*g1_conj + x[4]*g0_conj; y[2] = x[0] + x[1]*g1 + x[2]*g0_conj + x[3]*g0 + x[4]*g1_conj; y[3] = x[0] + x[1]*g1_conj + x[2]*g0 + x[3]*g0_conj + x[4]*g1; y[4] = x[0] + x[1]*g0_conj + x[2]*g1_conj + x[3]*g1 + x[4]*g0; return LIQUID_OK; } // int FFT(_execute_dft_6)(FFT(plan) _q) { TC * x = _q->x; TC * y = _q->y; // DC value is sum of inputs y[0] = x[0] + x[1] + x[2] + x[3] + x[4] + x[5]; // exp(-j*2*pi*1/6) = 1/2 - j*sqrt(3)/2 TC g = 0.5 - 0.866025403784439*_Complex_I; TC g1, g2, g4, g5; if (_q->direction == LIQUID_FFT_FORWARD) { g1 = g; // exp(-j*2*pi*1/6) g2 = -conjf(g); // exp(-j*2*pi*2/6) g4 = -g; // exp(-j*2*pi*4/6) g5 = conjf(g); // exp(-j*2*pi*5/6) } else { g1 = conjf(g); // exp( j*2*pi*1/6) g2 = -g; // exp( j*2*pi*2/6) g4 = -conjf(g); // exp( j*2*pi*4/6) g5 = g; // exp( j*2*pi*5/6) } y[1] = x[0] + x[1]*g1 + x[2]*g2 - x[3] + x[4]*g4 + x[5]*g5; y[2] = x[0] + x[1]*g2 + x[2]*g4 + x[3] + x[4]*g2 + x[5]*g4; y[3] = x[0] - x[1] + x[2] - x[3] + x[4] - x[5]; y[4] = x[0] + x[1]*g4 + x[2]*g2 + x[3] + x[4]*g4 + x[5]*g2; y[5] = x[0] + x[1]*g5 + x[2]*g4 - x[3] + x[4]*g2 + x[5]*g1; return LIQUID_OK; } // int FFT(_execute_dft_7)(FFT(plan) _q) { TC * x = _q->x; TC * y = _q->y; // DC value is sum of inputs y[0] = x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6]; // initialize twiddle factors TC g1 = 0.623489801858734 - 0.781831482468030 * _Complex_I; // exp(-j*2*pi*1/7) TC g2 = -0.222520933956314 - 0.974927912181824 * _Complex_I; // exp(-j*2*pi*2/7) TC g3 = -0.900968867902419 - 0.433883739117558 * _Complex_I; // exp(-j*2*pi*3/7) if (_q->direction == LIQUID_FFT_FORWARD) { } else { g1 = conjf(g1); // exp(+j*2*pi*1/7) g2 = conjf(g2); // exp(+j*2*pi*2/7) g3 = conjf(g3); // exp(+j*2*pi*3/7) } TC g4 = conjf(g3); TC g5 = conjf(g2); TC g6 = conjf(g1); y[1] = x[0] + x[1]*g1 + x[2]*g2 + x[3]*g3 + x[4]*g4 + x[5]*g5 + x[6]*g6; y[2] = x[0] + x[1]*g2 + x[2]*g4 + x[3]*g6 + x[4]*g1 + x[5]*g3 + x[6]*g5; y[3] = x[0] + x[1]*g3 + x[2]*g6 + x[3]*g2 + x[4]*g5 + x[5]*g1 + x[6]*g4; y[4] = x[0] + x[1]*g4 + x[2]*g1 + x[3]*g5 + x[4]*g2 + x[5]*g6 + x[6]*g3; y[5] = x[0] + x[1]*g5 + x[2]*g3 + x[3]*g1 + x[4]*g6 + x[5]*g4 + x[6]*g2; y[6] = x[0] + x[1]*g6 + x[2]*g5 + x[3]*g4 + x[4]*g3 + x[5]*g2 + x[6]*g1; return LIQUID_OK; } // int FFT(_execute_dft_8)(FFT(plan) _q) { TC yp; TC * x = _q->x; TC * y = _q->y; // fft or ifft? int fft = _q->direction == LIQUID_FFT_FORWARD ? 1 : 0; // index reversal y[0] = x[0]; y[1] = x[4]; y[2] = x[2]; y[3] = x[6]; y[4] = x[1]; y[5] = x[5]; y[6] = x[3]; y[7] = x[7]; // i=0 yp = y[1]; y[1] = y[0]-yp; y[0] += yp; yp = y[3]; y[3] = y[2]-yp; y[2] += yp; yp = y[5]; y[5] = y[4]-yp; y[4] += yp; yp = y[7]; y[7] = y[6]-yp; y[6] += yp; // i=1 yp = y[2]; y[2] = y[0]-yp; y[0] += yp; yp = y[6]; y[6] = y[4]-yp; y[4] += yp; if (fft) yp = cimagf(y[3]) - crealf(y[3])*_Complex_I; else yp = -cimagf(y[3]) + crealf(y[3])*_Complex_I; y[3] = y[1]-yp; y[1] += yp; if (fft) yp = cimagf(y[7]) - crealf(y[7])*_Complex_I; else yp = -cimagf(y[7]) + crealf(y[7])*_Complex_I; y[7] = y[5]-yp; y[5] += yp; // i=2 yp = y[4]; y[4] = y[0]-yp; y[0] += yp; if (fft) yp = y[5]*(M_SQRT1_2 - M_SQRT1_2*_Complex_I); else yp = y[5]*(M_SQRT1_2 + M_SQRT1_2*_Complex_I); y[5] = y[1]-yp; y[1] += yp; if (fft) yp = cimagf(y[6]) - crealf(y[6])*_Complex_I; else yp = -cimagf(y[6]) + crealf(y[6])*_Complex_I; y[6] = y[2]-yp; y[2] += yp; if (fft) yp = y[7]*(-M_SQRT1_2 - M_SQRT1_2*_Complex_I); else yp = y[7]*(-M_SQRT1_2 + M_SQRT1_2*_Complex_I); y[7] = y[3]-yp; y[3] += yp; return LIQUID_OK; } // int FFT(_execute_dft_16)(FFT(plan) _q) { TC yp; TC * x = _q->x; TC * y = _q->y; // fft or ifft? int fft = _q->direction == LIQUID_FFT_FORWARD ? 1 : 0; // index reversal y[ 0] = x[ 0]; y[ 1] = x[ 8]; y[ 2] = x[ 4]; y[ 3] = x[12]; y[ 4] = x[ 2]; y[ 5] = x[10]; y[ 6] = x[ 6]; y[ 7] = x[14]; y[ 8] = x[ 1]; y[ 9] = x[ 9]; y[10] = x[ 5]; y[11] = x[13]; y[12] = x[ 3]; y[13] = x[11]; y[14] = x[ 7]; y[15] = x[15]; // i=0 yp = y[ 1]; y[ 1] = y[ 0] - yp; y[ 0] += yp; yp = y[ 3]; y[ 3] = y[ 2] - yp; y[ 2] += yp; yp = y[ 5]; y[ 5] = y[ 4] - yp; y[ 4] += yp; yp = y[ 7]; y[ 7] = y[ 6] - yp; y[ 6] += yp; yp = y[ 9]; y[ 9] = y[ 8] - yp; y[ 8] += yp; yp = y[11]; y[11] = y[10] - yp; y[10] += yp; yp = y[13]; y[13] = y[12] - yp; y[12] += yp; yp = y[15]; y[15] = y[14] - yp; y[14] += yp; // i=1 yp = y[ 2]; y[ 2] = y[ 0] - yp; y[ 0] += yp; yp = y[ 6]; y[ 6] = y[ 4] - yp; y[ 4] += yp; yp = y[10]; y[10] = y[ 8] - yp; y[ 8] += yp; yp = y[14]; y[14] = y[12] - yp; y[12] += yp; if (fft) { yp = -y[ 3]*_Complex_I; y[ 3] = y[ 1] - yp; y[ 1] += yp; yp = -y[ 7]*_Complex_I; y[ 7] = y[ 5] - yp; y[ 5] += yp; yp = -y[11]*_Complex_I; y[11] = y[ 9] - yp; y[ 9] += yp; yp = -y[15]*_Complex_I; y[15] = y[13] - yp; y[13] += yp; } else { yp = y[ 3]*_Complex_I; y[ 3] = y[ 1] - yp; y[ 1] += yp; yp = y[ 7]*_Complex_I; y[ 7] = y[ 5] - yp; y[ 5] += yp; yp = y[11]*_Complex_I; y[11] = y[ 9] - yp; y[ 9] += yp; yp = y[15]*_Complex_I; y[15] = y[13] - yp; y[13] += yp; } // i=2 yp = y[ 4]; y[ 4] = y[ 0] - yp; y[ 0] += yp; yp = y[12]; y[12] = y[ 8] - yp; y[ 8] += yp; if (fft) { yp = y[ 5]*( 0.70710677 + _Complex_I* -0.70710677); y[ 5] = y[ 1] - yp; y[ 1] += yp; yp = y[13]*( 0.70710677 + _Complex_I* -0.70710677); y[13] = y[ 9] - yp; y[ 9] += yp; yp = -y[ 6]*_Complex_I; y[ 6] = y[ 2] - yp; y[ 2] += yp; yp = -y[14]*_Complex_I; y[14] = y[10] - yp; y[10] += yp; yp = y[ 7]*( -0.70710677 + _Complex_I* -0.70710677); y[ 7] = y[ 3] - yp; y[ 3] += yp; yp = y[15]*( -0.70710677 + _Complex_I* -0.70710677); y[15] = y[11] - yp; y[11] += yp; } else { yp = y[ 5]*( 0.70710677 - _Complex_I* -0.70710677); y[ 5] = y[ 1] - yp; y[ 1] += yp; yp = y[13]*( 0.70710677 - _Complex_I* -0.70710677); y[13] = y[ 9] - yp; y[ 9] += yp; yp = y[ 6]*_Complex_I; y[ 6] = y[ 2] - yp; y[ 2] += yp; yp = y[14]*_Complex_I; y[14] = y[10] - yp; y[10] += yp; yp = y[ 7]*( -0.70710677 - _Complex_I* -0.70710677); y[ 7] = y[ 3] - yp; y[ 3] += yp; yp = y[15]*( -0.70710677 - _Complex_I* -0.70710677); y[15] = y[11] - yp; y[11] += yp; } // i=3 yp = y[ 8]; y[ 8] = y[ 0] - yp; y[ 0] += yp; if (fft) { yp = y[ 9]*( 0.92387950 + _Complex_I* -0.38268346); y[ 9] = y[ 1] - yp; y[ 1] += yp; yp = y[10]*( 0.70710677 + _Complex_I* -0.70710677); y[10] = y[ 2] - yp; y[ 2] += yp; yp = y[11]*( 0.38268343 + _Complex_I* -0.92387950); y[11] = y[ 3] - yp; y[ 3] += yp; yp = -y[12]*_Complex_I; y[12] = y[ 4] - yp; y[ 4] += yp; yp = y[13]*( -0.38268340 + _Complex_I* -0.92387956); y[13] = y[ 5] - yp; y[ 5] += yp; yp = y[14]*( -0.70710677 + _Complex_I* -0.70710677); y[14] = y[ 6] - yp; y[ 6] += yp; yp = y[15]*( -0.92387950 + _Complex_I* -0.38268349); y[15] = y[ 7] - yp; y[ 7] += yp; } else { yp = y[ 9]*( 0.92387950 - _Complex_I* -0.38268346); y[ 9] = y[ 1] - yp; y[ 1] += yp; yp = y[10]*( 0.70710677 - _Complex_I* -0.70710677); y[10] = y[ 2] - yp; y[ 2] += yp; yp = y[11]*( 0.38268343 - _Complex_I* -0.92387950); y[11] = y[ 3] - yp; y[ 3] += yp; yp = y[12]*_Complex_I; y[12] = y[ 4] - yp; y[ 4] += yp; yp = y[13]*( -0.38268340 - _Complex_I* -0.92387956); y[13] = y[ 5] - yp; y[ 5] += yp; yp = y[14]*( -0.70710677 - _Complex_I* -0.70710677); y[14] = y[ 6] - yp; y[ 6] += yp; yp = y[15]*( -0.92387950 - _Complex_I* -0.38268349); y[15] = y[ 7] - yp; y[ 7] += yp; } return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/fft_mixed_radix.proto.c000066400000000000000000000201651474751757600224240ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_mixed_radix.c : definitions for mixed-radix transforms using // the Cooley-Tukey algorithm // #include #include #include #include #include "liquid.internal.h" #define FFT_DEBUG_MIXED_RADIX 0 // create FFT plan for regular DFT // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_mixed_radix)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_MIXED_RADIX; q->execute = FFT(_execute_mixed_radix); // find first 'prime' factor of _nfft unsigned int i; unsigned int Q = FFT(_estimate_mixed_radix)(_nfft); if (Q==0) return liquid_error_config("fft_create_plan_mixed_radix(), _nfft=%u is prime", _nfft); if ( (_nfft % Q) != 0 ) return liquid_error_config("fft_create_plan_mixed_radix(), _nfft=%u is not divisible by Q=%u", _nfft, Q); // set mixed-radix data unsigned int P = q->nfft / Q; q->data.mixedradix.Q = Q; q->data.mixedradix.P = P; // allocate memory for buffers unsigned int t_len = Q > P ? Q : P; q->data.mixedradix.t0 = (TC *) FFT_MALLOC(t_len * sizeof(TC)); q->data.mixedradix.t1 = (TC *) FFT_MALLOC(t_len * sizeof(TC)); // allocate memory for input buffers q->data.mixedradix.x = (TC *) malloc(q->nfft * sizeof(TC)); // create P-point FFT plan q->data.mixedradix.fft_P = FFT(_create_plan)(q->data.mixedradix.P, q->data.mixedradix.t0, q->data.mixedradix.t1, q->direction, q->flags); // create Q-point FFT plan q->data.mixedradix.fft_Q = FFT(_create_plan)(q->data.mixedradix.Q, q->data.mixedradix.t0, q->data.mixedradix.t1, q->direction, q->flags); // initialize twiddle factors, indices for mixed-radix transforms // TODO : only allocate necessary twiddle factors q->data.mixedradix.twiddle = (TC *) malloc(q->nfft * sizeof(TC)); T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; infft; i++) q->data.mixedradix.twiddle[i] = cexpf(_Complex_I*d*2*M_PI*(T)i / (T)(q->nfft)); return q; } // destroy FFT plan int FFT(_destroy_plan_mixed_radix)(FFT(plan) _q) { // destroy sub-plans FFT(_destroy_plan)(_q->data.mixedradix.fft_P); FFT(_destroy_plan)(_q->data.mixedradix.fft_Q); // free data specific to mixed-radix transforms FFT_FREE(_q->data.mixedradix.t0); FFT_FREE(_q->data.mixedradix.t1); free(_q->data.mixedradix.x); free(_q->data.mixedradix.twiddle); // free main object memory free(_q); return LIQUID_OK; } // execute mixed-radix FFT int FFT(_execute_mixed_radix)(FFT(plan) _q) { // set internal constants unsigned int P = _q->data.mixedradix.P; // first FFT size unsigned int Q = _q->data.mixedradix.Q; // second FFT size // set pointers TC * t0 = _q->data.mixedradix.t0; // small FFT input buffer TC * t1 = _q->data.mixedradix.t1; // small FFT output buffer TC * x = _q->data.mixedradix.x; // full input buffer (data copied) TC * twiddle = _q->data.mixedradix.twiddle; // twiddle factors // copy input to internal buffer memmove(x, _q->x, _q->nfft*sizeof(TC)); unsigned int i; unsigned int k; // compute 'Q' DFTs of size 'P' #if FFT_DEBUG_MIXED_RADIX printf("computing %u DFTs of size %u\n", Q, P); #endif for (i=0; idata.mixedradix.fft_P); // copy back to input, applying twiddle factors for (k=0; kdata.mixedradix.fft_Q); // copy and transpose for (k=0; ky[k*P+i] = t1[k]; #if DEBUG printf("i=%3u/%3u\n", i, P); for (k=0; ky[k*P+i]), cimagf(_q->y[k*P+i])); #endif } return LIQUID_OK; } // strategize as to best radix to use unsigned int FFT(_estimate_mixed_radix)(unsigned int _nfft) { // compute factors of _nfft unsigned int factors[LIQUID_MAX_FACTORS]; unsigned int num_factors; liquid_factor(_nfft, factors, &num_factors); // check if _nfft is prime if (num_factors < 2) { liquid_error(LIQUID_EICONFIG,"fft_estimate_mixed_radix(), %u is prime", _nfft); return 0; } // if _nfft has many factors of 2, retain for later in favor of // radix2 sub-fft method unsigned int num_factors_2 = 0; unsigned int i; for (i=0; i 0) { #if 0 // check if there are _only_ factors of 2 if (num_factors_2 == num_factors) { // return Q = 2^(ceil(num_factors_2 / 2)) // example: nfft = 128 = 2^7, return Q=2^4 = 16 return 1 << ((num_factors_2 + (num_factors_2%2))/2); } // return 2^num_factors_2 return 1 << num_factors_2; #else // use codelets if ( (_nfft%16)==0 ) return 16; if ( (_nfft% 8)==0 ) return 8; else if ( (_nfft% 4)==0 ) return 4; else return 2; #endif } // return next largest prime factor return factors[0]; } liquid-dsp-1.7.0/src/fft/src/fft_r2r_1d.proto.c000066400000000000000000000161571474751757600212260ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_r2r_1d.c : real-to-real methods (DCT/DST) // #include #include #include #include "liquid.internal.h" // create DCT/DST plan // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _type : type (e.g. LIQUID_FFT_REDFT00) // _method : fft method FFT(plan) FFT(_create_plan_r2r_1d)(unsigned int _nfft, T * _x, T * _y, int _type, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->xr = _x; q->yr = _y; q->type = _type; q->flags = _flags; // TODO : use separate 'method' for real-to-real types //q->method = LIQUID_FFT_METHOD_NONE; switch (q->type) { case LIQUID_FFT_REDFT00: q->execute = &FFT(_execute_REDFT00); break; // DCT-I case LIQUID_FFT_REDFT10: q->execute = &FFT(_execute_REDFT10); break; // DCT-II case LIQUID_FFT_REDFT01: q->execute = &FFT(_execute_REDFT01); break; // DCT-III case LIQUID_FFT_REDFT11: q->execute = &FFT(_execute_REDFT11); break; // DCT-IV case LIQUID_FFT_RODFT00: q->execute = &FFT(_execute_RODFT00); break; // DST-I case LIQUID_FFT_RODFT10: q->execute = &FFT(_execute_RODFT10); break; // DST-II case LIQUID_FFT_RODFT01: q->execute = &FFT(_execute_RODFT01); break; // DST-III case LIQUID_FFT_RODFT11: q->execute = &FFT(_execute_RODFT11); break; // DST-IV default: return liquid_error_config("fft_create_plan_r2r_1d(), invalid type, %d", q->type); } return q; } // destroy real-to-real transform plan int FFT(_destroy_plan_r2r_1d)(FFT(plan) _q) { // free main object memory free(_q); return LIQUID_OK; } // print real-to-real transform plan int FFT(_print_plan_r2r_1d)(FFT(plan) _q) { printf("real-to-real transform...\n"); // TODO: print actual transform type return LIQUID_OK; } // // DCT : Discrete Cosine Transforms // // DCT-I int FFT(_execute_REDFT00)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft-1); float phi; for (i=0; i<_q->nfft; i++) { T x0 = _q->xr[0]; // first element T xn = _q->xr[_q->nfft-1]; // last element _q->yr[i] = 0.5f*( x0 + (i%2 ? -xn : xn)); for (k=1; k<_q->nfft-1; k++) { phi = M_PI*n_inv*((float)k)*((float)i); _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DCT-II (regular 'dct') int FFT(_execute_REDFT10)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)_q->nfft; float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k + 0.5f)*i; _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DCT-III (regular 'idct') int FFT(_execute_REDFT01)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)_q->nfft; float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = _q->xr[0]*0.5f; for (k=1; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)i + 0.5f)*k; _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DCT-IV int FFT(_execute_REDFT11)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k+0.5f)*((float)i+0.5f); _q->yr[i] += _q->xr[k]*cosf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // // DST : Discrete Sine Transforms // // DST-I int FFT(_execute_RODFT00)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft+1); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*(float)((k+1)*(i+1)); _q->yr[i] += _q->xr[k]*sinf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DST-II int FFT(_execute_RODFT10)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k+0.5f)*(i+1); _q->yr[i] += _q->xr[k]*sinf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DST-III int FFT(_execute_RODFT01)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = ((i%2)==0 ? 0.5f : -0.5f) * _q->xr[_q->nfft-1]; for (k=0; k<_q->nfft-1; k++) { phi = M_PI*n_inv*((float)k+1)*((float)i+0.5f); _q->yr[i] += _q->xr[k]*sinf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } // DST-IV int FFT(_execute_RODFT11)(FFT(plan) _q) { // ugly, slow method unsigned int i,k; float n_inv = 1.0f / (float)(_q->nfft); float phi; for (i=0; i<_q->nfft; i++) { _q->yr[i] = 0.0f; for (k=0; k<_q->nfft; k++) { phi = M_PI*n_inv*((float)k+0.5f)*((float)i+0.5f); _q->yr[i] += _q->xr[k]*sinf(phi); } // compensate for discrepancy _q->yr[i] *= 2.0f; } return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/fft_rader.proto.c000066400000000000000000000136361474751757600212310ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_rader.c : definitions for transforms of prime length using // Rader's algorithm // // References: // [Rader:1968] Charles M. Rader, "Discrete Fourier Transforms When // the Number of Data Samples Is Prime," Proceedings of the IEEE, // vol. 56, number 6, pp. 1107--1108, June 1968 // #include #include #include #include #include "liquid.internal.h" #define FFT_DEBUG_RADER 0 // create FFT plan for regular DFT // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_rader)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_RADER; q->execute = FFT(_execute_rader); // allocate memory for sub-transforms q->data.rader.x_prime = (TC*) FFT_MALLOC((q->nfft-1)*sizeof(TC)); q->data.rader.X_prime = (TC*) FFT_MALLOC((q->nfft-1)*sizeof(TC)); // create sub-FFT of size nfft-1 q->data.rader.fft = FFT(_create_plan)(q->nfft-1, q->data.rader.x_prime, q->data.rader.X_prime, LIQUID_FFT_FORWARD, q->flags); // create sub-IFFT of size nfft-1 q->data.rader.ifft = FFT(_create_plan)(q->nfft-1, q->data.rader.X_prime, q->data.rader.x_prime, LIQUID_FFT_BACKWARD, q->flags); // compute primitive root of nfft unsigned int g = liquid_primitive_root_prime(q->nfft); // create and initialize sequence q->data.rader.seq = (unsigned int *)malloc((q->nfft-1)*sizeof(unsigned int)); unsigned int i; for (i=0; infft-1; i++) q->data.rader.seq[i] = liquid_modpow(g, i+1, q->nfft); // compute DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft-1 // NOTE: R[0] = -1, |R[k]| = sqrt(nfft) for k != 0 // (use newly-created FFT plan of length nfft-1) T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; infft-1; i++) q->data.rader.x_prime[i] = cexpf(_Complex_I*d*2*M_PI*q->data.rader.seq[i]/(T)(q->nfft)); FFT(_execute)(q->data.rader.fft); // copy result to R q->data.rader.R = (TC*)malloc((q->nfft-1)*sizeof(TC)); memmove(q->data.rader.R, q->data.rader.X_prime, (q->nfft-1)*sizeof(TC)); // return main object return q; } // destroy FFT plan int FFT(_destroy_plan_rader)(FFT(plan) _q) { // free data specific to Rader's algorithm free(_q->data.rader.seq); // sequence free(_q->data.rader.R); // pre-computed transform of exp(j*2*pi*seq) FFT_FREE(_q->data.rader.x_prime); // sub-transform input array FFT_FREE(_q->data.rader.X_prime); // sub-transform output array FFT(_destroy_plan)(_q->data.rader.fft); FFT(_destroy_plan)(_q->data.rader.ifft); // free main object memory free(_q); return LIQUID_OK; } // execute Rader's algorithm int FFT(_execute_rader)(FFT(plan) _q) { unsigned int i; // compute DFT of permuted sequence, size: nfft-1 for (i=0; i<_q->nfft-1; i++) { // reverse sequence unsigned int k = _q->data.rader.seq[_q->nfft-1-i-1]; _q->data.rader.x_prime[i] = _q->x[k]; } // compute sub-FFT // equivalent to: FFT(_run)(_q->nfft-1, xp, Xp, LIQUID_FFT_FORWARD, 0); FFT(_execute)(_q->data.rader.fft); // compute inverse FFT of product for (i=0; i<_q->nfft-1; i++) _q->data.rader.X_prime[i] *= _q->data.rader.R[i]; // compute sub-IFFT // equivalent to: FFT(_run)(_q->nfft-1, Xp, xp, LIQUID_FFT_BACKWARD, 0); FFT(_execute)(_q->data.rader.ifft); // set DC value _q->y[0] = 0.0f; for (i=0; i<_q->nfft; i++) _q->y[0] += _q->x[i]; // reverse permute result, scale, and add offset x[0] for (i=0; i<_q->nfft-1; i++) { unsigned int k = _q->data.rader.seq[i]; _q->y[k] = _q->data.rader.x_prime[i] / (T)(_q->nfft-1) + _q->x[0]; } return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/fft_rader2.proto.c000066400000000000000000000201351474751757600213030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_rader2.c : definitions for transforms of prime length using // Rader's alternate algorithm // // References: // [Rader:1968] Charles M. Rader, "Discrete Fourier Transforms When // the Number of Data Samples Is Prime," Proceedings of the IEEE, // vol. 56, number 6, pp. 1107--1108, June 1968 // #include #include #include #include "liquid.internal.h" #define FFT_DEBUG_RADER 0 // create FFT plan // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_rader2)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_RADER2; q->execute = FFT(_execute_rader2); unsigned int i; // compute primitive root of nfft unsigned int g = liquid_primitive_root_prime(q->nfft); // create and initialize sequence q->data.rader2.seq = (unsigned int *)malloc((q->nfft-1)*sizeof(unsigned int)); for (i=0; infft-1; i++) q->data.rader2.seq[i] = liquid_modpow(g, i+1, q->nfft); #if 0 // compute larger FFT length greater than 2*nfft-4 // NOTE: while any length greater than 2*nfft-4 will work, use // nfft_prime as smallest 'simple' FFT (mostly small factors) // // TODO: devise better score (fewer factors is better) // score(n) = n / sum(factors(n).^2) float gamma_max = 0.0f; // score unsigned int nfft_prime_opt = 0; unsigned int num_steps = 10;// + q->nfft; for (i=1; i<=num_steps; i++) { unsigned int n_hat = 2*q->nfft - 4 + i; // compute factors unsigned int k; unsigned int num_factors = 0; unsigned int m = n_hat; float gamma = 0.0f; do { for (k=2; k<=m; k++) { if ( (m % k) == 0) { m /= k; num_factors++; gamma += k*k; break; } } } while (m > 1); // compute score: //float gamma = (float)n_hat / (float)num_factors; //float gamma = 1e3f * (float)num_factors / (float)n_hat; gamma = (float)n_hat / gamma; if (gamma > gamma_max) { gamma_max = gamma; nfft_prime_opt = n_hat; } } q->data.rader2.nfft_prime = nfft_prime_opt; #else // compute larger FFT length greater than 2*nfft-4 // NOTE: while any length greater than 2*nfft-4 will work, use // nfft_prime = 2 ^ nextpow2( 2*nfft - 4 ) to enable // radix-2 transform unsigned int m=0; q->data.rader2.nfft_prime = (2*q->nfft-4)-1; while (q->data.rader2.nfft_prime > 0) { q->data.rader2.nfft_prime >>= 1; m++; } q->data.rader2.nfft_prime = 1 << m; #endif //printf("nfft_prime = %u\n", q->data.rader2.nfft_prime); // assert(nfft_prime > 2*nfft-4) // allocate memory for sub-transforms q->data.rader2.x_prime = (TC*) FFT_MALLOC((q->data.rader2.nfft_prime)*sizeof(TC)); q->data.rader2.X_prime = (TC*) FFT_MALLOC((q->data.rader2.nfft_prime)*sizeof(TC)); // create sub-FFT of size nfft-1 q->data.rader2.fft = FFT(_create_plan)(q->data.rader2.nfft_prime, q->data.rader2.x_prime, q->data.rader2.X_prime, LIQUID_FFT_FORWARD, q->flags); // create sub-IFFT of size nfft-1 q->data.rader2.ifft = FFT(_create_plan)(q->data.rader2.nfft_prime, q->data.rader2.X_prime, q->data.rader2.x_prime, LIQUID_FFT_BACKWARD, q->flags); // compute DFT of sequence { exp(-j*2*pi*g^i/nfft }, size: nfft_prime // NOTE: R[0] = -1, |R[k]| = sqrt(nfft) for k != 0 // (use newly-created FFT plan of length nfft_prime) T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; idata.rader2.nfft_prime; i++) q->data.rader2.x_prime[i] = cexpf(_Complex_I*d*2*M_PI*q->data.rader2.seq[i%(q->nfft-1)]/(T)(q->nfft)); FFT(_execute)(q->data.rader2.fft); // copy result to R q->data.rader2.R = (TC*)malloc(q->data.rader2.nfft_prime*sizeof(TC)); memmove(q->data.rader2.R, q->data.rader2.X_prime, q->data.rader2.nfft_prime*sizeof(TC)); // return main object return q; } // destroy FFT plan int FFT(_destroy_plan_rader2)(FFT(plan) _q) { // free data specific to Rader's algorithm free(_q->data.rader2.seq); // sequence free(_q->data.rader2.R); // pre-computed transform of exp(j*2*pi*seq) FFT_FREE(_q->data.rader2.x_prime); // sub-transform input array FFT_FREE(_q->data.rader2.X_prime); // sub-transform output array FFT(_destroy_plan)(_q->data.rader2.fft); FFT(_destroy_plan)(_q->data.rader2.ifft); // free main object memory free(_q); return LIQUID_OK; } // execute Rader's algorithm int FFT(_execute_rader2)(FFT(plan) _q) { unsigned int i; // set pointers to internal buffers TC * xp = _q->data.rader2.x_prime; TC * Xp = _q->data.rader2.X_prime; TC * R = _q->data.rader2.R; unsigned int * seq = _q->data.rader2.seq; // set constant values unsigned int nfft_prime = _q->data.rader2.nfft_prime; // compute nfft_prime-length DFT of permuted sequence with // nfft_prime-nfft+1 zeros inserted after first element xp[0] = _q->x[ seq[_q->nfft-2] ]; for (i=0; infft+1; i++) xp[i+1] = 0.0f; for (i=1; i<_q->nfft-1; i++) { // reverse sequence unsigned int k = seq[_q->nfft-1-i-1]; xp[i+nfft_prime-_q->nfft+1] = _q->x[k]; } FFT(_execute)(_q->data.rader2.fft); // compute inverse FFT of product // compute nfft_prime-length inverse FFT of product for (i=0; idata.rader2.ifft); // set DC value _q->y[0] = 0.0f; for (i=0; i<_q->nfft; i++) _q->y[0] += _q->x[i]; // reverse permute result, scale, and add offset x[0] for (i=0; i<_q->nfft-1; i++) { unsigned int k = seq[i]; _q->y[k] = xp[i] / (T)(nfft_prime) + _q->x[0]; } return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/fft_radix2.proto.c000066400000000000000000000110621474751757600213140ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_radix2.c : definitions for transforms of the form 2^m // #include #include #include #include "liquid.internal.h" // create FFT plan for regular DFT // _nfft : FFT size // _x : input array [size: _nfft x 1] // _y : output array [size: _nfft x 1] // _dir : fft direction: {LIQUID_FFT_FORWARD, LIQUID_FFT_BACKWARD} // _method : fft method FFT(plan) FFT(_create_plan_radix2)(unsigned int _nfft, TC * _x, TC * _y, int _dir, int _flags) { // allocate plan and initialize all internal arrays to NULL FFT(plan) q = (FFT(plan)) malloc(sizeof(struct FFT(plan_s))); q->nfft = _nfft; q->x = _x; q->y = _y; q->flags = _flags; q->type = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->direction = (_dir == LIQUID_FFT_FORWARD) ? LIQUID_FFT_FORWARD : LIQUID_FFT_BACKWARD; q->method = LIQUID_FFT_METHOD_RADIX2; q->execute = FFT(_execute_radix2); // initialize twiddle factors, indices for radix-2 transforms q->data.radix2.m = liquid_msb_index(q->nfft) - 1; // m = log2(nfft) q->data.radix2.index_rev = (unsigned int *) malloc((q->nfft)*sizeof(unsigned int)); unsigned int i; for (i=0; infft; i++) q->data.radix2.index_rev[i] = fft_reverse_index(i,q->data.radix2.m); // initialize twiddle factors q->data.radix2.twiddle = (TC *) malloc(q->nfft * sizeof(TC)); T d = (q->direction == LIQUID_FFT_FORWARD) ? -1.0 : 1.0; for (i=0; infft; i++) q->data.radix2.twiddle[i] = cexpf(_Complex_I*d*2*M_PI*(T)i / (T)(q->nfft)); return q; } // destroy FFT plan int FFT(_destroy_plan_radix2)(FFT(plan) _q) { // free data specific to radix-2 transforms free(_q->data.radix2.index_rev); free(_q->data.radix2.twiddle); // free main object memory free(_q); return LIQUID_OK; } // execute radix-2 FFT int FFT(_execute_radix2)(FFT(plan) _q) { // swap values unsigned int i,j,k; // unroll loop unsigned int nfft4 = (_q->nfft>>2)<<2; // floor(_nfft/4) for (i=0; iy[i ] = _q->x[ _q->data.radix2.index_rev[i ] ]; _q->y[i+1] = _q->x[ _q->data.radix2.index_rev[i+1] ]; _q->y[i+2] = _q->x[ _q->data.radix2.index_rev[i+2] ]; _q->y[i+3] = _q->x[ _q->data.radix2.index_rev[i+3] ]; } #if 0 // clean up remaining // NOTE : this only happens when _nfft=2 because we know (_nfft%4)==0 otherwise for ( ; i<_q->nfft; i++) _q->y[i] = _q->x[ _q->data.radix2.index_rev[i] ]; #endif TC yp; TC *y=_q->y; unsigned int n1 = 0; unsigned int n2 = 1; TC t; // twiddle value unsigned int stride = _q->nfft; unsigned int twiddle_index; for (i=0; i<_q->data.radix2.m; i++) { n1 = n2; n2 *= 2; stride >>= 1; twiddle_index = 0; for (j=0; jdata.radix2.twiddle[twiddle_index]; twiddle_index = (twiddle_index + stride) % _q->nfft; for (k=j; k<_q->nfft; k+=n2) { // NOTE: most computation is with the multiplication in next line yp = y[k+n1]*t; y[k+n1] = y[k] - yp; y[k] += yp; } } } return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/fft_utilities.c000066400000000000000000000064401474751757600210000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_utilities.c : common utilities not specific to precision // #include #include #include #include "liquid.internal.h" // clean up fftw's static plan memory int liquid_fftwf_cleanup_wrapper(void) { #if HAVE_FFTW3_H && !defined LIQUID_FFTOVERRIDE fftwf_cleanup(); #endif return LIQUID_OK; } // determine best FFT method based on size liquid_fft_method liquid_fft_estimate_method(unsigned int _nfft) { if (_nfft == 0) { // invalid length liquid_error(LIQUID_EIRANGE,"liquid_fft_estimate_method(), fft size must be > 0"); return LIQUID_FFT_METHOD_UNKNOWN; } else if (_nfft <= 8 || _nfft==11 || _nfft==13 || _nfft==16 || _nfft==17) { // use simple DFT return LIQUID_FFT_METHOD_DFT; } else if (fft_is_radix2(_nfft)) { // transform is of the form 2^m #if 0 // use radix-2 algorithm return LIQUID_FFT_METHOD_RADIX2; #else // actually, prefer Cooley-Tukey algorithm return LIQUID_FFT_METHOD_MIXED_RADIX; #endif } else if (liquid_is_prime(_nfft)) { // prefer Rader's alternate method (using radix-2 transform) // unless _nfft-1 is also radix2 // TODO : also prefer Rader-I if _nfft-1 is mostly factors of 2 if ( fft_is_radix2(_nfft-1) ) return LIQUID_FFT_METHOD_RADER; else return LIQUID_FFT_METHOD_RADER2; } // last resort //return LIQUID_FFT_METHOD_DFT; // use slow DFT method return LIQUID_FFT_METHOD_MIXED_RADIX; // use mixed radix method } // is input radix-2? int fft_is_radix2(unsigned int _n) { // check to see if _n is radix 2 unsigned int i; unsigned int d=0; unsigned int m=0; unsigned int t=_n; for (i=0; i<8*sizeof(unsigned int); i++) { d += (t & 1); // count bits, radix-2 if d==1 if (!m && (t&1)) m = i; // count lagging zeros, effectively log2(n) t >>= 1; } return (d == 1) ? 1 : 0; } // reverse _n-bit index _i unsigned int fft_reverse_index(unsigned int _i, unsigned int _n) { unsigned int j=0, k; for (k=0; k<_n; k++) { j <<= 1; j |= ( _i & 1 ); _i >>= 1; } return j; } liquid-dsp-1.7.0/src/fft/src/fftf.c000066400000000000000000000042671474751757600170600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // FFT API: floating-point (single precision) // #include "liquid.internal.h" // Macro definitions #define FFT(name) LIQUID_CONCAT(fft,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define T float /* primitive type */ #define TC float complex /* primitive type (complex) */ #define PRINTVAL_T(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) // include prototypes #include "fft_common.proto.c" // common source must come first (object definition) #include "fft_dft.proto.c" // FFT definitions for DFT #include "fft_radix2.proto.c" // FFT definitions for radix-2 transforms #include "fft_mixed_radix.proto.c" // FFT definitions for mixed-radix transforms (Cooley-Tukey) #include "fft_rader.proto.c" // FFT definitions for transforms of prime length (Rader's algorithm) #include "fft_rader2.proto.c" // FFT definitions for transforms of prime length (Rader's alternate algorithm) #include "fft_r2r_1d.proto.c" // real-to-real definitions (DCT/DST) liquid-dsp-1.7.0/src/fft/src/spgram.proto.c000066400000000000000000000426311474751757600205630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // spgram (spectral periodogram) // #include #include #include #include #include #include #include "liquid.internal.h" #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) struct SPGRAM(_s) { // options unsigned int nfft; // FFT length int wtype; // window type unsigned int window_len; // window length unsigned int delay; // delay between transforms [samples] float alpha; // spectrum smoothing filter: feedforward parameter float gamma; // spectrum smoothing filter: feedback parameter int accumulate; // accumulate? or use time-average WINDOW() buffer; // input buffer TC * buf_time; // pointer to input array (allocated) TC * buf_freq; // output fft (allocated) T * w; // tapering window [size: window_len x 1] FFT_PLAN fft; // FFT plan // psd accumulation T * psd; // accumulated power spectral density estimate (linear) unsigned int sample_timer; // countdown to transform unsigned long long int num_samples; // total number of samples since reset unsigned long long int num_samples_total; // total number of samples since start unsigned long long int num_transforms; // total number of transforms since reset unsigned long long int num_transforms_total;// total number of transforms since start // parameters for display purposes only float frequency; // center frequency [Hz] float sample_rate; // sample rate [Hz] }; // // internal methods // // compute spectral periodogram output (complex values) // from current buffer contents int SPGRAM(_step)(SPGRAM() _q); // create spgram object // _nfft : FFT size // _wtype : window type, e.g. LIQUID_WINDOW_HAMMING // _window_len : window length // _delay : delay between transforms, _delay > 0 SPGRAM() SPGRAM(_create)(unsigned int _nfft, int _wtype, unsigned int _window_len, unsigned int _delay) { // validate input if (_nfft < 2) return liquid_error_config("spgram%s_create(), fft size must be at least 2", EXTENSION); if (_window_len > _nfft) return liquid_error_config("spgram%s_create(), window size cannot exceed fft size", EXTENSION); if (_window_len == 0) return liquid_error_config("spgram%s_create(), window size must be greater than zero", EXTENSION); if (_wtype == LIQUID_WINDOW_KBD && _window_len % 2) return liquid_error_config("spgram%s_create(), KBD window length must be even", EXTENSION); if (_delay == 0) return liquid_error_config("spgram%s_create(), delay must be greater than 0", EXTENSION); // allocate memory for main object SPGRAM() q = (SPGRAM()) malloc(sizeof(struct SPGRAM(_s))); // set input parameters q->nfft = _nfft; q->wtype = _wtype; q->window_len = _window_len; q->delay = _delay; q->frequency = 0; q->sample_rate= -1; // set object for full accumulation SPGRAM(_set_alpha)(q, -1.0f); // create FFT arrays, object q->buf_time = (TC*) FFT_MALLOC((q->nfft)*sizeof(TC)); q->buf_freq = (TC*) FFT_MALLOC((q->nfft)*sizeof(TC)); q->psd = (T *) malloc((q->nfft)*sizeof(T )); q->fft = FFT_CREATE_PLAN(q->nfft, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, FFT_METHOD); // create buffer q->buffer = WINDOW(_create)(q->window_len); // create window q->w = (T*) malloc((q->window_len)*sizeof(T)); unsigned int i; unsigned int n = q->window_len; float beta = 10.0f; float zeta = 3.0f; for (i=0; iwtype) { case LIQUID_WINDOW_HAMMING: q->w[i] = liquid_hamming(i,n); break; case LIQUID_WINDOW_HANN: q->w[i] = liquid_hann(i,n); break; case LIQUID_WINDOW_BLACKMANHARRIS: q->w[i] = liquid_blackmanharris(i,n); break; case LIQUID_WINDOW_BLACKMANHARRIS7: q->w[i] = liquid_blackmanharris7(i,n); break; case LIQUID_WINDOW_KAISER: q->w[i] = liquid_kaiser(i,n,beta); break; case LIQUID_WINDOW_FLATTOP: q->w[i] = liquid_flattop(i,n); break; case LIQUID_WINDOW_TRIANGULAR: q->w[i] = liquid_triangular(i,n,n); break; case LIQUID_WINDOW_RCOSTAPER: q->w[i] = liquid_rcostaper_window(i,n,n/3); break; case LIQUID_WINDOW_KBD: q->w[i] = liquid_kbd(i,n,zeta); break; default: liquid_error_config("spgram%s_create(), invalid window", EXTENSION); SPGRAM(_destroy)(q); return NULL; } } // scale by window magnitude float g = 0.0f; for (i=0; iwindow_len; i++) g += q->w[i] * q->w[i]; g = 1.0f / sqrtf(g); // scale window and copy for (i=0; iwindow_len; i++) q->w[i] = g * q->w[i]; // reset the spgram object SPGRAM(_reset)(q); // return new object return q; } // create default spgram object (Kaiser-Bessel window) SPGRAM() SPGRAM(_create_default)(unsigned int _nfft) { // validate input if (_nfft < 2) return liquid_error_config("spgram%s_create_default(), fft size must be at least 2", EXTENSION); return SPGRAM(_create)(_nfft, LIQUID_WINDOW_KAISER, _nfft/2, _nfft/4); } // copy object SPGRAM() SPGRAM(_copy)(SPGRAM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("spgram%s_copy(), object cannot be NULL", EXTENSION); // allocate memory for main object SPGRAM() q_copy = (SPGRAM()) malloc(sizeof(struct SPGRAM(_s))); // copy all internal memory memmove(q_copy, q_orig, sizeof(struct SPGRAM(_s))); // copy buffer and its contents q_copy->buffer = WINDOW(_copy)(q_orig->buffer); // create FFT arrays, object q_copy->buf_time = (TC*) FFT_MALLOC((q_copy->nfft)*sizeof(TC)); q_copy->buf_freq = (TC*) FFT_MALLOC((q_copy->nfft)*sizeof(TC)); q_copy->psd = (T *) malloc((q_copy->nfft)*sizeof(T )); q_copy->fft = FFT_CREATE_PLAN(q_copy->nfft, q_copy->buf_time, q_copy->buf_freq, FFT_DIR_FORWARD, FFT_METHOD); // reset the time buffer unsigned int i; for (i=0; infft; i++) q_copy->buf_time[i] = 0.0f; // copy accumulated PSD buffer memmove(q_copy->psd, q_orig->psd, q_copy->nfft*sizeof(T)); // copy tapering window q_copy->w = (T*) malloc((q_copy->window_len)*sizeof(T)); memmove(q_copy->w, q_orig->w, q_copy->window_len*sizeof(T)); // return copied object return q_copy; } // destroy spgram object int SPGRAM(_destroy)(SPGRAM() _q) { if (_q == NULL) return liquid_error(LIQUID_EIOBJ,"spgram%s_destroy(), invalid null pointer passed",EXTENSION); // free allocated memory FFT_FREE(_q->buf_time); FFT_FREE(_q->buf_freq); free(_q->w); free(_q->psd); WINDOW(_destroy)(_q->buffer); FFT_DESTROY_PLAN(_q->fft); // free main object free(_q); return LIQUID_OK; } // clears the internal state of the spgram object, but not // the internal buffer int SPGRAM(_clear)(SPGRAM() _q) { // clear FFT input unsigned int i; for (i=0; i<_q->nfft; i++) _q->buf_time[i] = 0.0f; // reset counters _q->sample_timer = _q->delay; _q->num_transforms = 0; _q->num_samples = 0; // clear PSD accumulation for (i=0; i<_q->nfft; i++) _q->psd[i] = 0.0f; return LIQUID_OK; } // reset the spgram object to its original state completely int SPGRAM(_reset)(SPGRAM() _q) { // reset spgram object except for the window buffer SPGRAM(_clear)(_q); // clear the window buffer WINDOW(_reset)(_q->buffer); // reset counters _q->num_samples_total = 0; _q->num_transforms_total = 0; return LIQUID_OK; } // prints the spgram object's parameters int SPGRAM(_print)(SPGRAM() _q) { printf("spgram%s: nfft=%u, window=%u, delay=%u\n", EXTENSION, _q->nfft, _q->window_len, _q->delay); return LIQUID_OK; } // set forgetting factor int SPGRAM(_set_alpha)(SPGRAM() _q, float _alpha) { // validate input if (_alpha != -1 && (_alpha < 0.0f || _alpha > 1.0f)) { liquid_error(LIQUID_EICONFIG,"spgram%s_set_alpha(), alpha must be in {-1,[0,1]}", EXTENSION); return -1; } // set accumulation flag appropriately _q->accumulate = (_alpha == -1.0f) ? 1 : 0; if (_q->accumulate) { _q->alpha = 1.0f; _q->gamma = 1.0f; } else { _q->alpha = _alpha; _q->gamma = 1.0f - _q->alpha; } return LIQUID_OK; } // set center freuqncy int SPGRAM(_set_freq)(SPGRAM() _q, float _freq) { _q->frequency = _freq; return LIQUID_OK; } // set sample rate int SPGRAM(_set_rate)(SPGRAM() _q, float _rate) { // validate input if (_rate <= 0.0f) return liquid_error(LIQUID_EICONFIG,"spgram%s_set_rate(), sample rate must be greater than zero", EXTENSION); _q->sample_rate = _rate; return LIQUID_OK; } // get FFT size unsigned int SPGRAM(_get_nfft)(SPGRAM() _q) { return _q->nfft; } // get window length unsigned int SPGRAM(_get_window_len)(SPGRAM() _q) { return _q->window_len; } // get delay between transforms unsigned int SPGRAM(_get_delay)(SPGRAM() _q) { return _q->delay; } // Get window type used for spectral estimation int SPGRAM(_get_wtype)(SPGRAM() _q) { return _q->wtype; } // get number of samples processed since reset unsigned long long int SPGRAM(_get_num_samples)(SPGRAM() _q) { return _q->num_samples; } // get number of samples processed since start unsigned long long int SPGRAM(_get_num_samples_total)(SPGRAM() _q) { return _q->num_samples_total; } // get number of transforms processed since reset unsigned long long int SPGRAM(_get_num_transforms)(SPGRAM() _q) { return _q->num_transforms; } // get number of transforms processed since start unsigned long long int SPGRAM(_get_num_transforms_total)(SPGRAM() _q) { return _q->num_transforms_total; } // get forgetting factor (filer bandwidth) float SPGRAM(_get_alpha)(SPGRAM() _q) { return _q->alpha; } // push a single sample into the spgram object // _q : spgram object // _x : input sample int SPGRAM(_push)(SPGRAM() _q, TI _x) { // push sample into internal window WINDOW(_push)(_q->buffer, _x); // update counters _q->num_samples++; _q->num_samples_total++; // adjust timer _q->sample_timer--; if (_q->sample_timer) return LIQUID_OK; // reset timer and step through computation _q->sample_timer = _q->delay; return SPGRAM(_step)(_q); } // write a block of samples to the spgram object // _q : spgram object // _x : input buffer [size: _n x 1] // _n : input buffer length int SPGRAM(_write)(SPGRAM() _q, TI * _x, unsigned int _n) { #if 0 // write a block of samples to the internal window WINDOW(_write)(_q->buffer, _x, _n); #else // TODO: be smarter about how to write and execute samples unsigned int i; for (i=0; i<_n; i++) SPGRAM(_push)(_q, _x[i]); #endif return LIQUID_OK; } // compute spectral periodogram output from current buffer contents // _q : spgram object int SPGRAM(_step)(SPGRAM() _q) { unsigned int i; // read buffer, copy to FFT input (applying window) // TODO: use SIMD extensions to speed this up TI * rc; WINDOW(_read)(_q->buffer, &rc); for (i=0; i<_q->window_len; i++) _q->buf_time[i] = rc[i] * _q->w[i]; // execute fft on _q->buf_time and store result in _q->buf_freq FFT_EXECUTE(_q->fft); // accumulate output // TODO: vectorize this operation for (i=0; i<_q->nfft; i++) { T v = crealf( _q->buf_freq[i] * conjf(_q->buf_freq[i]) ); if (_q->num_transforms == 0) _q->psd[i] = v; else _q->psd[i] = _q->gamma*_q->psd[i] + _q->alpha*v; } _q->num_transforms++; _q->num_transforms_total++; return LIQUID_OK; } // compute spectral periodogram output (fft-shifted values, linear) // from current buffer contents // _q : spgram object // _psd : output spectrum [size: _nfft x 1] int SPGRAM(_get_psd_mag)(SPGRAM() _q, T * _psd) { // compute magnitude (linear) and run FFT shift unsigned int i; unsigned int nfft_2 = _q->nfft / 2; T scale = _q->accumulate ? 1.0f / max(1,_q->num_transforms) : 0.0f; // TODO: adjust scale if infinite integration for (i=0; i<_q->nfft; i++) { unsigned int k = (i + nfft_2) % _q->nfft; _psd[i] = max(LIQUID_SPGRAM_PSD_MIN,_q->psd[k]) * scale; } return LIQUID_OK; } // compute spectral periodogram output (fft-shifted values // in dB) from current buffer contents // _q : spgram object // _psd : output spectrum [size: _nfft x 1] int SPGRAM(_get_psd)(SPGRAM() _q, T * _psd) { // compute magnitude, linear int rc = SPGRAM(_get_psd_mag)(_q, _psd); if (rc != LIQUID_OK) return rc; // convert to dB unsigned int i; for (i=0; i<_q->nfft; i++) _psd[i] = 10*log10f(_psd[i]); return LIQUID_OK; } // export gnuplot file // _q : spgram object // _filename : input buffer [size: _n x 1] int SPGRAM(_export_gnuplot)(SPGRAM() _q, const char * _filename) { FILE * fid = fopen(_filename,"w"); if (fid == NULL) return liquid_error(LIQUID_EIO,"spgram%s_export_gnuplot(), could not open '%s' for writing",EXTENSION,_filename); fprintf(fid,"# %s : auto-generated file\n", _filename); fprintf(fid,"reset\n"); fprintf(fid,"set terminal png size 1200,800 enhanced font 'Verdana,10'\n"); fprintf(fid,"set output '%s.png'\n", _filename); fprintf(fid,"set autoscale y\n"); fprintf(fid,"set ylabel 'Power Spectral Density'\n"); fprintf(fid,"set style line 12 lc rgb '#404040' lt 0 lw 1\n"); fprintf(fid,"set grid xtics ytics\n"); fprintf(fid,"set grid front ls 12\n"); //fprintf(fid,"set style fill transparent solid 0.2\n"); const char plot_with[] = "lines"; // "filledcurves x1" fprintf(fid,"set nokey\n"); if (_q->sample_rate < 0) { fprintf(fid,"set xrange [-0.5:0.5]\n"); fprintf(fid,"set xlabel 'Noramlized Frequency'\n"); fprintf(fid,"plot '-' w %s lt 1 lw 2 lc rgb '#004080'\n", plot_with); } else { char unit = ' '; float g = 1.0f; float f0 = fabsf( _q->frequency - _q->sample_rate/2.0f ); float f1 = fabsf( _q->frequency + _q->sample_rate/2.0f ); float fmax = f0 > f1 ? f0 : f1; liquid_get_scale(fmax, &unit, &g); fprintf(fid,"set xlabel 'Frequency [%cHz]'\n", unit); fprintf(fid,"set xrange [%f:%f]\n", g*(_q->frequency-0.5*_q->sample_rate), g*(_q->frequency+0.5*_q->sample_rate)); fprintf(fid,"plot '-' u ($1*%f+%f):2 w %s lt 1 lw 2 lc rgb '#004080'\n", g*(_q->sample_rate < 0 ? 1 : _q->sample_rate), g*_q->frequency, plot_with); } // export spectrum data T * psd = (T*) malloc(_q->nfft * sizeof(T)); SPGRAM(_get_psd)(_q, psd); unsigned int i; for (i=0; i<_q->nfft; i++) fprintf(fid," %12.8f %12.8f\n", (float)i/(float)(_q->nfft)-0.5f, (float)(psd[i])); free(psd); fprintf(fid,"e\n"); // close it up fclose(fid); return LIQUID_OK; } // // object-independent methods // // estimate spectrum on input signal // _nfft : FFT size // _x : input signal [size: _n x 1] // _n : input signal length // _psd : output spectrum, [size: _nfft x 1] int SPGRAM(_estimate_psd)(unsigned int _nfft, TI * _x, unsigned int _n, T * _psd) { // create object SPGRAM() q = SPGRAM(_create_default)(_nfft); // run spectral estimate on entire sequence SPGRAM(_write)(q, _x, _n); // force step if no transforms have been taken if (q->num_transforms == 0) SPGRAM(_step)(q); // get PSD estimate SPGRAM(_get_psd)(q, _psd); // destroy object SPGRAM(_destroy)(q); return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/src/spgramcf.c000066400000000000000000000040501474751757600177230ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // spectral periodogram API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION "cf" // name-mangling macros #define ASGRAM(name) LIQUID_CONCAT(asgramcf,name) #define SPGRAM(name) LIQUID_CONCAT(spgramcf,name) #define SPWATERFALL(name) LIQUID_CONCAT(spwaterfallcf,name) #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define FFT(name) LIQUID_CONCAT(fft,name) #define T float // primitive type (real) #define TC float complex // primitive type (complex) #define TI float complex // input type #define TI_COMPLEX 1 #define PRINTVAL_T(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_CFLOAT(X,F) // prototypes #include "asgram.proto.c" #include "spgram.proto.c" #include "spwaterfall.proto.c" liquid-dsp-1.7.0/src/fft/src/spgramf.c000066400000000000000000000040421474751757600175610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // spectral periodogram API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION "f" // name-mangling macros #define ASGRAM(name) LIQUID_CONCAT(asgramf,name) #define SPGRAM(name) LIQUID_CONCAT(spgramf,name) #define SPWATERFALL(name) LIQUID_CONCAT(spwaterfallf,name) #define WINDOW(name) LIQUID_CONCAT(windowf,name) #define FFT(name) LIQUID_CONCAT(fft,name) #define T float // primitive type (real) #define TC float complex // primitive type (complex) #define TI float // input type #define TI_COMPLEX 0 #define PRINTVAL_T(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_FLOAT(X,F) // prototypes #include "asgram.proto.c" #include "spgram.proto.c" #include "spwaterfall.proto.c" liquid-dsp-1.7.0/src/fft/src/spwaterfall.proto.c000066400000000000000000000446501474751757600216210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // spwaterfall (spectral periodogram waterfall) // #include #include #include #include #include #include #include "liquid.internal.h" struct SPWATERFALL(_s) { // options unsigned int nfft; // FFT length unsigned int time; // minimum time buffer SPGRAM() periodogram; // spectral periodogram object // buffers T * psd; // time/frequency buffer [nfft x 2*time] unsigned int index_time; // time index for writing to buffer unsigned int rollover; // number of FFTs to take before writing to output // parameters for display purposes only float frequency; // center frequency [Hz] float sample_rate; // sample rate [Hz] unsigned int width; // image width [pixels] unsigned int height; // image height [pixels] char * commands; // commands to execute directly before 'plot' }; // // internal methods // // compute spectral periodogram output (complex values) from internal periodogram object int SPWATERFALL(_step)(SPWATERFALL() _q); // consolidate buffer by taking log-average of two separate spectral estimates in time int SPWATERFALL(_consolidate_buffer)(SPWATERFALL() _q); // export files int SPWATERFALL(_export_bin)(SPWATERFALL() _q, const char * _base); int SPWATERFALL(_export_gnu)(SPWATERFALL() _q, const char * _base); // create spwaterfall object // _nfft : FFT size // _wtype : window type, e.g. LIQUID_WINDOW_HAMMING // _window_len : window length // _delay : delay between transforms, _delay > 0 SPWATERFALL() SPWATERFALL(_create)(unsigned int _nfft, int _wtype, unsigned int _window_len, unsigned int _delay, unsigned int _time) { // validate input if (_nfft < 2) return liquid_error_config("spwaterfall%s_create(), fft size must be at least 2", EXTENSION); if (_window_len > _nfft) return liquid_error_config("spwaterfall%s_create(), window size cannot exceed fft size", EXTENSION); if (_window_len == 0) return liquid_error_config("spwaterfall%s_create(), window size must be greater than zero", EXTENSION); if (_wtype == LIQUID_WINDOW_KBD && _window_len % 2) return liquid_error_config("spwaterfall%s_create(), KBD window length must be even", EXTENSION); if (_delay == 0) return liquid_error_config("spwaterfall%s_create(), delay must be greater than 0", EXTENSION); if (_time == 0) return liquid_error_config("spwaterfall%s_create(), time must be greater than 0", EXTENSION); // allocate memory for main object SPWATERFALL() q = (SPWATERFALL()) malloc(sizeof(struct SPWATERFALL(_s))); // set input parameters q->nfft = _nfft; q->time = _time; q->frequency = 0; q->sample_rate = -1; q->width = 800; q->height = 800; q->commands = NULL; // create buffer to hold aggregated power spectral density // NOTE: the buffer is two-dimensional time/frequency grid that is two times // 'nfft' and 'time' to account for log-average consolidation each time // the buffer gets filled q->psd = (T*) malloc( 2 * q->nfft * q->time * sizeof(T)); // create spectral periodogram object q->periodogram = SPGRAM(_create)(_nfft, _wtype, _window_len, _delay); // reset the object SPWATERFALL(_reset)(q); // return new object return q; } // create default spwaterfall object (Kaiser-Bessel window) SPWATERFALL() SPWATERFALL(_create_default)(unsigned int _nfft, unsigned int _time) { // validate input if (_nfft < 2) return liquid_error_config("spwaterfall%s_create_default(), fft size must be at least 2", EXTENSION); if (_time < 2) return liquid_error_config("spwaterfall%s_create_default(), fft size must be at least 2", EXTENSION); return SPWATERFALL(_create)(_nfft, LIQUID_WINDOW_KAISER, _nfft/2, _nfft/4, _time); } SPWATERFALL() SPWATERFALL(_copy)(SPWATERFALL() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("spwaterfall%s_copy(), object cannot be NULL", EXTENSION); // allocate memory for main object SPWATERFALL() q_copy = (SPWATERFALL()) malloc(sizeof(struct SPWATERFALL(_s))); // copy all memory and overwrite specific values memmove(q_copy, q_orig, sizeof(struct SPWATERFALL(_s))); // copy spectral periodogram object and internal state q_copy->periodogram = SPGRAM(_copy)(q_orig->periodogram); // create new buffer and copy values q_copy->psd = (T*) malloc( 2 * q_copy->nfft * q_copy->time * sizeof(T)); memmove(q_copy->psd, q_orig->psd, 2 * q_copy->nfft * q_copy->time * sizeof(T)); // set commands value q_copy->commands = NULL; SPWATERFALL(_set_commands)(q_copy, q_orig->commands); // return object return q_copy; } // destroy spwaterfall object int SPWATERFALL(_destroy)(SPWATERFALL() _q) { // free allocated memory free(_q->psd); free(_q->commands); // destroy internal spectral periodogram object SPGRAM(_destroy)(_q->periodogram); // free main object free(_q); return LIQUID_OK; } // clears the internal state of the spwaterfall object, but not // the internal buffer int SPWATERFALL(_clear)(SPWATERFALL() _q) { SPGRAM(_clear)(_q->periodogram); memset(_q->psd, 0x00, 2*_q->nfft*_q->time*sizeof(T)); _q->index_time = 0; return LIQUID_OK; } // reset the spwaterfall object to its original state completely int SPWATERFALL(_reset)(SPWATERFALL() _q) { SPWATERFALL(_clear)(_q); SPGRAM(_reset)(_q->periodogram); _q->rollover = 1; return LIQUID_OK; } // prints the spwaterfall object's parameters int SPWATERFALL(_print)(SPWATERFALL() _q) { printf("\n", EXTENSION, _q->nfft, _q->time); return LIQUID_OK; } // Get number of samples processed since object was created uint64_t SPWATERFALL(_get_num_samples_total)(SPWATERFALL() _q) { return SPGRAM(_get_num_samples_total)(_q->periodogram); } // Get FFT size (columns in PSD output) unsigned int SPWATERFALL(_get_num_freq)(SPWATERFALL() _q) { return _q->nfft; } // Get number of accumulated FFTs (rows in PSD output) unsigned int SPWATERFALL(_get_num_time)(SPWATERFALL() _q) { return _q->index_time; } // Get window length used in spectral estimation unsigned int SPWATERFALL(_get_window_len)(SPWATERFALL() _q) { return SPGRAM(_get_window_len)(_q->periodogram); } // Get delay between transforms used in spectral estimation unsigned int SPWATERFALL(_get_delay)(SPWATERFALL() _q) { return SPGRAM(_get_delay)(_q->periodogram); } // Get window type used in spectral estimation int SPWATERFALL(_get_wtype)(SPWATERFALL() _q) { return SPGRAM(_get_wtype)(_q->periodogram); } // Get power spectral density (PSD), size: nfft x time const float * SPWATERFALL(_get_psd)(SPWATERFALL() _q) { return (const T *) _q->psd; } // set center freuqncy int SPWATERFALL(_set_freq)(SPWATERFALL() _q, float _freq) { _q->frequency = _freq; return LIQUID_OK; } // set sample rate int SPWATERFALL(_set_rate)(SPWATERFALL() _q, float _rate) { // validate input if (_rate <= 0.0f) return liquid_error(LIQUID_EICONFIG,"spwaterfall%s_set_rate(), sample rate must be greater than zero", EXTENSION); _q->sample_rate = _rate; return LIQUID_OK; } // set image dimensions int SPWATERFALL(_set_dims)(SPWATERFALL() _q, unsigned int _width, unsigned int _height) { _q->width = _width; _q->height = _height; return LIQUID_OK; } // set image dimensions int SPWATERFALL(_set_commands)(SPWATERFALL() _q, const char * _commands) { // clear memory with NULL pointer if (_commands == NULL) { free(_q->commands); _q->commands = NULL; return LIQUID_OK; } // sanity check unsigned int n = strlen(_commands); if (n > 1<<14) { SPWATERFALL(_set_commands)(_q, "# error: input string size limit exceeded"); return liquid_error(LIQUID_EICONFIG,"spwaterfall%s_set_commands(), input string size exceeds reasonable limits",EXTENSION); } // reallocate memory, copy input, and return _q->commands = (char*) realloc(_q->commands, n+1); memmove(_q->commands, _commands, n); _q->commands[n] = '\0'; return LIQUID_OK; } // push a single sample into the spwaterfall object // _q : spwaterfall object // _x : input sample int SPWATERFALL(_push)(SPWATERFALL() _q, TI _x) { if (SPGRAM(_push)(_q->periodogram, _x)) return liquid_error(LIQUID_EINT,"spwaterfall%s_push(), could not push to internal spgram object",EXTENSION); if (SPWATERFALL(_step)(_q)) return liquid_error(LIQUID_EINT,"spwaterfall%s_push(), could not step internal state",EXTENSION); return LIQUID_OK; } // write a block of samples to the spwaterfall object // _q : spwaterfall object // _x : input buffer [size: _n x 1] // _n : input buffer length int SPWATERFALL(_write)(SPWATERFALL() _q, TI * _x, unsigned int _n) { // TODO: be smarter about how to write and execute samples unsigned int i; for (i=0; i<_n; i++) SPWATERFALL(_push)(_q, _x[i]); return LIQUID_OK; } // export output files // _q : spwaterfall object // _base : base filename int SPWATERFALL(_export)(SPWATERFALL() _q, const char * _base) { if (SPWATERFALL(_export_bin)(_q, _base)) return liquid_error(LIQUID_EIO,"spwaterfall%s_export(), could not export binary file to '%s.bin'",EXTENSION,_base); if (SPWATERFALL(_export_gnu)(_q, _base)) return liquid_error(LIQUID_EIO,"spwaterfall%s_export(), could not export gnuplot file to '%s.gnu'",EXTENSION,_base); return LIQUID_OK; } // compute spectral periodogram output from current buffer contents // _q : spwaterfall object int SPWATERFALL(_step)(SPWATERFALL() _q) { // determine if we need to extract PSD estimate from periodogram if (SPGRAM(_get_num_transforms)(_q->periodogram) >= _q->rollover) { //printf("index : %u\n", _q->index_time); // get PSD estimate from periodogram object, placing result in // proper location in internal buffer SPGRAM(_get_psd)(_q->periodogram, _q->psd + _q->nfft*_q->index_time); // soft reset of internal state, counters SPGRAM(_clear)(_q->periodogram); // increment buffer counter _q->index_time++; // determine if buffer is full and we need to consolidate buffer if (_q->index_time == 2*_q->time) SPWATERFALL(_consolidate_buffer)(_q); } return LIQUID_OK; } // consolidate buffer by taking log-average of two separate spectral estimates in time // _q : spwaterfall object int SPWATERFALL(_consolidate_buffer)(SPWATERFALL() _q) { // assert(_q->index_time == 2*_q->time); //printf("consolidating... (rollover = %10u, total samples : %16llu, index : %u)\n", // _q->rollover, SPGRAM(_get_num_samples_total)(_q->periodogram), _q->index_time); unsigned int i; // time index unsigned int k; // freq index for (i=0; i<_q->time; i++) { for (k=0; k<_q->nfft; k++) { // convert to linear, compute average, convert back to log T v0 = powf(10.0f, _q->psd[ (2*i + 0)*_q->nfft + k ]*0.1f); T v1 = powf(10.0f, _q->psd[ (2*i + 1)*_q->nfft + k ]*0.1f); // save result _q->psd[ i*_q->nfft + k ] = 10.0f*log10f(0.5f*(v0+v1)); } } // update time index _q->index_time = _q->time; // update rollover counter _q->rollover *= 2; return LIQUID_OK; } // export gnuplot file // _q : spwaterfall object // _filename : input buffer [size: _n x 1] int SPWATERFALL(_export_bin)(SPWATERFALL() _q, const char * _base) { // add '.bin' extension to base int n = strlen(_base); char filename[n+5]; sprintf(filename,"%s.bin", _base); // open output file for writing FILE * fid = fopen(filename,"w"); if (fid == NULL) { liquid_error(LIQUID_EICONFIG,"spwaterfall%s_export_bin(), could not open '%s' for writing", EXTENSION, filename); return -1; } unsigned int i; // write header float nfftf = (float)(_q->nfft); fwrite(&nfftf, sizeof(float), 1, fid); for (i=0; i<_q->nfft; i++) { float f = (float)i/nfftf - 0.5f; fwrite(&f, sizeof(float), 1, fid); } // write output spectral estimate // TODO: force conversion from type 'T' to type 'float' uint64_t total_samples = SPGRAM(_get_num_samples_total)(_q->periodogram); for (i=0; i<_q->index_time; i++) { float n = (float)i / (float)(_q->index_time) * (float)total_samples; fwrite(&n, sizeof(float), 1, fid); fwrite(&_q->psd[i*_q->nfft], sizeof(float), _q->nfft, fid); } // close it up fclose(fid); //printf("results written to %s\n", filename); return LIQUID_OK; } // export gnuplot file // _q : spwaterfall object // _filename : input buffer [size: _n x 1] int SPWATERFALL(_export_gnu)(SPWATERFALL() _q, const char * _base) { // add '.bin' extension to base int n = strlen(_base); char filename[n+5]; sprintf(filename,"%s.gnu", _base); // open output file for writing FILE * fid = fopen(filename,"w"); if (fid == NULL) return liquid_error(LIQUID_EICONFIG,"spwaterfall%s_export_gnu(), could not open '%s' for writing",EXTENSION,filename); // scale to thousands, millions, billions (etc.) automatically uint64_t total_samples = SPGRAM(_get_num_samples_total)(_q->periodogram); char units = ' '; float scale = 1.0f; liquid_get_scale((float)total_samples/4, &units, &scale); fprintf(fid,"#!/usr/bin/gnuplot\n"); fprintf(fid,"reset\n"); fprintf(fid,"set terminal png size %u,%u enhanced font 'Verdana,10'\n", _q->width, _q->height); fprintf(fid,"set output '%s.png'\n", _base); fprintf(fid,"unset key\n"); fprintf(fid,"set style line 11 lc rgb '#808080' lt 1\n"); fprintf(fid,"set border 3 front ls 11\n"); fprintf(fid,"set style line 12 lc rgb '#888888' lt 0 lw 1\n"); fprintf(fid,"set grid front ls 12\n"); fprintf(fid,"set tics nomirror out scale 0.75\n"); fprintf(fid,"set yrange [0:%f]\n", (float)(total_samples-1)*scale); fprintf(fid,"set ylabel 'Sample Index'\n"); fprintf(fid,"set format y '%%.0f %c'\n", units); fprintf(fid,"# disable colorbar tics\n"); fprintf(fid,"set cbtics scale 0\n"); fprintf(fid,"set palette negative defined ( \\\n"); fprintf(fid," 0 '#D53E4F',\\\n"); fprintf(fid," 1 '#F46D43',\\\n"); fprintf(fid," 2 '#FDAE61',\\\n"); fprintf(fid," 3 '#FEE08B',\\\n"); fprintf(fid," 4 '#E6F598',\\\n"); fprintf(fid," 5 '#ABDDA4',\\\n"); fprintf(fid," 6 '#66C2A5',\\\n"); fprintf(fid," 7 '#3288BD' )\n"); fprintf(fid,"\n"); if (_q->sample_rate < 0) { fprintf(fid,"set xrange [-0.5:0.5]\n"); float xtics = 0.1f; fprintf(fid,"set xtics %f\n", xtics); fprintf(fid,"set xlabel 'Normalized Frequency [f/F_s]'\n"); if (_q->commands != NULL) fprintf(fid,"%s\n", _q->commands); fprintf(fid,"plot '%s.bin' u 1:($2*%e):3 binary matrix with image\n", _base, scale); } else { char unit; float g = 1.0f; float f_hi = _q->frequency + 0.5f*_q->sample_rate; // highest frequency liquid_get_scale(f_hi/2, &unit, &g); fprintf(fid,"set xlabel 'Frequency [%cHz]'\n", unit); // target xtics spacing roughly every 60-80 pixels float xn = ((float) _q->width * 0.8f) / 70.0f; // rough number of tics //float xs = _q->sample_rate * g / xn; // normalized spacing float xt = 1.0f; // round to nearest 1, 2, 5, or 10 // potential xtic spacings float spacing[] = {0.01,0.02,0.05,0.1,0.2,0.5,1.0,2.0,5.0,10.0,20.0,50.0,100.0,200.0,500.0,-1.0f}; unsigned int i=0; while (spacing[i] > 0) { if (_q->sample_rate*g/spacing[i] < 1.2f*xn) { xt = spacing[i]; break; } i++; } //printf("xn:%f, xs:%f, xt:%f\n", xn, xs, xt); fprintf(fid,"set xrange [%f:%f]\n", g*(_q->frequency-0.5*_q->sample_rate), g*(_q->frequency+0.5*_q->sample_rate)); fprintf(fid,"set xtics %f\n", xt); if (_q->commands != NULL) fprintf(fid,"%s\n", _q->commands); fprintf(fid,"plot '%s.bin' u ($1*%f+%f):($2*%e):3 binary matrix with image\n", _base, g*(_q->sample_rate < 0 ? 1 : _q->sample_rate), g*_q->frequency, scale); } fclose(fid); // close it up #if 0 printf("results written to %s\n", filename); printf("index time : %u\n", _q->index_time); printf("rollover : %u\n", _q->rollover); printf("total transforms : %llu\n", SPGRAM(_get_num_transforms_total)(_q->periodogram)); #endif return LIQUID_OK; } liquid-dsp-1.7.0/src/fft/tests/000077500000000000000000000000001474751757600163315ustar00rootroot00000000000000liquid-dsp-1.7.0/src/fft/tests/asgram_autotest.c000066400000000000000000000050461474751757600217040ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // test ASCII spectral periodogram (asgram) objects #include #include "autotest/autotest.h" #include "liquid.internal.h" // check copy method void autotest_asgramcf_copy() { // options unsigned int nfft = 70; // transform size unsigned int num_samples = 844; float nstd = 0.1f; // create object asgramcf q0 = asgramcf_create(nfft); // set parameters asgramcf_set_scale (q0, -20.8f, 3.1f); asgramcf_set_display(q0, "abcdeFGHIJ"); // generate a bunch of random noise samples unsigned int i; for (i=0; i float complex fft_test_x10[] = { -0.380648737020 + 1.003981780953*_Complex_I, 1.031511152163 + -2.625896014009*_Complex_I, -1.083239396623 + 1.646877001105*_Complex_I, 0.951587457487 + -0.004983138281*_Complex_I, 0.407589360084 + 0.345698641918*_Complex_I, 0.549291472049 + 0.542579734652*_Complex_I, -0.911825526748 + 1.282009726257*_Complex_I, -0.617849040964 + 0.696673367751*_Complex_I, 1.097501043733 + 1.373947311009*_Complex_I, 0.848713422957 + -0.738252787172*_Complex_I}; float complex fft_test_y10[] = { 1.892631207117 + 3.522635624182*_Complex_I, -1.167216826866 + -3.158947047615*_Complex_I, -0.019614668329 + 1.291770408491*_Complex_I, -3.842057814631 + -1.668342848977*_Complex_I, -2.323082893679 + 1.200058008683*_Complex_I, -3.633877720265 + 7.782393298301*_Complex_I, 0.649048218143 + 6.997144832999*_Complex_I, 1.025423884758 + 1.907666229150*_Complex_I, 0.644231811894 + -5.278801296330*_Complex_I, 2.968027431661 + -2.555759399357*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_120.c000066400000000000000000000317321474751757600215460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 120-point transform // #include float complex fft_test_x120[] = { -2.933561116248 + 0.585802030432*_Complex_I, 0.996149474765 + -0.621353657548*_Complex_I, -0.262138535383 + 0.974643272654*_Complex_I, -1.483709823026 + -1.654326811798*_Complex_I, 0.009105914718 + -0.801453728867*_Complex_I, 1.480357059658 + -0.231135073122*_Complex_I, -0.580765210290 + 1.288460832776*_Complex_I, 0.485467815383 + 0.439565460988*_Complex_I, -1.010673740947 + -0.691639979516*_Complex_I, -0.525003222625 + -0.639606200048*_Complex_I, -0.806916915589 + 0.103762356730*_Complex_I, -0.399336315292 + 0.323161793208*_Complex_I, 0.111455618955 + 0.487552495249*_Complex_I, 0.523592233718 + 0.565527718910*_Complex_I, -0.181781072708 + 0.927375893986*_Complex_I, -0.427811932504 + -1.730760015952*_Complex_I, 0.722234655868 + -0.528518032448*_Complex_I, 0.327894303730 + 1.078490369290*_Complex_I, -0.365985637484 + -0.829110156759*_Complex_I, -1.230443935235 + 1.168892009209*_Complex_I, -0.497547601907 + -1.884812736460*_Complex_I, -0.188693666275 + -0.388189056130*_Complex_I, 1.581490442848 + -0.773206675201*_Complex_I, -0.276904037052 + -1.607191981281*_Complex_I, 0.869586527848 + 2.279865113156*_Complex_I, 2.280976663440 + -0.491932963519*_Complex_I, -0.972146414270 + 1.317390598922*_Complex_I, 0.752226877706 + 0.307325301979*_Complex_I, -2.176688443840 + -0.178238348418*_Complex_I, 0.603808804599 + -1.024869177311*_Complex_I, 1.637709885855 + 1.283852424020*_Complex_I, 0.766867282671 + -2.390532794299*_Complex_I, -0.803164170514 + -0.738964307326*_Complex_I, -0.217928168834 + -1.591138647698*_Complex_I, 0.044558930462 + -0.585819999208*_Complex_I, 0.185461763498 + 0.190876001378*_Complex_I, -0.887233966458 + 0.932582089649*_Complex_I, -1.388038826042 + 0.114934886174*_Complex_I, 0.079732100731 + 0.150414346304*_Complex_I, 1.215962906658 + 0.864185821675*_Complex_I, -0.889642609373 + -0.510424427491*_Complex_I, 0.243053087540 + -1.438563895787*_Complex_I, -0.409793881375 + 0.157176601902*_Complex_I, -1.193700035506 + -0.866457731187*_Complex_I, 1.192127022305 + -0.584612994505*_Complex_I, -0.387515835212 + 1.536461365714*_Complex_I, -0.853256362306 + -0.633564682282*_Complex_I, -0.152836605296 + -0.219510310627*_Complex_I, -1.151934152005 + 0.171485405414*_Complex_I, -0.010116218440 + 0.914918482762*_Complex_I, -1.686537878154 + 0.779331814618*_Complex_I, 0.673793112643 + 0.566118503412*_Complex_I, -0.143701669515 + -0.556780150872*_Complex_I, -0.845847069767 + 0.686668013963*_Complex_I, -1.147722980640 + -0.455850082513*_Complex_I, 1.310965019946 + -0.268939336441*_Complex_I, 0.641191445468 + 0.065635531845*_Complex_I, 0.790297755545 + 0.898978586598*_Complex_I, -1.539239983789 + 1.569958337837*_Complex_I, -1.042534751831 + -1.615908992141*_Complex_I, 0.848219334777 + 1.570278962754*_Complex_I, 0.768312422101 + 1.168572048009*_Complex_I, -0.119617114473 + 0.018922768020*_Complex_I, 0.463083556040 + -0.289189219121*_Complex_I, -2.334868450076 + 0.543186130761*_Complex_I, -0.859810016516 + -0.073915244925*_Complex_I, -0.986571365561 + 0.653098182477*_Complex_I, 0.522451913274 + -0.042046367028*_Complex_I, 0.106640796179 + -0.069187996590*_Complex_I, 1.052892113567 + 0.678469397559*_Complex_I, -0.698384198090 + 0.402405190110*_Complex_I, -0.274412699197 + 0.194991340203*_Complex_I, 0.154775651261 + -1.748234046267*_Complex_I, -0.373611252309 + 0.759957440236*_Complex_I, 0.307971942775 + 0.177025819034*_Complex_I, 1.127535219986 + -0.133866569607*_Complex_I, -0.780872981180 + -1.914809677751*_Complex_I, 0.097809503845 + -0.311527508403*_Complex_I, -1.338663250568 + -0.272131094279*_Complex_I, -1.774506466862 + 0.189947566984*_Complex_I, -0.108910232947 + -1.104077803690*_Complex_I, 0.700684038217 + 0.489503255191*_Complex_I, 1.723390943656 + -0.653061888020*_Complex_I, -0.307392508631 + -0.487335518704*_Complex_I, -1.351222246370 + -0.276340698500*_Complex_I, 0.554657638847 + 1.969266502927*_Complex_I, -0.693153982211 + -0.117977636798*_Complex_I, -0.639852935555 + 0.539350932011*_Complex_I, 0.774200449083 + 1.123041486424*_Complex_I, -2.046058231062 + -0.457644959516*_Complex_I, -1.606346330196 + -1.560038496690*_Complex_I, -1.701087998893 + 1.670050065045*_Complex_I, 0.443897868781 + 0.379995716985*_Complex_I, 0.193958078518 + 0.643773547931*_Complex_I, -1.527640156621 + 1.266495146511*_Complex_I, 0.259186234049 + -0.465035554366*_Complex_I, -0.385562205417 + -1.015469771575*_Complex_I, -1.871226440588 + 0.185126256408*_Complex_I, 0.542445571049 + -0.431681611434*_Complex_I, 0.214440313475 + -0.338588753334*_Complex_I, 0.163385540462 + -0.222892296796*_Complex_I, 0.477872198487 + -0.578917341564*_Complex_I, -1.258436301493 + -0.335313659938*_Complex_I, 0.310183724816 + -1.538340991002*_Complex_I, 0.315711034668 + 0.372755872975*_Complex_I, -0.832316134028 + 0.846715050479*_Complex_I, 1.810572502100 + -0.747188365112*_Complex_I, -1.238997433684 + 2.921109879602*_Complex_I, -1.359334420871 + 1.137914515456*_Complex_I, -1.735544412609 + 0.353972290274*_Complex_I, -1.967071931759 + 1.720943408177*_Complex_I, 0.175659653421 + 0.673882179212*_Complex_I, 0.566435305275 + 1.086122584518*_Complex_I, -0.685557294027 + 0.440265086848*_Complex_I, 1.232868086689 + -0.376035944159*_Complex_I, 0.031017508722 + -1.091694970471*_Complex_I, 0.153454665192 + -0.387812357268*_Complex_I, 0.055087132749 + 0.121934454858*_Complex_I, -1.641857455950 + -0.680302798653*_Complex_I, -0.235668947578 + -0.276093078030*_Complex_I}; float complex fft_test_y120[] = { -26.130540532441 + 2.500301372380*_Complex_I, -8.384737785882 + -11.493299680300*_Complex_I, -10.815843993705 + 1.373214442809*_Complex_I, -3.468316057471 + -0.197988490875*_Complex_I, -8.468015203881 + 4.172305025792*_Complex_I, -6.972140924378 + -19.059978062591*_Complex_I, 12.894909733921 + -14.674650174719*_Complex_I, 6.217174828182 + -4.198857679111*_Complex_I, -3.038713671007 + 11.416582830167*_Complex_I, -5.889009032363 + 2.623087027225*_Complex_I, 4.415856321129 + 20.520368038723*_Complex_I, -7.596161829888 + -9.011449139900*_Complex_I, -22.967094572900 + -14.281559182333*_Complex_I, -13.103802451651 + 2.098170225144*_Complex_I, -5.815320588822 + 10.518428726478*_Complex_I, -1.290859552698 + -5.007381379220*_Complex_I, 10.503332312095 + -13.128075179264*_Complex_I, -0.995307687739 + 6.404055459139*_Complex_I, -7.098602985708 + 2.406450947955*_Complex_I, -5.425368507411 + 31.439384831310*_Complex_I, -4.531419053887 + -0.173481154479*_Complex_I, 9.402659099609 + 3.570607998710*_Complex_I, 10.130149004652 + -16.694138931142*_Complex_I, -2.197851988961 + 2.938436935104*_Complex_I, 5.864606545918 + -13.199247801155*_Complex_I, 12.427931476763 + -14.442851189707*_Complex_I, -0.346878049148 + -2.649522091233*_Complex_I, -6.110432016865 + 10.576069646496*_Complex_I, 29.337845632961 + -5.226538341924*_Complex_I, -5.530434871933 + -6.791491806236*_Complex_I, 12.511893544960 + -9.883054566598*_Complex_I, -13.522823191342 + 3.402811573476*_Complex_I, -6.949602446599 + -2.976747287959*_Complex_I, -13.604769865716 + -21.208579208314*_Complex_I, -2.667739313157 + 7.095560898932*_Complex_I, -4.030948890524 + -4.275911410965*_Complex_I, -1.538455879764 + 0.859913764271*_Complex_I, -1.597640929072 + 9.198642244462*_Complex_I, 3.258927941252 + 3.681214115496*_Complex_I, -27.177542272720 + -9.835919044876*_Complex_I, 2.137018426012 + 5.951425737520*_Complex_I, -9.328564597213 + -8.189268926052*_Complex_I, -15.202874868646 + -10.830493804699*_Complex_I, -14.141307626573 + 6.069950543455*_Complex_I, 23.789715337183 + -0.149207303988*_Complex_I, 1.018819274801 + 23.160092205105*_Complex_I, 0.160728240887 + 25.021802134125*_Complex_I, -27.292399750004 + -12.724069599967*_Complex_I, -11.090997281400 + 7.909805227447*_Complex_I, -12.632686116172 + 4.297788877667*_Complex_I, -10.947166654332 + -7.342984066688*_Complex_I, -12.526588806117 + 6.326089996957*_Complex_I, 7.848075855545 + 5.822833656652*_Complex_I, 4.463550473312 + -2.355918199764*_Complex_I, -3.359730942688 + -1.811340237346*_Complex_I, -16.045827623056 + -11.927425635813*_Complex_I, -17.191945449780 + 14.640840260710*_Complex_I, 5.723503979540 + -3.333396073843*_Complex_I, -7.212762063453 + -0.426026153122*_Complex_I, -8.371988589537 + -1.588815189476*_Complex_I, -16.721024926709 + 1.223543596227*_Complex_I, 21.500278405653 + 15.014414278563*_Complex_I, -12.998260008435 + 6.823922119636*_Complex_I, -11.969924059222 + -6.475357643023*_Complex_I, -3.880671177744 + 23.295158190426*_Complex_I, -1.615932730740 + 9.161241055173*_Complex_I, 6.743423357908 + 4.077889764270*_Complex_I, -8.491295100234 + -14.590167909493*_Complex_I, -4.050564794383 + -0.332576254078*_Complex_I, -7.563666582981 + -0.491929778422*_Complex_I, 5.325292014900 + 13.120067752469*_Complex_I, 17.266746589948 + -1.749739091662*_Complex_I, 9.016685746645 + -6.656805505959*_Complex_I, -8.457355300299 + -4.003222916857*_Complex_I, -31.407914776214 + -9.344158206903*_Complex_I, -8.003020240767 + -1.945349879704*_Complex_I, 10.679124047221 + 1.579265510278*_Complex_I, 7.576096581517 + -20.019004345583*_Complex_I, 5.425463900123 + -6.332000571240*_Complex_I, -11.713907656105 + 7.443366839954*_Complex_I, -0.593664650946 + 6.790006366701*_Complex_I, 10.381068180108 + -7.397393197217*_Complex_I, 0.455908842424 + 7.373964657268*_Complex_I, -8.378432107508 + 18.256672106713*_Complex_I, -24.128536613056 + 5.444870431684*_Complex_I, 8.421822254234 + -9.806814459804*_Complex_I, 7.173520639058 + 9.565811687718*_Complex_I, -6.236143277340 + 6.409295846945*_Complex_I, -5.379127157610 + -7.097598602556*_Complex_I, 0.992816214134 + 1.184456111668*_Complex_I, -8.630312793127 + -3.752996076907*_Complex_I, -0.458097520531 + 10.469419461305*_Complex_I, 3.184993888854 + 4.049136044816*_Complex_I, 2.080876935294 + -9.778155908324*_Complex_I, -12.941818037027 + 3.242798433849*_Complex_I, -6.524522778987 + 2.497157598131*_Complex_I, 3.225741204857 + 15.546794796319*_Complex_I, -6.079247610512 + -13.728424650306*_Complex_I, -4.960232908834 + 10.931039387444*_Complex_I, -2.558877649510 + 10.755632383919*_Complex_I, -19.611477019565 + 5.785472297267*_Complex_I, 21.866745387027 + -15.392995894737*_Complex_I, 16.349317592240 + 12.469152896354*_Complex_I, -9.294214354347 + 3.922833779556*_Complex_I, 13.879970160908 + 7.328114738105*_Complex_I, 2.651592361533 + -7.170628973597*_Complex_I, -5.253905486354 + 2.891157258399*_Complex_I, -8.491348558042 + 11.767371163610*_Complex_I, -0.986424222839 + 12.293687558243*_Complex_I, -16.973656701850 + -4.692292471582*_Complex_I, -10.242186370330 + 14.766563852584*_Complex_I, -5.961461862786 + 15.202716060356*_Complex_I, -8.983395642462 + -16.343883875645*_Complex_I, -10.094160152160 + -8.605909997569*_Complex_I, -2.538579712014 + -14.632787859230*_Complex_I, 10.260131998695 + -4.124613468367*_Complex_I, 5.155214364436 + -0.647489300204*_Complex_I, -7.821333192327 + -15.606994193249*_Complex_I, 4.093578304649 + 15.462757600992*_Complex_I, 4.765467299654 + 7.963215307045*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_130.c000066400000000000000000000337021474751757600215460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 130-point transform // #include float complex fft_test_x130[] = { 2.295593731681 + 0.411874155977*_Complex_I, 0.867233010936 + 2.391238924231*_Complex_I, -0.979511815183 + 0.113140414722*_Complex_I, 0.077578424280 + 1.186610948031*_Complex_I, -1.071528198235 + 0.804300526324*_Complex_I, 2.564018851452 + -0.310561947705*_Complex_I, -0.950972074792 + 0.436022224496*_Complex_I, 0.329631038192 + -0.396044027241*_Complex_I, -0.862183775613 + 0.927159525327*_Complex_I, -1.059508389407 + 0.941689902943*_Complex_I, 0.561615143764 + 0.096377911775*_Complex_I, 0.534738747717 + 0.825200677825*_Complex_I, 0.532672479322 + -1.976151133815*_Complex_I, -1.310581230339 + 0.002609415320*_Complex_I, -0.093941505596 + 0.905920914198*_Complex_I, 0.925525275182 + 1.564605784264*_Complex_I, -0.117943104365 + -0.166904851246*_Complex_I, -0.009619069574 + 1.676338431134*_Complex_I, -1.367286699092 + 1.175301759986*_Complex_I, -0.053699588910 + 1.515076774609*_Complex_I, -0.070846548150 + -1.323601968188*_Complex_I, 1.796443691981 + -2.011926920619*_Complex_I, 0.493444077774 + -0.231926417128*_Complex_I, 0.426102034457 + -0.966613330823*_Complex_I, -0.403283890205 + 0.570936153832*_Complex_I, 0.339532677572 + -2.038175992612*_Complex_I, 0.202689295315 + 0.573201095278*_Complex_I, -0.571885221166 + -1.275661165797*_Complex_I, -0.794196427625 + 0.423266616492*_Complex_I, -1.259472882356 + 0.532748103823*_Complex_I, 0.578465509624 + 0.826666605971*_Complex_I, -0.185287664847 + 1.746937914937*_Complex_I, 0.763423434636 + 2.020182432630*_Complex_I, 0.086623435989 + 0.431914895390*_Complex_I, 1.507900753669 + 0.056290417021*_Complex_I, -0.032809671097 + 0.098620827398*_Complex_I, 1.816125083125 + 0.081663531528*_Complex_I, 0.214492964742 + -0.162240129055*_Complex_I, 0.189647728207 + -1.547086817248*_Complex_I, -0.273499165641 + -0.552833918252*_Complex_I, 0.118280846537 + 2.716796709548*_Complex_I, 0.771040737403 + 2.763544783033*_Complex_I, -1.225097272428 + 0.386568340878*_Complex_I, -0.106529445935 + 2.317399662638*_Complex_I, -0.309752877128 + 0.781864233638*_Complex_I, -0.382242026751 + 0.530778535695*_Complex_I, 2.187686178145 + -1.629696212455*_Complex_I, -0.796121964339 + 1.212447992147*_Complex_I, 0.483902967137 + -1.761611437465*_Complex_I, 0.078193155045 + -0.695682313346*_Complex_I, -0.586826944592 + 0.119088984700*_Complex_I, 0.105215960567 + 1.605824117591*_Complex_I, -1.096678506319 + 0.626271388642*_Complex_I, -1.393844336696 + 0.006228875154*_Complex_I, -0.563177155438 + -0.137367111477*_Complex_I, 0.009064659930 + 0.774248879600*_Complex_I, 0.116957909967 + -0.374512247987*_Complex_I, 0.139602276134 + 1.196173350261*_Complex_I, 2.212769662630 + 0.374920897734*_Complex_I, 0.016527615895 + 0.361537040940*_Complex_I, -0.121813458827 + -1.829691824294*_Complex_I, -1.177075906748 + 0.142539646960*_Complex_I, 0.036310389827 + 1.045967306206*_Complex_I, -0.065389592517 + -1.807892452763*_Complex_I, -1.387880762495 + 0.171082957785*_Complex_I, -0.561065052343 + -1.260326041796*_Complex_I, 0.640813649741 + -1.777293190718*_Complex_I, -0.854417690416 + 2.237007530372*_Complex_I, -0.547722791713 + -2.330803396241*_Complex_I, 0.241170879004 + -0.617927403601*_Complex_I, 1.149285559687 + -0.376338314437*_Complex_I, -0.611492918690 + 2.047469301403*_Complex_I, 1.187263678013 + -0.165876393098*_Complex_I, 0.165257041186 + 1.672015729392*_Complex_I, -0.994770290926 + -0.351786586669*_Complex_I, -0.899279932248 + 0.810204064241*_Complex_I, -0.989604008277 + -0.119746717438*_Complex_I, -0.645537324969 + 0.353174690969*_Complex_I, -0.170329112065 + 0.085003743875*_Complex_I, -0.622581542228 + 0.035852829902*_Complex_I, 1.027721243658 + -1.009164344833*_Complex_I, -0.512899325586 + 1.422707083000*_Complex_I, -1.537474288640 + 0.734758277184*_Complex_I, 0.300068603056 + -0.844600037520*_Complex_I, 1.173177814994 + 0.474849978182*_Complex_I, 1.994390672833 + 0.274156356539*_Complex_I, -0.395247012804 + 1.046793121497*_Complex_I, 0.111209493599 + -1.063639370387*_Complex_I, 0.804028185695 + -2.330860293474*_Complex_I, -0.790484315366 + -2.043033932357*_Complex_I, -1.938436910347 + 0.005399210558*_Complex_I, -2.213763088095 + -0.050657389028*_Complex_I, -1.085606481444 + -1.672620738363*_Complex_I, 0.114374573479 + -0.314566566070*_Complex_I, -0.334479316133 + -0.269357185023*_Complex_I, -0.405597270856 + -1.024425491739*_Complex_I, -0.268446228006 + 0.625273024277*_Complex_I, 0.114305720338 + 0.091667406850*_Complex_I, 0.458271491171 + 0.893733272049*_Complex_I, 2.164470970876 + -0.008479990723*_Complex_I, 2.534318741148 + -0.513177256373*_Complex_I, 1.349837294176 + 0.730739449071*_Complex_I, 0.178600395004 + 0.598903569881*_Complex_I, 0.999820793703 + 0.023280883440*_Complex_I, 2.567157231145 + 2.857783095653*_Complex_I, 1.121937084722 + -0.127318755949*_Complex_I, -1.476481512156 + 0.438739152692*_Complex_I, 0.102675413849 + -1.072173994008*_Complex_I, 1.753108769750 + -1.363923993462*_Complex_I, -0.329713403173 + -0.836197629494*_Complex_I, 0.053237332369 + -0.316007225300*_Complex_I, 1.094272758407 + 0.154099319830*_Complex_I, 1.120647617053 + 2.290453172159*_Complex_I, -0.909112485707 + -0.663394681024*_Complex_I, 0.427832898254 + 0.948020241699*_Complex_I, 0.346684378724 + 1.412486035318*_Complex_I, -0.142628142360 + 0.034555947923*_Complex_I, 0.329645857287 + 2.194959848150*_Complex_I, -0.914476449793 + 0.031998423787*_Complex_I, 3.135765246395 + -1.497430797101*_Complex_I, 1.209028626447 + -0.686517697463*_Complex_I, 0.379503693068 + -0.842990842120*_Complex_I, -0.660923599405 + -0.501650971018*_Complex_I, 0.299565764767 + 1.443185673085*_Complex_I, -0.436332705510 + -0.166601489288*_Complex_I, 0.671417018091 + 1.996886835639*_Complex_I, -0.357759632151 + -0.399361979644*_Complex_I, 1.113330373199 + -0.350135780628*_Complex_I, -0.281958991560 + -0.356378430727*_Complex_I, 1.134108928078 + -2.092860871008*_Complex_I}; float complex fft_test_y130[] = { 14.378246546427 + 16.821529859589*_Complex_I, 27.857066272618 + 13.571899136472*_Complex_I, -15.456704775735 + 12.690273582209*_Complex_I, -8.753035425840 + 7.321557750269*_Complex_I, 28.113754727138 + -12.547913966687*_Complex_I, 10.563681172036 + 7.127854603059*_Complex_I, -6.710153682806 + 1.534074734434*_Complex_I, -0.152583781138 + 1.608751427720*_Complex_I, 9.516727413961 + -11.938945268968*_Complex_I, 11.591596283751 + 29.464218232945*_Complex_I, -1.861083239337 + 0.048807386609*_Complex_I, 13.530879033363 + -18.257581820108*_Complex_I, -11.904116745072 + -21.233551918127*_Complex_I, 25.195023350250 + -2.967265398356*_Complex_I, 11.563020359283 + -8.938209578954*_Complex_I, -2.212982769038 + 20.141015933481*_Complex_I, 9.560556874374 + 25.805352474019*_Complex_I, 9.352588131212 + -7.076490204727*_Complex_I, 19.915109002940 + 6.825454682895*_Complex_I, 9.736225779794 + -4.099017628979*_Complex_I, 10.036798782148 + 4.863204800610*_Complex_I, -5.027402703494 + 4.645951171953*_Complex_I, 0.722099014183 + 4.901713974497*_Complex_I, 12.341913244180 + 4.734214019087*_Complex_I, 6.490076890583 + -14.694265064166*_Complex_I, 18.468325287177 + -3.754877637942*_Complex_I, 30.687354000703 + 1.981540291860*_Complex_I, -17.305129028905 + 1.869860221279*_Complex_I, 3.696020771673 + -4.871064988434*_Complex_I, 15.580947342376 + 22.519564496626*_Complex_I, 3.848144651945 + -1.781612409800*_Complex_I, 8.942942784269 + -3.602301409947*_Complex_I, -7.765663555408 + -0.625063385554*_Complex_I, -19.365854088060 + -1.898384733722*_Complex_I, 22.654736737697 + -31.009432894736*_Complex_I, 8.366067634071 + 17.695248714554*_Complex_I, 13.661573039778 + 5.489335650118*_Complex_I, 7.965893046432 + 0.920878507501*_Complex_I, -6.773323972099 + -8.838093482259*_Complex_I, 18.008424231247 + 0.970453153687*_Complex_I, 3.616219743282 + -7.106399136439*_Complex_I, 4.354625182855 + 6.303312903302*_Complex_I, 2.152940232565 + 10.856400632985*_Complex_I, 9.549358562936 + 3.736001577178*_Complex_I, -23.393358100356 + -6.204075948816*_Complex_I, 15.508680212133 + 8.577949641991*_Complex_I, -7.063921889490 + -9.211630834511*_Complex_I, 21.009705406653 + -6.517205812361*_Complex_I, 15.423888702704 + 0.981999687774*_Complex_I, 28.573348594219 + 5.383290022507*_Complex_I, 15.304347003446 + 27.118709596573*_Complex_I, 14.142070126013 + 6.277279353863*_Complex_I, 1.625323780309 + -9.187451801090*_Complex_I, 8.830870090341 + 18.810210753448*_Complex_I, -0.345015176149 + -9.619976818810*_Complex_I, 7.341484437606 + -0.732292583861*_Complex_I, 8.958852700478 + -10.587428450375*_Complex_I, 3.882707974052 + -17.745844755612*_Complex_I, -8.873303252125 + -15.211822737393*_Complex_I, -6.167534400705 + 10.214589494545*_Complex_I, -20.228656724261 + 17.585629744635*_Complex_I, 10.933318198559 + 14.370328231006*_Complex_I, -8.461977401717 + -11.180604276190*_Complex_I, -9.616742566226 + -24.903826036989*_Complex_I, -11.411472927768 + 17.575007330620*_Complex_I, -2.685486674198 + -14.771303637127*_Complex_I, -25.251618764170 + 6.826824013717*_Complex_I, -6.299724034225 + -16.396112316751*_Complex_I, -7.265214784934 + -5.565409121926*_Complex_I, -6.640524692135 + 0.521019036698*_Complex_I, 16.214262242728 + 2.209865277239*_Complex_I, -5.045705495784 + 7.246063716170*_Complex_I, 12.635656398329 + 5.953408206671*_Complex_I, 7.826253258739 + 10.349167227222*_Complex_I, 2.088937948255 + -5.121963022405*_Complex_I, -11.873961874446 + 14.994764484717*_Complex_I, 22.398422820899 + 6.844715327780*_Complex_I, -12.730924558399 + -11.992318329822*_Complex_I, 13.524168525742 + -4.729670042115*_Complex_I, 1.202484810688 + -1.663460844124*_Complex_I, -1.947874132965 + 1.302757622556*_Complex_I, -20.543601027337 + 12.258518226726*_Complex_I, -3.137767302170 + -2.981480633371*_Complex_I, -7.975513140256 + -16.485317151074*_Complex_I, 8.810596349659 + 6.332990185486*_Complex_I, -6.161246346457 + 5.235039382005*_Complex_I, 2.843534766863 + -4.617409607122*_Complex_I, -4.073520680077 + -5.879651303740*_Complex_I, -2.171553918002 + -2.554595714543*_Complex_I, -6.693230033855 + -4.317974300454*_Complex_I, 2.510552087942 + 5.009469541979*_Complex_I, -19.083210256655 + 5.125864403228*_Complex_I, 0.411198384867 + 2.018760355265*_Complex_I, -9.315948091880 + -15.753105210356*_Complex_I, 7.665007791183 + 19.339077441185*_Complex_I, 17.992904291137 + 1.608531544860*_Complex_I, 7.252549051948 + 5.185390374966*_Complex_I, -3.402294497131 + 15.472029335175*_Complex_I, -10.304002604604 + -3.412309568194*_Complex_I, 3.576347909571 + -16.980789801741*_Complex_I, -14.889487424902 + -0.293460269814*_Complex_I, -2.329133331489 + 15.570197654593*_Complex_I, -4.321477736813 + 4.956074608145*_Complex_I, 3.632694634916 + 11.871283520762*_Complex_I, 2.290904837875 + -0.771528125573*_Complex_I, 36.996035166517 + -1.073727284586*_Complex_I, 6.227709813318 + -9.761528406472*_Complex_I, -2.515872122268 + 0.034234272997*_Complex_I, 4.552755682518 + -9.370352932646*_Complex_I, 9.004603455113 + 4.753018490255*_Complex_I, 0.440587766505 + 16.114787576668*_Complex_I, -28.634077387281 + -5.605910818928*_Complex_I, -5.160190484618 + -11.779239644678*_Complex_I, -17.819659704355 + 0.062857325389*_Complex_I, -14.769191642874 + -0.223091433159*_Complex_I, 2.070190617098 + -3.834976376660*_Complex_I, -3.825400452939 + -5.056722468813*_Complex_I, -15.844519611706 + -11.255119227692*_Complex_I, 25.546454083988 + 2.033450780777*_Complex_I, 25.208964212648 + -18.608412069091*_Complex_I, -30.422847814837 + -18.350779470779*_Complex_I, 15.095434571838 + 20.530536309828*_Complex_I, 1.789608009331 + 28.248536173054*_Complex_I, -12.951533049636 + 6.950006423363*_Complex_I, 8.717234868692 + -32.148462751388*_Complex_I, 7.386347991900 + 3.651733560911*_Complex_I, -12.562312227509 + 3.070991373115*_Complex_I, -0.069804711953 + 1.802309211709*_Complex_I, 1.176122484348 + -14.149959691947*_Complex_I, 5.353573748142 + 0.564676076929*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_157.c000066400000000000000000000411161474751757600215550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 157-point transform // #include float complex fft_test_x157[] = { 0.257182749425 + 0.221924222343*_Complex_I, 1.678933476985 + 1.690438801569*_Complex_I, -0.370453539748 + -0.279443271284*_Complex_I, -0.425568170028 + -0.346884537719*_Complex_I, 0.025131704106 + 0.368626953376*_Complex_I, -0.013250700538 + 0.876875327290*_Complex_I, 0.935964221688 + -0.003996500003*_Complex_I, 0.697482794970 + 0.169890786221*_Complex_I, -0.672758751419 + -0.529033743727*_Complex_I, -0.103638614252 + 0.221443696028*_Complex_I, -0.365208618659 + -0.660189374984*_Complex_I, 0.148416173585 + -0.919145673704*_Complex_I, -0.015366679279 + -0.943544155661*_Complex_I, 1.622323455798 + 0.481254671673*_Complex_I, -0.438594792675 + 0.487727000762*_Complex_I, 1.590594341984 + -0.549613288902*_Complex_I, -0.917184623744 + -2.221026339765*_Complex_I, -1.617744928538 + 1.593484682047*_Complex_I, -0.989508283152 + -0.094108203222*_Complex_I, 0.852090994091 + -2.231080010685*_Complex_I, -0.400903430450 + -0.366248303051*_Complex_I, -0.125211983197 + -1.455734382818*_Complex_I, 1.947225389836 + 0.980175860892*_Complex_I, -1.398014729095 + 0.014318572276*_Complex_I, -0.771114386583 + 0.544211573481*_Complex_I, 0.126434853618 + -0.465319924891*_Complex_I, 0.952552119580 + 2.799409645314*_Complex_I, 0.745539772546 + 0.038782344125*_Complex_I, 0.629464449611 + -1.544746925900*_Complex_I, -1.430974620188 + -1.148543279148*_Complex_I, -0.550191215098 + -1.044145048363*_Complex_I, -0.616171694097 + -1.252745889547*_Complex_I, 0.988808988108 + -1.602725943935*_Complex_I, -0.607710796313 + 0.518971475013*_Complex_I, 0.771090806997 + -0.385515422626*_Complex_I, 0.825512088357 + 0.474459769075*_Complex_I, -0.291745809631 + -0.149808656805*_Complex_I, -1.958415654055 + 0.651147959844*_Complex_I, -0.778182389479 + -0.780881485990*_Complex_I, -2.015821535479 + -0.050499463828*_Complex_I, 0.887353255055 + -1.214230826942*_Complex_I, -0.096317891587 + 0.761206139060*_Complex_I, -1.062009284735 + -0.271266211836*_Complex_I, 1.423990266183 + 1.335814455222*_Complex_I, -0.847479948365 + 2.671530186606*_Complex_I, -1.345728311726 + -0.634481496676*_Complex_I, -0.797816703427 + 0.502757855534*_Complex_I, -0.464673266498 + 0.116721201943*_Complex_I, 0.203062847770 + 0.561494795746*_Complex_I, 0.033909266352 + -0.261380019453*_Complex_I, -0.658056423237 + 1.281296865326*_Complex_I, 0.941736081602 + 1.987602839317*_Complex_I, -0.423846356775 + -1.241587960307*_Complex_I, -0.393324168712 + 0.737043249313*_Complex_I, -1.944403782443 + -0.943905358441*_Complex_I, -0.528242253913 + 1.908236422266*_Complex_I, 1.452295322067 + -0.869099055081*_Complex_I, -1.120053624869 + 0.850800785935*_Complex_I, 0.365006117743 + -0.347073388222*_Complex_I, -1.980724188697 + 1.747266666168*_Complex_I, 1.558965406397 + 0.725116188824*_Complex_I, -1.050340476177 + 0.477386287145*_Complex_I, 0.078299549695 + -1.166209184146*_Complex_I, 0.666177598254 + -1.881539760701*_Complex_I, -0.553008717374 + 0.112063233224*_Complex_I, -1.542438669400 + -0.905459946121*_Complex_I, -0.540183077595 + -0.653405677927*_Complex_I, 0.093096056538 + 1.658838310544*_Complex_I, -0.070743442866 + -0.474238998458*_Complex_I, -1.057268947675 + 0.965366634327*_Complex_I, -0.084404481306 + 0.516458044167*_Complex_I, 0.415540467796 + -0.571894574983*_Complex_I, -0.495234089660 + 0.103235766156*_Complex_I, 0.464768365021 + 0.651070663181*_Complex_I, -1.478301866530 + -1.246265840883*_Complex_I, -0.810080291321 + -0.090687751615*_Complex_I, 1.597727768491 + -1.303542260713*_Complex_I, 0.899193648643 + 0.101515082173*_Complex_I, -1.275261212066 + -1.670150745367*_Complex_I, -0.067477528818 + 0.082676448878*_Complex_I, -0.593487795772 + 1.015383261914*_Complex_I, -0.195143706875 + 0.197795648282*_Complex_I, 1.470101318427 + -1.090920995443*_Complex_I, 3.099635934834 + 0.418783664178*_Complex_I, 0.517928899798 + -0.515604023095*_Complex_I, -0.699637334030 + 0.411968031541*_Complex_I, 0.238527504044 + -1.024932943805*_Complex_I, 1.067350706566 + -1.185403362126*_Complex_I, 1.013271318338 + 0.881471326676*_Complex_I, 0.004430604182 + -0.799775043761*_Complex_I, 0.351524389294 + 0.780435439706*_Complex_I, 0.106334238498 + 0.458736063427*_Complex_I, -0.008723581305 + 2.334855897709*_Complex_I, -0.486030470423 + -0.237085023857*_Complex_I, -0.752315645429 + 0.905584767839*_Complex_I, -0.578103821311 + 1.125629982729*_Complex_I, -0.948197773007 + -0.457632138151*_Complex_I, 0.742229639059 + 0.271160961106*_Complex_I, -0.773931821655 + -0.314444247010*_Complex_I, -1.490298210738 + 0.035980837847*_Complex_I, 0.199618338445 + 0.632691460449*_Complex_I, -0.234261424994 + -1.443456519632*_Complex_I, 0.463236279099 + 0.303140551137*_Complex_I, 0.292524617190 + -0.043026971072*_Complex_I, 0.046692677937 + 1.116783220186*_Complex_I, -1.861132210698 + 0.261380583838*_Complex_I, -0.341148975896 + -0.470343064889*_Complex_I, -0.671470989909 + 0.007947245970*_Complex_I, -0.534160841208 + -0.124549058301*_Complex_I, 0.487094311512 + -0.314353890072*_Complex_I, -0.403442115448 + -0.857412221358*_Complex_I, 1.085529198882 + -0.386892824664*_Complex_I, 0.591555113309 + 0.384947041491*_Complex_I, -0.516471791207 + -0.646903850947*_Complex_I, -0.216099520865 + 0.030923700983*_Complex_I, -2.362722198570 + 2.187609191074*_Complex_I, -2.996234948353 + 1.169329942024*_Complex_I, 0.398987017180 + 1.432369958192*_Complex_I, -0.321543239403 + -1.079202616493*_Complex_I, 0.155932087142 + 0.283226593654*_Complex_I, -0.149566717019 + 2.000037448099*_Complex_I, -0.505275327391 + -0.592114971901*_Complex_I, 0.712863240336 + -0.919212613392*_Complex_I, 2.561694455976 + -0.315857229465*_Complex_I, -0.401098664528 + -1.414850199386*_Complex_I, 1.068811040362 + -0.520713203914*_Complex_I, -0.928756706401 + -1.036472849545*_Complex_I, 0.731918541008 + 2.246056257734*_Complex_I, -1.087622423230 + -1.271134991425*_Complex_I, 0.747682565630 + 1.167376255945*_Complex_I, 0.823139516666 + 0.417274248065*_Complex_I, 0.488604293527 + -0.768657162242*_Complex_I, -1.566207330521 + -0.520510590335*_Complex_I, 0.286432330277 + -0.603250643993*_Complex_I, 0.685025047143 + -0.939995698866*_Complex_I, 0.955471389243 + -0.323428744209*_Complex_I, -1.169027438782 + -0.175653814544*_Complex_I, -0.284005159687 + 0.460772145706*_Complex_I, -0.310159212214 + -1.720418494846*_Complex_I, 0.305232638909 + -0.090314073904*_Complex_I, 0.190795117789 + -0.467619419555*_Complex_I, -0.905744042954 + -1.143116395802*_Complex_I, 0.392128587570 + 2.286798561832*_Complex_I, -1.315880319405 + -1.432434182558*_Complex_I, 1.007683317172 + -0.154461360928*_Complex_I, 0.474642520199 + 0.729416858430*_Complex_I, -0.679375823140 + -2.856682284668*_Complex_I, -0.687426016158 + -1.023213289303*_Complex_I, -0.022785229613 + 0.698739170753*_Complex_I, -0.643221050022 + 1.444057111513*_Complex_I, 0.149585673645 + -0.602773170360*_Complex_I, 0.389853409146 + -0.949003645210*_Complex_I, -1.115251553217 + -0.405311422912*_Complex_I, 0.228569355271 + -0.486849085232*_Complex_I, -0.140823347089 + -0.328067722810*_Complex_I, 1.388787822068 + -2.267147899079*_Complex_I, 0.939124099904 + -0.563609820499*_Complex_I}; float complex fft_test_y157[] = { -13.721520175468 + -9.568907767571*_Complex_I, 8.721468524756 + -10.198063416643*_Complex_I, 15.060716782723 + -14.846901712846*_Complex_I, -11.623905596583 + 16.650835292293*_Complex_I, 19.695072317931 + -11.298461808236*_Complex_I, 1.838122765692 + 7.179001252206*_Complex_I, 8.145195639028 + -10.634659386087*_Complex_I, 13.033783220459 + 19.061682407788*_Complex_I, -3.959970595745 + -7.333783752376*_Complex_I, 17.086993536942 + -6.079044767515*_Complex_I, 10.491053572778 + -4.514192461667*_Complex_I, 6.064025221921 + 10.332579887094*_Complex_I, -3.762638600928 + 10.624543304629*_Complex_I, -1.847856432273 + -8.006182372781*_Complex_I, 41.710087074031 + 2.242012124979*_Complex_I, 8.362552928082 + -0.431571425998*_Complex_I, -2.684280607792 + -19.646530227003*_Complex_I, -5.355855356382 + -4.457469415514*_Complex_I, -7.411106913072 + 24.950544746191*_Complex_I, 16.058416814462 + 7.398904353701*_Complex_I, 4.287192732400 + -11.227843680234*_Complex_I, -1.117925486982 + 24.330611594547*_Complex_I, 3.444591991920 + 32.326680862100*_Complex_I, 17.351475510592 + -7.023399927552*_Complex_I, -0.243462815765 + 5.525094059061*_Complex_I, 1.824464191173 + -10.437625350692*_Complex_I, 0.863195259259 + 8.286510583962*_Complex_I, -2.958971801726 + -14.975362935027*_Complex_I, 9.706578069666 + 2.274491450388*_Complex_I, 18.904225667531 + 9.156322125243*_Complex_I, 1.847919083204 + 22.188095024380*_Complex_I, -4.136288117963 + -22.092021747680*_Complex_I, 4.703234992916 + 0.532501901615*_Complex_I, -3.030532632664 + -11.313921121067*_Complex_I, 1.091146775351 + 7.577427645200*_Complex_I, 3.975634530789 + 10.604839429746*_Complex_I, 12.752600166339 + 7.600696307234*_Complex_I, 15.977675567158 + 16.362460714763*_Complex_I, -0.020172843559 + 3.858168994446*_Complex_I, -14.397449821557 + 12.915383581435*_Complex_I, 15.101543348628 + -23.907576345828*_Complex_I, -1.954273280892 + 13.597214533352*_Complex_I, -8.025138226552 + 3.693906127107*_Complex_I, -10.663001711599 + 11.720999651550*_Complex_I, -1.917368345264 + -19.036649221044*_Complex_I, 4.152821868650 + -8.488773546805*_Complex_I, -24.343188706355 + -10.538612575861*_Complex_I, 12.414685926300 + 16.068084980361*_Complex_I, 2.673733474235 + -8.293379374130*_Complex_I, 9.339757855123 + 0.779105093141*_Complex_I, 34.385020257627 + -8.910778839680*_Complex_I, 13.686080719584 + -2.468581114278*_Complex_I, -0.105352104096 + -7.123485160682*_Complex_I, -26.981218401390 + 13.727259016390*_Complex_I, -6.504207057579 + 3.268522185903*_Complex_I, 7.577558748754 + 2.965812787302*_Complex_I, -22.926267985360 + 4.630017422388*_Complex_I, -8.347022143339 + 1.975527870103*_Complex_I, 3.060029390078 + -21.656262254959*_Complex_I, 9.637126253972 + -7.538708825218*_Complex_I, -13.130853679756 + -18.805264312027*_Complex_I, -16.821204438708 + 4.950740394033*_Complex_I, 22.988677066759 + -1.571260161915*_Complex_I, 1.406205876954 + 12.062599478139*_Complex_I, -28.514716646160 + 7.993271146497*_Complex_I, -0.907689305572 + 0.456303536916*_Complex_I, -3.571030267866 + -4.518597998420*_Complex_I, -11.957457146313 + -19.766437913007*_Complex_I, -5.413654003898 + -1.754632161022*_Complex_I, -9.175989023330 + -7.046783981905*_Complex_I, -4.258428526498 + -16.319730685668*_Complex_I, -8.132160224937 + -1.537755723079*_Complex_I, 15.156793468505 + 10.343087291076*_Complex_I, 25.761505476002 + 3.887909686471*_Complex_I, 21.853951697775 + -12.770771455381*_Complex_I, -14.242421455518 + 2.407693112009*_Complex_I, -13.467445303389 + -29.036488998230*_Complex_I, -9.305071893547 + 2.506212475888*_Complex_I, 22.323867850705 + -4.075769716056*_Complex_I, -5.679643000649 + -3.670620943265*_Complex_I, -13.769169134408 + 13.834529429033*_Complex_I, -12.414956903750 + -16.194735699494*_Complex_I, -2.005403979995 + -11.362528318332*_Complex_I, 7.730155179299 + 9.255875770335*_Complex_I, 15.051941677947 + -3.828126836044*_Complex_I, -21.086873877673 + 12.717384691065*_Complex_I, 22.428970474249 + 14.741806815196*_Complex_I, 2.480130753861 + -23.039122194478*_Complex_I, -10.903771391849 + -13.412743738585*_Complex_I, 6.147006915635 + 13.690721935985*_Complex_I, -20.616357511746 + -17.845769868478*_Complex_I, -8.402987902554 + 3.410410123270*_Complex_I, 10.582061652995 + 4.348210154826*_Complex_I, 15.024788596168 + -5.782083339001*_Complex_I, 8.689851678442 + 35.535383742654*_Complex_I, -4.132601952228 + -0.321739745032*_Complex_I, -19.197163106392 + 3.413027621621*_Complex_I, -5.794327856223 + -7.331102283615*_Complex_I, -6.543417534351 + -1.677934031582*_Complex_I, 7.329352169488 + -4.324029036611*_Complex_I, -25.477673544286 + -10.789721951286*_Complex_I, -0.912644707297 + -9.637940446228*_Complex_I, 4.037691841333 + 3.096945310047*_Complex_I, -5.847674330905 + 13.938407689472*_Complex_I, 10.812159378022 + 2.497873869651*_Complex_I, 5.034733833406 + 20.614345199846*_Complex_I, 9.197163204775 + 3.499527690970*_Complex_I, -11.061382406800 + 3.269075618163*_Complex_I, -2.869327440190 + -17.824719429904*_Complex_I, -16.473833296088 + -7.487202778068*_Complex_I, 6.310496423938 + 5.004751989728*_Complex_I, -6.079010956757 + 18.024756582815*_Complex_I, -4.356220575254 + -2.205381751597*_Complex_I, -8.493558121870 + -3.869308590719*_Complex_I, 7.159973070917 + 6.849733506562*_Complex_I, 17.405411913875 + -3.643915205170*_Complex_I, 1.342183355448 + 0.252403128806*_Complex_I, 2.470554720768 + 3.325864954849*_Complex_I, 3.304540368971 + -7.701906570289*_Complex_I, -41.203455184368 + 12.817592975767*_Complex_I, -20.058954711820 + 19.878752053751*_Complex_I, 9.046175416813 + 11.732938261288*_Complex_I, -0.786044861883 + 17.615815760165*_Complex_I, -3.027566374297 + 11.824558467687*_Complex_I, -3.793394817088 + 4.309384254386*_Complex_I, -15.395453276032 + -6.476272377854*_Complex_I, 2.993318695808 + 20.818567190739*_Complex_I, -21.109827170023 + -18.433989642597*_Complex_I, -7.427193578999 + -4.496310454720*_Complex_I, 13.462176439125 + -14.456554646582*_Complex_I, 2.860309865551 + 0.813195406900*_Complex_I, -16.705039250487 + 5.416257334069*_Complex_I, 12.149530796231 + 5.677739145239*_Complex_I, 10.883522142352 + -2.048976821145*_Complex_I, 33.919769198703 + 14.546697989253*_Complex_I, -0.080428049883 + -5.729314964055*_Complex_I, -1.382967825489 + -0.843240827862*_Complex_I, -14.258739687335 + -4.164415134916*_Complex_I, -11.232537602109 + 13.450368521399*_Complex_I, 6.475674985073 + -6.229640995099*_Complex_I, 9.211806090883 + -7.267971548561*_Complex_I, -14.365301190661 + 8.987964911736*_Complex_I, -11.266093935597 + -15.954781116216*_Complex_I, -18.499836430748 + -8.923649916614*_Complex_I, 31.090884321227 + 2.260100309627*_Complex_I, -7.383545212516 + 10.553116472713*_Complex_I, 1.165337529929 + -1.083672004639*_Complex_I, 1.026784219611 + -16.203749347621*_Complex_I, -0.529416311921 + -8.707703034115*_Complex_I, -9.657893357311 + 12.096083541637*_Complex_I, -15.285477594802 + 4.224467463110*_Complex_I, 16.595393096965 + 1.232758856522*_Complex_I, 10.380238903621 + -5.473695910884*_Complex_I, -5.199124871644 + 14.427071924858*_Complex_I, -10.919624558299 + 16.105413828801*_Complex_I, 15.081167155045 + -6.737986374676*_Complex_I, 5.602666437487 + -19.846630500695*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_16.c000066400000000000000000000054671474751757600215000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 16-point transform // #include float complex fft_test_x16[] = { -1.772146047027 + 0.295934658602*_Complex_I, -1.433777343858 + -0.874041962217*_Complex_I, -0.388629405392 + 0.611030474954*_Complex_I, -0.492539890742 + 1.007726724574*_Complex_I, 0.494699992643 + -1.725668238103*_Complex_I, 0.572982289851 + 0.061642401846*_Complex_I, -0.574974496567 + 0.909843544187*_Complex_I, 0.733687565510 + 0.447433079732*_Complex_I, 0.308242485351 + -1.532252262483*_Complex_I, 1.207949830231 + -0.953543898451*_Complex_I, 0.640048909719 + -1.022371047059*_Complex_I, -0.241879356643 + -0.462432765300*_Complex_I, -0.435900183311 + 0.856847254979*_Complex_I, 0.577243720893 + 0.220786650383*_Complex_I, 1.263302572543 + 1.444493924498*_Complex_I, 1.911070541506 + -1.906912076526*_Complex_I}; float complex fft_test_y16[] = { 2.369381184706 + -2.621483536381*_Complex_I, -2.618054253504 + 4.676728363894*_Complex_I, -2.946376269367 + 0.522273546089*_Complex_I, 2.120729100677 + 4.308004588255*_Complex_I, -2.975823103566 + -3.062195121072*_Complex_I, -3.932696300262 + 3.143967424649*_Complex_I, -0.247865075327 + 5.467645213372*_Complex_I, 3.887448941709 + 5.439788616063*_Complex_I, -3.300093528791 + 2.297200155534*_Complex_I, -4.008939493163 + 4.239020717646*_Complex_I, -5.630386554230 + -0.383449644305*_Complex_I, -0.707551950987 + 2.197968388714*_Complex_I, -1.713879561730 + -5.034075846097*_Complex_I, -8.091926054909 + -8.469369525668*_Complex_I, 2.733814414891 + -7.076455598181*_Complex_I, -3.292118248586 + -0.910613204873*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_17.c000066400000000000000000000056331474751757600214740ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 17-point transform // #include float complex fft_test_x17[] = { -0.655587921776 + -0.863886550358*_Complex_I, -1.070139919529 + -2.370656605854*_Complex_I, 1.167384281127 + 0.116747569575*_Complex_I, 1.105640858428 + -1.226141009276*_Complex_I, -0.349562744440 + -0.005953723423*_Complex_I, 0.655312446998 + 1.594642817084*_Complex_I, -0.230495501721 + -0.272806523691*_Complex_I, 0.731764183318 + -0.732380509571*_Complex_I, -0.953609619255 + 1.102615917395*_Complex_I, -0.496898865182 + -1.822920499315*_Complex_I, -2.052948327746 + -0.382334768518*_Complex_I, 1.062783811112 + 0.673250838256*_Complex_I, -0.142175503751 + 0.542432325176*_Complex_I, 1.108087524611 + -0.029888173999*_Complex_I, -0.164259605567 + -1.184782100304*_Complex_I, -0.236452649938 + -0.998080495482*_Complex_I, -0.197908967423 + -0.229518503722*_Complex_I}; float complex fft_test_y17[] = { -0.719066520735 + -6.089659996026*_Complex_I, 1.821427336790 + -5.621144218242*_Complex_I, -6.173678834923 + -4.525807530343*_Complex_I, -1.549626337288 + 0.314087328771*_Complex_I, -5.136370472539 + 4.327372264632*_Complex_I, -0.105170126419 + -2.207231016009*_Complex_I, -5.750228396460 + 3.094152945701*_Complex_I, 0.618725077794 + 3.278602823446*_Complex_I, -0.888646366224 + -3.887677672776*_Complex_I, 3.905822192802 + 7.933139073811*_Complex_I, -1.522365359136 + 0.172605279098*_Complex_I, 8.552784050577 + -3.105361200836*_Complex_I, -1.598265822441 + -5.532288727983*_Complex_I, 1.151099028128 + -2.046469788513*_Complex_I, 0.253410312032 + 6.386316111258*_Complex_I, -4.676752932337 + -4.421634395132*_Complex_I, 0.671908500186 + -2.755072636947*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_192.c000066400000000000000000000477721474751757600215720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 192-point transform // #include float complex fft_test_x192[] = { -0.570749076040 + 1.623496753738*_Complex_I, -0.801441214588 + -0.237768079755*_Complex_I, -1.136144657269 + 0.367681411439*_Complex_I, -0.021881616373 + -1.310767380444*_Complex_I, -1.897076967315 + -0.151633764169*_Complex_I, -0.065089420065 + 0.179240807290*_Complex_I, -0.459561140285 + 0.186362705450*_Complex_I, -1.459184572831 + -0.172507317719*_Complex_I, 0.768770035801 + -0.603405455907*_Complex_I, -0.445592790811 + -0.545504111400*_Complex_I, -1.133095461256 + 0.347109313928*_Complex_I, 0.680343842697 + 0.984380778227*_Complex_I, 1.434274246060 + -0.455280274247*_Complex_I, 1.367719846389 + -0.017753112833*_Complex_I, -1.036796157162 + 0.202926093122*_Complex_I, -0.608495290895 + 1.377505175242*_Complex_I, 0.677352983170 + 0.522913747818*_Complex_I, 0.829598919707 + -0.238489026179*_Complex_I, 1.658006740638 + 1.321959544651*_Complex_I, -1.813019197848 + -1.379543844064*_Complex_I, -0.105360926209 + 0.770250719958*_Complex_I, 0.950326938828 + -0.839058539588*_Complex_I, 1.158809729841 + -0.647245275247*_Complex_I, -0.360439558788 + -0.056522073112*_Complex_I, -0.729658576111 + -0.230389217591*_Complex_I, -0.147264114233 + -0.844995936147*_Complex_I, 3.006061814772 + 0.324561093094*_Complex_I, 0.421672171136 + -1.045335631843*_Complex_I, 1.450421276223 + -1.809661507608*_Complex_I, 0.112589736618 + -0.680553655537*_Complex_I, -0.962866997971 + 0.051225992580*_Complex_I, -0.069473575656 + 0.412572221634*_Complex_I, 0.807441882459 + -0.390366883673*_Complex_I, 0.494922478167 + 0.666273714397*_Complex_I, 0.534063543949 + 0.216473899855*_Complex_I, 0.115686515954 + -1.150016410968*_Complex_I, -0.911950154175 + -1.906708901788*_Complex_I, 0.035013270272 + 1.560677880077*_Complex_I, -0.689521651706 + -0.963904151064*_Complex_I, -1.140202975221 + -0.076069898430*_Complex_I, -0.246077937761 + 0.616853881528*_Complex_I, -0.251792408901 + -0.385289165959*_Complex_I, 0.144732608298 + -0.544232656456*_Complex_I, 0.716079834835 + 0.154716467884*_Complex_I, -0.454600091317 + -0.778823717821*_Complex_I, -0.004009391933 + 0.239803231190*_Complex_I, 0.128608781578 + 0.252750485610*_Complex_I, -0.104121384913 + -1.189000295448*_Complex_I, 0.242846644961 + 0.081301007736*_Complex_I, 1.450965500668 + 0.361778385840*_Complex_I, -0.190106534680 + 0.071804478293*_Complex_I, 0.420793349874 + 1.491145034929*_Complex_I, 2.460108883286 + 0.757779280601*_Complex_I, -0.825692579645 + -0.596573882891*_Complex_I, 0.671589132843 + 1.011087599399*_Complex_I, 1.284648906257 + -0.045814861627*_Complex_I, -0.760224555847 + -0.722324468953*_Complex_I, -1.322063665211 + -2.308468943382*_Complex_I, 2.293407378555 + 0.010203054084*_Complex_I, 0.055649061121 + -2.002674185757*_Complex_I, -0.282775998354 + -1.935193634195*_Complex_I, 1.737107472308 + -1.107578165456*_Complex_I, -0.235741548678 + -0.486998315145*_Complex_I, -0.270131100153 + -2.340452003512*_Complex_I, -1.145976320980 + 1.671478612533*_Complex_I, 1.046314822557 + 0.182117686556*_Complex_I, -0.745497599782 + -0.723373842151*_Complex_I, -0.511430521736 + -0.669552224448*_Complex_I, 0.619398807961 + -0.051926233859*_Complex_I, 0.650768664429 + -0.054337533084*_Complex_I, -0.377066273366 + 0.748578490695*_Complex_I, 0.868445500849 + -1.916678793529*_Complex_I, -0.745634363305 + 2.968322096526*_Complex_I, 1.601642204548 + -1.815842464572*_Complex_I, -0.110280900762 + -0.375012568050*_Complex_I, 1.082989689805 + 0.615940836645*_Complex_I, 0.285506402216 + 0.273198983697*_Complex_I, 0.277214797147 + 1.771337438831*_Complex_I, 0.165028606876 + -0.704451808040*_Complex_I, 0.317894159247 + 0.492665087928*_Complex_I, 0.601574563612 + -0.904521376193*_Complex_I, -0.642798244158 + 0.327271328047*_Complex_I, 0.011482342139 + -0.787115819239*_Complex_I, 0.244096373806 + 0.152569770967*_Complex_I, 0.178980665283 + 0.813856965670*_Complex_I, 1.492787787643 + -0.413137630323*_Complex_I, -1.122949408956 + -0.730572761342*_Complex_I, 0.096736426284 + -0.623125567869*_Complex_I, -0.054054998356 + 0.102181208006*_Complex_I, 0.016144101863 + -0.139709667178*_Complex_I, 1.323423360215 + -1.218385808067*_Complex_I, 1.225801036168 + 1.825795241395*_Complex_I, 1.773877495557 + 0.364293281834*_Complex_I, -1.266134039437 + 0.099487732018*_Complex_I, -0.417581296163 + 0.343715046363*_Complex_I, 0.505757022167 + -0.500849213570*_Complex_I, 0.968334906502 + -0.526257684744*_Complex_I, 0.333143774360 + 0.396107354791*_Complex_I, -0.506358896777 + -0.087644984012*_Complex_I, 1.324525846569 + 1.494077333636*_Complex_I, -0.951951460363 + 0.994211347018*_Complex_I, -2.692462733023 + -0.697601652243*_Complex_I, -1.072637853655 + 1.879429345687*_Complex_I, -0.193163794476 + 1.344807479696*_Complex_I, -0.036468538711 + -2.246890819337*_Complex_I, 0.123890932473 + -1.171359056597*_Complex_I, 1.614167761632 + -0.084861961160*_Complex_I, 0.813475153805 + -1.363244160675*_Complex_I, -0.751043379055 + -0.001003534113*_Complex_I, -1.127244933655 + 0.033479567244*_Complex_I, 0.120947403072 + 0.172712059551*_Complex_I, -0.650772252959 + 1.321513948454*_Complex_I, 1.305164416475 + -0.787832375788*_Complex_I, -0.312608725354 + -0.233463073219*_Complex_I, -0.754485246213 + -0.132782409884*_Complex_I, 1.522953329225 + 0.109222954313*_Complex_I, -0.495952414190 + 0.544687157445*_Complex_I, 0.506640354547 + -1.676292292327*_Complex_I, 0.495984603346 + 0.705582611126*_Complex_I, 0.555362258234 + 1.175515543993*_Complex_I, -1.380515094250 + 0.427692852149*_Complex_I, 0.003538138035 + 1.425908489255*_Complex_I, 1.062943493718 + 1.079328766594*_Complex_I, 0.035769210794 + 0.546944179639*_Complex_I, -1.009393498146 + -0.836699998466*_Complex_I, -1.299667858035 + -1.876603335383*_Complex_I, 1.400213634255 + -1.094331065468*_Complex_I, -0.978532602360 + -1.133768146514*_Complex_I, -0.126022453004 + -0.548218141207*_Complex_I, -0.459386774097 + -1.142543752432*_Complex_I, -0.634282978000 + 0.401478043588*_Complex_I, 0.536619631169 + -0.637851111890*_Complex_I, -2.177417556650 + -0.582755642600*_Complex_I, 1.956859485192 + 0.756502126757*_Complex_I, -1.033248608338 + 0.083674820018*_Complex_I, 0.361227297522 + 0.246987978580*_Complex_I, 0.200321461901 + 0.997822511718*_Complex_I, -1.130355402825 + -0.097176654080*_Complex_I, 1.384768698791 + -0.772817911874*_Complex_I, 0.926525539860 + 0.145277765291*_Complex_I, -0.540081956252 + 0.372734113022*_Complex_I, 0.327046375183 + 1.452638689757*_Complex_I, -0.402162597503 + -0.571759031309*_Complex_I, 1.213886497238 + 0.862378057918*_Complex_I, -0.024799349445 + -0.640880433466*_Complex_I, 0.605895117723 + 1.040856615204*_Complex_I, 0.875424648817 + -1.747168830682*_Complex_I, 1.792252094005 + 1.449436965826*_Complex_I, -0.058686051876 + 0.024079540685*_Complex_I, -1.197793455172 + 0.076528126740*_Complex_I, -1.451475019825 + 2.506331331519*_Complex_I, 0.115177207244 + 0.581887944455*_Complex_I, -0.894760295667 + 0.941285480086*_Complex_I, 0.167847546335 + 0.113650691315*_Complex_I, 0.580138910850 + 1.482400230136*_Complex_I, -0.638693285492 + 0.706252192544*_Complex_I, -0.679198255352 + -0.864392741247*_Complex_I, 0.309224287292 + 0.802306837308*_Complex_I, 0.089371278986 + -1.059876744659*_Complex_I, 1.352756771804 + -0.303374747952*_Complex_I, 0.142478845463 + 1.679379378038*_Complex_I, -0.307104681980 + -1.525241010787*_Complex_I, 0.947136026136 + -0.176290475474*_Complex_I, -0.191221819400 + 0.872369793925*_Complex_I, -0.694209420142 + 0.251537117440*_Complex_I, 1.193931121456 + 0.364438121717*_Complex_I, 0.364530798418 + 0.953151437736*_Complex_I, -2.204969193002 + 0.591100538765*_Complex_I, 1.152638435048 + 0.423855010290*_Complex_I, -0.190087319373 + -0.236280077579*_Complex_I, -0.959025701481 + -1.046604614844*_Complex_I, -0.059036610250 + 0.757806508323*_Complex_I, 1.193828263334 + 0.991816149312*_Complex_I, -0.644717162130 + 0.685130498159*_Complex_I, 0.386929662859 + 0.246269623980*_Complex_I, 0.747830541986 + -0.853860497506*_Complex_I, 0.563215051840 + -1.553462734011*_Complex_I, -0.411175328612 + 0.338710437150*_Complex_I, -1.017739241999 + -0.234632452129*_Complex_I, -2.270318833952 + 0.624001888473*_Complex_I, 0.530109233459 + -3.021054334701*_Complex_I, -0.733212401282 + 0.337380481817*_Complex_I, 0.686400469100 + 1.434988023046*_Complex_I, -1.537557685024 + 0.266727612837*_Complex_I, 2.377907246279 + -0.647849557308*_Complex_I, 1.588677766399 + -0.611004042543*_Complex_I, 0.547569751159 + -0.942144527428*_Complex_I, -0.489770632777 + -1.190329237689*_Complex_I, -0.588811442748 + 1.025069940138*_Complex_I, -0.380574882230 + -1.193424193517*_Complex_I, -2.719012193329 + -0.412270955448*_Complex_I, 1.447794971270 + 0.160429136252*_Complex_I}; float complex fft_test_y192[] = { 11.637079481157 + -8.771861743960*_Complex_I, -26.395324212554 + -12.523034709229*_Complex_I, -13.199274560613 + 4.197128353434*_Complex_I, 2.770319150971 + -22.367461652042*_Complex_I, 0.642915300037 + 6.363791329048*_Complex_I, -1.448465724858 + 11.100404880196*_Complex_I, -6.231101627932 + -0.711426629573*_Complex_I, 6.572370237538 + -9.008077010635*_Complex_I, 7.543400860435 + 28.757508480923*_Complex_I, -17.693058117854 + -14.497870123296*_Complex_I, -18.350699894294 + 19.700720310742*_Complex_I, -22.388250522169 + 7.667843634853*_Complex_I, 14.220360999832 + 11.088627215515*_Complex_I, 14.686986747880 + 4.769183572180*_Complex_I, -16.224161466491 + 18.657410968166*_Complex_I, -5.561225898629 + 0.059313803898*_Complex_I, 13.221567254519 + -8.899219750894*_Complex_I, -20.776362788232 + -12.895144971233*_Complex_I, 16.702761314442 + -1.206621684382*_Complex_I, 1.152218624052 + 10.429943215921*_Complex_I, 1.406407090905 + -25.487932735618*_Complex_I, 5.058858691359 + 14.007031493308*_Complex_I, 3.915927218401 + -3.143885706619*_Complex_I, 0.511679691204 + 7.640849778701*_Complex_I, -9.519895102966 + -18.415287292132*_Complex_I, 2.876304518596 + 20.969442045845*_Complex_I, 7.342107433201 + -12.347059316472*_Complex_I, -0.618433952859 + 25.041216941337*_Complex_I, 0.580421597502 + -14.237985250543*_Complex_I, 8.771852508251 + 0.733917062704*_Complex_I, 3.782207555074 + 16.248301038041*_Complex_I, -8.524579539709 + 9.295327847229*_Complex_I, -4.768100090762 + -10.116200145201*_Complex_I, 5.053774488844 + -2.415715341537*_Complex_I, 14.309532012096 + -0.424419688667*_Complex_I, 12.756379146573 + 5.032080306349*_Complex_I, 34.330424118154 + 10.117580842288*_Complex_I, -5.753681073486 + -1.411149381440*_Complex_I, 1.264859359146 + 4.528836925970*_Complex_I, -2.586666114372 + 13.851391335293*_Complex_I, -1.713098457415 + 20.890928009489*_Complex_I, -13.434363693601 + 24.394077211392*_Complex_I, -10.022671324009 + 17.664609245348*_Complex_I, -1.725934813257 + 1.891913667017*_Complex_I, 9.110355361482 + -0.179266402064*_Complex_I, -6.803970453739 + 1.078079859350*_Complex_I, 15.245357404619 + -16.002907380848*_Complex_I, 18.798658922559 + -8.909897678113*_Complex_I, -9.340116247154 + -1.125951004947*_Complex_I, 3.688509570515 + -32.689986273951*_Complex_I, 0.407888797988 + 12.869443175340*_Complex_I, 11.996274048535 + -2.662751606922*_Complex_I, 7.018158515976 + 28.262862824837*_Complex_I, 7.922722654625 + 14.250007388651*_Complex_I, 2.975237590008 + -10.603333565612*_Complex_I, 0.455653895495 + 1.453939650391*_Complex_I, -9.066906825176 + 25.796872875146*_Complex_I, -0.918183225634 + -10.468224002255*_Complex_I, -0.142851335912 + 22.780663054656*_Complex_I, 2.282086213671 + 29.891813625626*_Complex_I, 7.221536839959 + 7.770574674805*_Complex_I, -37.398067728397 + -1.105557754066*_Complex_I, -17.142633714292 + 6.118620955162*_Complex_I, -6.477664567284 + -7.690396365101*_Complex_I, 16.982767357512 + -18.131798098394*_Complex_I, 1.080785945291 + 16.906857138491*_Complex_I, 0.599451587747 + 26.081775902564*_Complex_I, -0.978816302785 + 5.925677319285*_Complex_I, 10.210787997091 + -9.910196007357*_Complex_I, -19.147402098057 + -2.498686289732*_Complex_I, 21.966256137493 + -22.859882129197*_Complex_I, -15.265643040019 + -4.426471861527*_Complex_I, 12.929479693820 + 22.330642231752*_Complex_I, 2.740221347659 + 24.061774049828*_Complex_I, -14.562401185320 + -19.628678597306*_Complex_I, 20.997689192967 + 5.792733814018*_Complex_I, 5.119546713501 + 3.964059886246*_Complex_I, -1.928221405609 + -6.512384434671*_Complex_I, -2.156293329162 + 7.753329775994*_Complex_I, -3.573953149890 + -9.239991326571*_Complex_I, -13.630949945730 + -8.106005746278*_Complex_I, 12.825262070728 + -4.660266138913*_Complex_I, -1.891349427851 + 9.400617516536*_Complex_I, -18.076150879307 + 22.373408216149*_Complex_I, -15.956268983268 + -21.975317374526*_Complex_I, 0.164201332756 + 24.388112510894*_Complex_I, -4.597078387934 + 7.039522987551*_Complex_I, -12.697120797033 + 9.467372419639*_Complex_I, 0.666493946055 + 16.398714904237*_Complex_I, 14.501434995333 + -1.201151824518*_Complex_I, -5.674281705139 + 5.888174371162*_Complex_I, -20.163201241601 + -1.818438322864*_Complex_I, -30.219423076971 + -13.719313314399*_Complex_I, -13.990403694826 + 2.714807784298*_Complex_I, 11.250768761115 + 3.628822569150*_Complex_I, -0.733728572049 + 2.948828784375*_Complex_I, -3.826671819253 + 4.571602216696*_Complex_I, 23.522991447544 + -2.821207413423*_Complex_I, 5.182638636295 + -2.280239804828*_Complex_I, -14.978530389737 + 34.007674915178*_Complex_I, 12.067946114665 + -7.231592873495*_Complex_I, -18.036308190888 + -1.167944458385*_Complex_I, -14.570445828147 + 33.703221498009*_Complex_I, -14.355007896334 + 8.624163479423*_Complex_I, -12.522417307559 + 2.964999959389*_Complex_I, 1.285831266251 + 17.486913574970*_Complex_I, -18.400444537057 + 10.275105944079*_Complex_I, -10.798107010917 + -9.398928074828*_Complex_I, -3.735870933695 + -3.928195596167*_Complex_I, -28.347786532915 + -4.087804201121*_Complex_I, 22.446246894740 + -3.314141727023*_Complex_I, -12.595391479166 + -20.525839403734*_Complex_I, -28.712938572605 + -6.003936755853*_Complex_I, 28.019514492138 + -30.082449455145*_Complex_I, -11.209466775921 + 26.443062244454*_Complex_I, 1.207579305184 + 15.519647647646*_Complex_I, -4.037012632720 + -7.499501325179*_Complex_I, 10.741743378262 + 10.026834979238*_Complex_I, 18.870849049565 + 11.960677218574*_Complex_I, 5.853418449079 + -7.462260554939*_Complex_I, 4.335224360674 + 3.129860437677*_Complex_I, 12.605242126520 + 4.554248036599*_Complex_I, -16.969702130369 + -29.534520407430*_Complex_I, -6.120705955107 + -4.482591730189*_Complex_I, -12.926535006552 + -1.874171675105*_Complex_I, 14.665201057893 + -1.128035925962*_Complex_I, 24.051538767781 + -15.958257482748*_Complex_I, 19.820057240718 + -22.152759047970*_Complex_I, -24.058042894391 + 13.729789221856*_Complex_I, 19.182753493650 + -1.045899761274*_Complex_I, 7.427878004795 + -14.645722900400*_Complex_I, 0.354829774210 + -28.351378771571*_Complex_I, -0.079617808212 + 3.973765307882*_Complex_I, -0.956500599215 + -15.489797280577*_Complex_I, 0.762491009085 + -25.453122941666*_Complex_I, -11.840853996701 + 12.962212817110*_Complex_I, 35.495866538641 + 9.686565151838*_Complex_I, -0.038469688004 + 4.392742866312*_Complex_I, -19.123338054473 + 2.775599118392*_Complex_I, -11.096274610813 + 9.852185716742*_Complex_I, 15.297635548840 + -11.871123303123*_Complex_I, -20.554975892285 + 3.876667437210*_Complex_I, 35.623881203832 + -7.111604836972*_Complex_I, -6.116783490647 + 6.858127980009*_Complex_I, 7.214111046309 + -6.503534651808*_Complex_I, 13.222866709925 + 14.222914198476*_Complex_I, 7.177684846410 + 4.449199979110*_Complex_I, 8.704887882540 + 13.440615520893*_Complex_I, 3.880333256992 + -21.379125009121*_Complex_I, 7.048477459126 + -5.798390953651*_Complex_I, -2.887754540526 + 0.926387706089*_Complex_I, -4.738508647891 + 1.592531834771*_Complex_I, -29.140442148645 + 1.326408413819*_Complex_I, -17.686809708344 + 9.306299214767*_Complex_I, -11.287941537086 + 18.573964519700*_Complex_I, -14.430331062949 + 20.500648002089*_Complex_I, 5.833514963456 + -0.787459203485*_Complex_I, 6.996874871331 + 4.372973087460*_Complex_I, 10.606258817386 + -15.371196814824*_Complex_I, 7.173199494850 + -3.739254103514*_Complex_I, 0.650868123207 + 1.129252104053*_Complex_I, 2.934818232673 + -15.452697731691*_Complex_I, 5.965230433753 + 25.063178506013*_Complex_I, 23.622843424435 + -9.618416072703*_Complex_I, 7.156185469219 + 3.585963809070*_Complex_I, -5.732158086481 + -13.452361329340*_Complex_I, -9.590479206366 + -9.053169128213*_Complex_I, 2.000269872570 + -9.513605072784*_Complex_I, 11.315627899677 + 22.817996942644*_Complex_I, 12.413894814140 + 13.626175038709*_Complex_I, 29.172874942325 + 1.484706508481*_Complex_I, 0.015766090270 + 4.368571218197*_Complex_I, 15.563774953007 + 4.894512943893*_Complex_I, -11.842691536265 + 35.592965762670*_Complex_I, -12.994473369362 + 2.698888313132*_Complex_I, 8.754669228150 + 11.235443005907*_Complex_I, -10.328265749913 + 2.323163803747*_Complex_I, -13.439572075998 + 13.889640848681*_Complex_I, -3.977518922953 + 0.690204512797*_Complex_I, -10.800653995412 + -6.554357023667*_Complex_I, -11.525124988298 + -20.660565069742*_Complex_I, 19.162721444200 + 9.408214211732*_Complex_I, -0.088361438150 + -0.665881998403*_Complex_I, -18.557501816859 + -12.065202621962*_Complex_I, 8.534483256201 + 9.270859667546*_Complex_I, 10.095451307996 + -11.066538969502*_Complex_I, -21.844145113512 + -28.094981179422*_Complex_I, -19.202996015641 + 7.054377546211*_Complex_I, -15.529186020599 + 7.476299951687*_Complex_I, -18.157842430552 + -5.316780213393*_Complex_I, -5.293208686973 + -3.663831551237*_Complex_I, 10.661425533836 + 11.243445036012*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_2.c000066400000000000000000000026741474751757600214100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 2-point transform // #include float complex fft_test_x2[] = { -0.442695266914 + -1.176601139920*_Complex_I, 0.164300702210 + 0.941269951205*_Complex_I}; float complex fft_test_y2[] = { -0.278394564704 + -0.235331188715*_Complex_I, -0.606995969123 + -2.117871091124*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_20.c000066400000000000000000000063071474751757600214650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 20-point transform // #include float complex fft_test_x20[] = { -0.138174469322 + -0.274748504122*_Complex_I, -1.227476709426 + 0.905279873773*_Complex_I, -0.940584818722 + -0.463678927507*_Complex_I, -0.327372793730 + 0.441537277752*_Complex_I, 0.086812488375 + 1.122322318862*_Complex_I, -0.100645730164 + -0.142102548176*_Complex_I, -0.339607323410 + -0.632982556339*_Complex_I, -1.122342071583 + -0.361529677196*_Complex_I, -0.394764118785 + 1.317868322379*_Complex_I, 0.885025645922 + 0.277662260330*_Complex_I, -0.937809434341 + -0.464711897028*_Complex_I, -0.316998490158 + 0.688777215432*_Complex_I, 0.649526607014 + 0.181558179235*_Complex_I, 0.780299241568 + -0.070192359053*_Complex_I, 1.932600474030 + -0.136400805574*_Complex_I, -0.216121187682 + -0.461249755715*_Complex_I, 0.926223942818 + -0.028529590209*_Complex_I, 1.602135289481 + 1.434596371731*_Complex_I, 1.623836928491 + -1.265873017618*_Complex_I, 1.568843067308 + -0.364404259258*_Complex_I}; float complex fft_test_y20[] = { 3.993406537683 + 1.703197921701*_Complex_I, 3.008874212687 + 7.663142996950*_Complex_I, -1.159042365700 + 3.282695683450*_Complex_I, 0.903124379379 + 1.428002755716*_Complex_I, -1.572075523393 + 4.283883169775*_Complex_I, 2.253301421641 + 2.928788716985*_Complex_I, 3.534976344610 + 2.383761115026*_Complex_I, 1.326813143543 + 3.111834244207*_Complex_I, -3.988701280111 + -0.677308408606*_Complex_I, -1.984004176890 + -4.401380983625*_Complex_I, 0.942714014611 + -2.993550877540*_Complex_I, 2.448617718798 + -1.195359461640*_Complex_I, -3.328697057289 + -4.221639306000*_Complex_I, 4.287827550431 + 1.139111429335*_Complex_I, -4.013398939947 + -0.677595378939*_Complex_I, -2.670924173537 + 7.635447143438*_Complex_I, -2.067686784436 + -7.802196902076*_Complex_I, -1.972088145081 + -6.957222482710*_Complex_I, -3.101333982661 + -2.675851028288*_Complex_I, 0.394807719219 + -9.452730429599*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_21.c000066400000000000000000000064531474751757600214700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 21-point transform // #include float complex fft_test_x21[] = { -0.292459060095 + -0.918931582987*_Complex_I, -1.517033866291 + -0.323416256164*_Complex_I, -1.482752904272 + 0.244611310478*_Complex_I, 0.319915998225 + -0.315947516079*_Complex_I, -0.304653265396 + 1.887596128705*_Complex_I, 0.411043591735 + -0.374178478358*_Complex_I, 0.462233294747 + 0.181705549666*_Complex_I, -0.053584030277 + -1.645170622140*_Complex_I, -0.503521485275 + 0.734911625473*_Complex_I, -0.425967471739 + 0.316306288806*_Complex_I, 0.824866046500 + -0.830071277629*_Complex_I, 1.806337286696 + -0.766132673126*_Complex_I, 0.620721751355 + 0.965491952308*_Complex_I, -2.440640280723 + -0.836336433610*_Complex_I, -0.620347474921 + -1.385103078296*_Complex_I, -0.195316065403 + 0.051333260777*_Complex_I, -0.448853815719 + 1.473820485114*_Complex_I, 0.468718174491 + -0.133593056210*_Complex_I, -0.912579674279 + 0.093239456860*_Complex_I, -0.060107647935 + -1.182219308121*_Complex_I, -1.630393758159 + -1.763218511036*_Complex_I}; float complex fft_test_y21[] = { -5.974374656733 + -4.525302735571*_Complex_I, -3.602445825195 + -3.324518378407*_Complex_I, 1.072414517043 + -2.680697729601*_Complex_I, -2.544321267300 + -3.718686381182*_Complex_I, 7.073007677928 + -0.865187973747*_Complex_I, -4.293690988707 + 8.225140969655*_Complex_I, 6.571053045547 + -6.857090522238*_Complex_I, 4.072721192387 + 4.943421889232*_Complex_I, 0.156147391740 + -4.066681194313*_Complex_I, -0.307481517626 + -5.479113972476*_Complex_I, -3.514186056563 + 2.187768615743*_Complex_I, 6.761786041122 + 2.434424093260*_Complex_I, 6.161936098710 + 2.932845658178*_Complex_I, -0.983132976608 + 2.475188613552*_Complex_I, 0.631299782782 + 0.701473074392*_Complex_I, -0.667672994573 + -2.853889888582*_Complex_I, -1.447661658880 + 2.115483689466*_Complex_I, 4.415160634353 + 1.955631737971*_Complex_I, -10.003872665072 + -7.143199142087*_Complex_I, -2.863331203221 + -6.794540372208*_Complex_I, -6.854994833120 + 1.039966706231*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_22.c000066400000000000000000000066171474751757600214730ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 22-point transform // #include float complex fft_test_x22[] = { 1.005393906711 + 1.012308570546*_Complex_I, 1.688071880070 + 1.150240841419*_Complex_I, 0.683345289428 + -0.062623351865*_Complex_I, 0.155361503274 + -0.795786088580*_Complex_I, -1.820284248422 + 1.218801819999*_Complex_I, 0.628547514320 + -0.973049954879*_Complex_I, 1.065280228237 + 0.036573157841*_Complex_I, -2.060385212897 + 0.046192542979*_Complex_I, -1.013657698873 + 0.781474907362*_Complex_I, 0.375646814842 + 1.554324770487*_Complex_I, 0.891369658302 + -0.161096019710*_Complex_I, -1.068796361214 + 0.437936260633*_Complex_I, 2.551818984217 + -0.855823653619*_Complex_I, 1.902986665335 + 0.173617409071*_Complex_I, 0.782297326663 + 1.157416587734*_Complex_I, 1.408853663828 + -0.360396487397*_Complex_I, -1.133068299545 + 0.494376224047*_Complex_I, -0.644483632405 + -0.024946520734*_Complex_I, -1.906331676937 + 0.114276645380*_Complex_I, -0.607040125764 + 0.926527519920*_Complex_I, 0.405414441208 + 0.272172965895*_Complex_I, 0.522244149054 + 0.024648904750*_Complex_I}; float complex fft_test_y22[] = { 3.812584769431 + 6.167167051279*_Complex_I, -2.048551145080 + 1.920025824226*_Complex_I, 6.865239600362 + -6.254294174522*_Complex_I, 6.680188302485 + 7.175301698042*_Complex_I, 0.336985685391 + -2.472221525673*_Complex_I, 2.704578846644 + -1.072297553521*_Complex_I, -5.869735761695 + 0.406925054472*_Complex_I, 7.260505946731 + 4.415111182242*_Complex_I, 1.284910248555 + -1.935024971881*_Complex_I, 1.066939615916 + -8.084240769565*_Complex_I, -5.103441669518 + 4.459170611366*_Complex_I, -0.789428947455 + 1.848548655941*_Complex_I, -2.925771543223 + -0.333175332942*_Complex_I, 8.231473045218 + -1.322435498403*_Complex_I, -2.591866662060 + 5.216079561352*_Complex_I, -0.164183264077 + -4.464934113704*_Complex_I, -10.152302601435 + 2.776060476179*_Complex_I, -1.546651996340 + 8.030006620400*_Complex_I, 2.238990051464 + -2.081025590453*_Complex_I, 2.420796442681 + -1.572310054104*_Complex_I, 11.406980883199 + 10.003031983787*_Complex_I, -0.999573899550 + -0.554680582506*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_24.c000066400000000000000000000071271474751757600214720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 24-point transform // #include float complex fft_test_x24[] = { -1.420307293620 + 0.936847943063*_Complex_I, -0.496969771953 + 0.590714565032*_Complex_I, -1.354677361467 + -2.010032405560*_Complex_I, -0.345483299359 + 0.404926987051*_Complex_I, 0.689486222452 + -0.768259750193*_Complex_I, -1.549641684121 + -0.858118594125*_Complex_I, 0.420175234777 + -0.280408837681*_Complex_I, -2.217262854791 + -0.375004631542*_Complex_I, -1.198653374297 + 0.900261122326*_Complex_I, 0.329725819477 + 0.014746627154*_Complex_I, 0.045545673584 + -0.712071131515*_Complex_I, -0.495265874931 + -0.922857927267*_Complex_I, 0.628733326629 + 0.643883091672*_Complex_I, 0.331696680042 + -1.105791987558*_Complex_I, 0.515399107713 + -0.438177945625*_Complex_I, 0.183533661425 + -0.031372217136*_Complex_I, -0.276753781687 + 0.187288341292*_Complex_I, 0.177067067896 + -0.017072068523*_Complex_I, -0.269294774259 + 0.299567125253*_Complex_I, 0.691280106543 + -0.285429769347*_Complex_I, -0.478959763653 + 0.592471601549*_Complex_I, 0.731469600041 + -1.116061252131*_Complex_I, 0.506952261982 + -1.310440154883*_Complex_I, -0.131823537621 + 1.440176198054*_Complex_I}; float complex fft_test_y24[] = { -4.984028609200 + -4.220215070640*_Complex_I, -4.250507506099 + 6.724208699822*_Complex_I, 0.057360770043 + 0.512716211712*_Complex_I, -3.908279516708 + 6.693724296623*_Complex_I, -1.890450979255 + 6.088953815148*_Complex_I, -1.373512942118 + 4.739496879303*_Complex_I, -4.642576156472 + 5.105686189601*_Complex_I, -2.584328440882 + 1.728098263528*_Complex_I, 0.744531943959 + 0.135606499920*_Complex_I, -0.971959807211 + -7.134164325953*_Complex_I, 0.738417588646 + -0.940988007706*_Complex_I, -0.528146358843 + -0.272559882858*_Complex_I, 0.599319565507 + 0.302073070033*_Complex_I, -3.856916042162 + -10.635041786616*_Complex_I, -5.293262572847 + -3.982011344991*_Complex_I, -4.348687900619 + 2.460786763911*_Complex_I, 5.015153490569 + 6.700996972453*_Complex_I, 0.389766514080 + -0.278393532462*_Complex_I, 0.801466543459 + 8.782425209839*_Complex_I, 3.623555226700 + -0.026142755609*_Complex_I, -3.328686450422 + 0.591920646925*_Complex_I, -5.710969715584 + 4.204863120029*_Complex_I, 2.683867262111 + -0.108391775481*_Complex_I, -1.068500953539 + -4.689297523031*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_26.c000066400000000000000000000074371474751757600215000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 26-point transform // #include float complex fft_test_x26[] = { -1.513790990128 + 0.450104660529*_Complex_I, -0.609587704775 + 0.200963343771*_Complex_I, 1.150854971928 + -0.979670346844*_Complex_I, 0.676761753784 + -0.390760850862*_Complex_I, 0.025326431025 + 0.226613394038*_Complex_I, -0.877894422758 + 0.377687762743*_Complex_I, 0.016945667503 + -0.414424826825*_Complex_I, 0.671396901344 + 1.014597796222*_Complex_I, 1.620562100771 + -0.445584464270*_Complex_I, -0.621912682345 + 0.523347355420*_Complex_I, -1.722706628967 + -1.473722873869*_Complex_I, 1.604125850850 + -0.595523792175*_Complex_I, 2.695969244871 + -0.740444785313*_Complex_I, -1.837539349404 + -0.402987576873*_Complex_I, 0.643703593669 + -0.530984627964*_Complex_I, 0.745985203740 + -1.158124796569*_Complex_I, 0.492860315079 + 0.183477887101*_Complex_I, -0.715219690752 + -0.979086251385*_Complex_I, 0.179883358483 + 0.236135674483*_Complex_I, 0.196402574786 + -1.059380996958*_Complex_I, 0.069933652344 + 0.829344522775*_Complex_I, 0.325146685501 + -1.266467132602*_Complex_I, -1.839777223485 + -0.327473446299*_Complex_I, 1.778506841624 + -1.571433253340*_Complex_I, 1.002599293378 + 0.297630901673*_Complex_I, -1.821267785996 + 1.027493831629*_Complex_I}; float complex fft_test_y26[] = { 2.337267962069 + -6.968672891765*_Complex_I, -1.374144569280 + 2.440460452235*_Complex_I, 0.293963382503 + -1.014603415840*_Complex_I, -5.808647515741 + 2.932080281412*_Complex_I, -3.954391977726 + 4.050421232706*_Complex_I, -10.434029005073 + -2.430379478773*_Complex_I, -14.396971442054 + 7.561455425624*_Complex_I, 4.801073402095 + -7.297832464880*_Complex_I, -6.451827528493 + -1.778154888801*_Complex_I, 7.694740702469 + -3.586296872724*_Complex_I, 0.830361317715 + -4.000025563805*_Complex_I, 2.193823341792 + 2.627715132519*_Complex_I, 5.557050661872 + 3.023112572307*_Complex_I, 3.307459610871 + 1.590676230192*_Complex_I, -12.118932653799 + -2.054113664628*_Complex_I, 5.893155083845 + -6.130479717222*_Complex_I, 1.236890091413 + -1.250300895885*_Complex_I, 6.703265906214 + 0.834044438577*_Complex_I, -7.565202099594 + 2.208332250508*_Complex_I, 3.230245599909 + 6.555949348851*_Complex_I, -7.293883944894 + -3.228615872305*_Complex_I, -4.814526866453 + 4.783901741180*_Complex_I, -0.579907911716 + 5.262229129419*_Complex_I, -0.768605942699 + 3.726121287503*_Complex_I, -1.461710271209 + -1.198541330006*_Complex_I, -6.415081077369 + 5.044238707360*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_3.c000066400000000000000000000030401474751757600213750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 3-point transform // #include float complex fft_test_x3[] = { -0.757661328095 + 0.655250200055*_Complex_I, -1.262964116539 + 0.804288531547*_Complex_I, 0.075727215016 + -0.825503865060*_Complex_I}; float complex fft_test_y3[] = { -1.944898229617 + 0.634034866542*_Complex_I, 1.247398741022 + 1.825198567765*_Complex_I, -1.575484495691 + -0.493482834141*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_30.c000066400000000000000000000102571474751757600214650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 30-point transform // #include float complex fft_test_x30[] = { 1.383958311928 + 1.009063372834*_Complex_I, 0.656943839727 + -0.201492142788*_Complex_I, -1.263185461543 + -0.762235271683*_Complex_I, -0.279286295800 + 0.737833309276*_Complex_I, 0.061984731638 + 0.232640465778*_Complex_I, 0.078974781535 + 0.151163978562*_Complex_I, -0.067264854607 + -1.701011326832*_Complex_I, -2.367250035232 + -0.675654408115*_Complex_I, 0.901831068347 + -2.291740807507*_Complex_I, -0.685180193104 + 0.640309251420*_Complex_I, -0.865870302577 + -0.234993063029*_Complex_I, 0.394411867502 + -1.629554965527*_Complex_I, -0.163205564173 + 0.199656642882*_Complex_I, 0.561129126184 + 2.875025531619*_Complex_I, -1.191762025326 + 0.544473782291*_Complex_I, 0.808768695645 + 1.055445062240*_Complex_I, -0.145391531392 + -0.095884441741*_Complex_I, 1.006538762836 + -0.724775764669*_Complex_I, 2.116364610835 + -2.412759658708*_Complex_I, 0.210526780948 + 1.338479312378*_Complex_I, 0.722177277886 + 1.447742766425*_Complex_I, 0.148533332865 + 0.262381546261*_Complex_I, -1.337190861421 + 1.251733062365*_Complex_I, -0.346555962201 + -0.012481387193*_Complex_I, 1.400932749094 + -0.360556660035*_Complex_I, 0.479524006659 + -0.777208683834*_Complex_I, -0.525976158853 + -0.155146817266*_Complex_I, -1.237887495307 + 0.159614688084*_Complex_I, 0.526429110861 + -1.368405705104*_Complex_I, -0.688995272873 + 0.833548127008*_Complex_I}; float complex fft_test_y30[] = { 0.294027040082 + -0.664790204608*_Complex_I, -7.251086654153 + 1.930700457878*_Complex_I, 4.192769230897 + 1.789725983362*_Complex_I, 11.197367573831 + 3.254783235859*_Complex_I, -10.053118996304 + -1.739286933243*_Complex_I, 10.012405959748 + -4.383419562391*_Complex_I, -1.293134786584 + 8.917417869363*_Complex_I, 3.828158834339 + 7.240756714477*_Complex_I, 2.213781017086 + -3.491740260928*_Complex_I, -11.803330439118 + 1.771364969478*_Complex_I, 9.272563287802 + 0.848929030951*_Complex_I, -0.497098653141 + -0.996109950789*_Complex_I, -3.419412966566 + -7.252273855897*_Complex_I, -3.013334143526 + -1.690385014079*_Complex_I, 8.340586193744 + 1.433397080247*_Complex_I, 2.813635161314 + -8.730057114052*_Complex_I, 0.460908379865 + 1.518681481090*_Complex_I, -5.717851959043 + -2.820174393000*_Complex_I, 8.168927986272 + 11.157813415293*_Complex_I, 2.879730739941 + 1.551007915618*_Complex_I, 0.710609564242 + -1.414210144075*_Complex_I, 5.664928404839 + 12.624792285877*_Complex_I, -4.559435692794 + 5.128817112052*_Complex_I, 3.020061485600 + 2.317084746039*_Complex_I, 9.287256582183 + 1.097899941841*_Complex_I, 4.921470505274 + -5.250097784974*_Complex_I, 5.775306053035 + 5.396588308077*_Complex_I, -8.507611683876 + 0.041180219148*_Complex_I, 3.499272220645 + 8.240657702592*_Complex_I, 1.080399112219 + -7.557152066173*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_317.c000066400000000000000000001003161474751757600215510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 317-point transform // #include float complex fft_test_x317[] = { 0.554097588235 + 0.674837317416*_Complex_I, 0.530737753317 + -0.079409691311*_Complex_I, 0.132225792019 + -2.683942671459*_Complex_I, -0.433831796385 + -0.644436889896*_Complex_I, 0.531193579547 + -0.234132120154*_Complex_I, 0.372970050685 + 0.234590738463*_Complex_I, 0.469189910453 + 1.347839137560*_Complex_I, 1.407357556116 + -0.732654574714*_Complex_I, -0.892419998715 + 1.232301421325*_Complex_I, -2.097695896055 + 0.374300022370*_Complex_I, 0.841647143326 + 1.509643189344*_Complex_I, 2.033126977287 + -0.280107016121*_Complex_I, 0.436605233661 + -0.542582266432*_Complex_I, -0.564143476179 + -1.316474379263*_Complex_I, 1.205813790177 + 0.314460438693*_Complex_I, -0.290370012573 + -0.142559201647*_Complex_I, 0.389754456864 + 0.846145131479*_Complex_I, 1.072733277575 + 0.217097105341*_Complex_I, -0.530701360675 + 0.621669741612*_Complex_I, -0.747465971012 + -1.217065085995*_Complex_I, 0.285811246522 + -0.575506757253*_Complex_I, 1.731868270921 + -1.695420723201*_Complex_I, 2.062026927380 + -0.467312976619*_Complex_I, -0.238522083883 + 0.733481847031*_Complex_I, 0.962605683108 + -0.932743731262*_Complex_I, -0.244109153061 + 0.048909057472*_Complex_I, -0.521908701077 + -0.335290348825*_Complex_I, -0.224377634061 + 0.812682493510*_Complex_I, -0.808168093175 + -2.606743537297*_Complex_I, -0.383229234780 + 0.204386340920*_Complex_I, -1.604057984500 + 0.282386325516*_Complex_I, 1.123689375175 + 0.294576201783*_Complex_I, 1.045506847212 + 0.558518419936*_Complex_I, 0.444874000589 + 0.832776075751*_Complex_I, 0.381774427538 + 0.783400026120*_Complex_I, 0.591805517099 + 0.899143948342*_Complex_I, 0.995508244414 + -0.835798382940*_Complex_I, -2.173146523457 + 0.954135191444*_Complex_I, 2.429109028004 + 0.404032043829*_Complex_I, -0.642851155627 + -0.253033059825*_Complex_I, -0.960201285491 + -0.932974674369*_Complex_I, 0.052794955676 + 0.070183835184*_Complex_I, -0.122786042744 + 0.417387287207*_Complex_I, 0.200201640049 + -0.342343750496*_Complex_I, 0.152601120150 + 0.746938165561*_Complex_I, -0.720582709452 + 1.464296507060*_Complex_I, 0.286243449065 + -0.356130710199*_Complex_I, -0.855441109470 + 0.260173089323*_Complex_I, 1.241960323905 + -1.220424835146*_Complex_I, 0.410436718259 + -0.915784426815*_Complex_I, -0.608754986761 + 1.196797063902*_Complex_I, 0.842595164718 + 1.776375320466*_Complex_I, 0.461313891161 + 0.132552548247*_Complex_I, -1.038934516657 + -0.503009712801*_Complex_I, -0.174516309894 + -1.414963943166*_Complex_I, -1.312041533200 + 0.350893580013*_Complex_I, 0.208956667743 + -0.958786287939*_Complex_I, 0.803660420194 + 1.011070131954*_Complex_I, 2.165017913712 + -1.468093310734*_Complex_I, 1.129645943719 + 0.537365498647*_Complex_I, -1.595984272966 + -0.203122161061*_Complex_I, 1.001865195124 + -1.388137201018*_Complex_I, 0.824523455412 + 0.399895307714*_Complex_I, 1.390174301291 + 2.631574565038*_Complex_I, -0.950205283612 + -1.131255194597*_Complex_I, 1.905487211032 + -0.077934597969*_Complex_I, 1.003876696894 + -0.060334922974*_Complex_I, -0.739566795906 + -0.125966238551*_Complex_I, 0.638862295532 + 0.312440320520*_Complex_I, 0.812688518156 + -0.687832384174*_Complex_I, -0.247460071939 + 1.506637100983*_Complex_I, 1.119835012306 + 1.284530437377*_Complex_I, 0.514075655596 + 0.315432575412*_Complex_I, -0.556581507109 + -2.240098527759*_Complex_I, 0.249592136667 + 0.505876736625*_Complex_I, 0.138808728752 + -0.362938299441*_Complex_I, -1.295018476090 + -0.498162870507*_Complex_I, 0.633165144610 + -1.395172629954*_Complex_I, 0.932960550573 + -0.237180627122*_Complex_I, 1.661895463725 + 0.690503082347*_Complex_I, 0.333824445072 + -1.788741666587*_Complex_I, 0.489887999458 + -0.706548054495*_Complex_I, -0.548551848905 + 0.898884888429*_Complex_I, -0.608101416118 + -0.201679435156*_Complex_I, 0.890886957534 + -0.480205878554*_Complex_I, -0.000052987921 + 0.753051843488*_Complex_I, -2.008688335321 + -0.531405355010*_Complex_I, 0.178224821311 + 0.093166214057*_Complex_I, -1.028365245165 + -0.852475963885*_Complex_I, 0.686303677542 + 1.543109809415*_Complex_I, 1.711982713732 + -0.058899888612*_Complex_I, 1.120881384941 + 0.023773370634*_Complex_I, 0.452547007139 + -0.345550830853*_Complex_I, 0.851642145828 + 0.918449585078*_Complex_I, 1.354411836149 + 0.053840956523*_Complex_I, 0.186505302140 + 0.455350659118*_Complex_I, 1.178867803924 + 0.561242592990*_Complex_I, -0.867274007830 + 0.778369347385*_Complex_I, -0.763210306046 + -0.056553236256*_Complex_I, -0.925493602469 + 1.802123360882*_Complex_I, -0.381880717193 + 0.836790955039*_Complex_I, 0.740584915503 + 0.410451383495*_Complex_I, -1.739773756173 + -0.008392421431*_Complex_I, -0.927812449353 + 0.225621894111*_Complex_I, 0.291685537968 + -0.631710150727*_Complex_I, 1.044752342554 + -0.921336822198*_Complex_I, 0.379926674636 + 0.104269280376*_Complex_I, -0.747794397492 + -1.586409810217*_Complex_I, -0.707471806222 + -3.451349626151*_Complex_I, -0.610242217287 + -0.050520690817*_Complex_I, -1.141609802996 + -0.450890109498*_Complex_I, -0.110600652376 + 0.711135784835*_Complex_I, -2.154140310955 + -0.464833145767*_Complex_I, 2.215673027150 + 0.378163057373*_Complex_I, -0.654346983910 + -0.446467309237*_Complex_I, 0.054883600089 + -0.699447750344*_Complex_I, 0.806739839269 + 0.085857123252*_Complex_I, -1.606523541279 + 0.816575059374*_Complex_I, 0.592874861350 + -0.160053556472*_Complex_I, -0.487687814535 + 2.062004006591*_Complex_I, -0.494854876646 + 1.222171460716*_Complex_I, 1.143598578272 + -0.256116050124*_Complex_I, 2.400451006261 + -0.615247709498*_Complex_I, 1.794972603823 + 0.061326347413*_Complex_I, -1.785033202582 + 1.285030637182*_Complex_I, 0.952408789671 + -0.061111017884*_Complex_I, 0.045375503932 + -0.337506966204*_Complex_I, 0.098933506757 + 1.552870310423*_Complex_I, -0.114562876521 + 0.289943289341*_Complex_I, -0.283731751338 + -0.946113439136*_Complex_I, 0.461130821204 + 0.048895395259*_Complex_I, -1.174095369155 + 0.023986190137*_Complex_I, -0.098711272023 + 0.155133236840*_Complex_I, 1.644296831488 + -0.763890180558*_Complex_I, -0.598417564337 + -0.286264760137*_Complex_I, 0.526726895394 + 1.073518895905*_Complex_I, -0.853228628205 + -1.282488324989*_Complex_I, -1.020706122357 + 0.248901790873*_Complex_I, 1.313386656293 + 1.883626375861*_Complex_I, -0.596968080006 + 1.198886796626*_Complex_I, -1.090527229732 + 1.322486318068*_Complex_I, 0.055643681240 + -1.476648993263*_Complex_I, -0.134166277120 + 0.538780165850*_Complex_I, -0.394194728658 + 0.287017836253*_Complex_I, 0.451499019863 + 0.196444291722*_Complex_I, -1.227900659262 + 0.066951464777*_Complex_I, 0.281655958102 + 0.477082252845*_Complex_I, 1.584578121348 + 2.263167026855*_Complex_I, -0.337702889133 + -1.675522983729*_Complex_I, -1.262293072370 + 0.295093464675*_Complex_I, -1.466903736895 + 0.492057686013*_Complex_I, -1.485463891249 + 1.082857775981*_Complex_I, -0.275569696975 + -0.635382067043*_Complex_I, 1.705596337300 + 2.104558859516*_Complex_I, 0.704228406430 + 1.560694307633*_Complex_I, 0.940747890984 + 0.080075753674*_Complex_I, -0.671195049979 + -0.305225546505*_Complex_I, 1.351213152915 + -0.159424965469*_Complex_I, -0.168781019368 + 0.642571757925*_Complex_I, -0.431378015911 + -0.017150397606*_Complex_I, 0.084141441624 + 0.021065037620*_Complex_I, -0.464340239256 + -0.192995496761*_Complex_I, -1.333718595841 + -0.017151207176*_Complex_I, 1.699781888517 + 1.611185583580*_Complex_I, -0.413570253776 + -0.044257707528*_Complex_I, 2.258631378215 + -0.166004542094*_Complex_I, -0.465389665786 + 0.871749883624*_Complex_I, 1.029189363291 + 0.713498194652*_Complex_I, -0.094915760832 + -1.625030317385*_Complex_I, -1.232066038521 + -0.607872994844*_Complex_I, 1.502005331699 + -0.020525271340*_Complex_I, -0.683321223012 + -0.293225147764*_Complex_I, -0.907670613167 + -0.107969897144*_Complex_I, 0.462429724200 + -0.775625444256*_Complex_I, -1.205101490966 + -0.132384994859*_Complex_I, -1.179628062446 + 2.189754291494*_Complex_I, -0.631509862810 + 1.222985676196*_Complex_I, 0.789563515020 + 0.698677701769*_Complex_I, 1.687609752565 + 0.400827580780*_Complex_I, -0.645610608306 + -0.014606261491*_Complex_I, -1.361740989948 + -0.117827247124*_Complex_I, 1.314229682964 + -0.603800894199*_Complex_I, -1.956380418062 + 1.043229034913*_Complex_I, -0.801537986631 + 2.532651178906*_Complex_I, -2.386565797106 + -1.098115563132*_Complex_I, 0.220407348326 + -1.279188578233*_Complex_I, -0.692180379497 + 0.560515689944*_Complex_I, -0.356604504521 + 0.793303202093*_Complex_I, -0.159496968171 + -1.294766371488*_Complex_I, 1.198119217621 + -1.994862046372*_Complex_I, -0.568527073111 + 0.401071277388*_Complex_I, 2.987226058138 + -0.073884662975*_Complex_I, 1.799586418676 + -0.574490253290*_Complex_I, 0.011347684988 + -0.745307885407*_Complex_I, 0.729683796427 + -1.060721735894*_Complex_I, -1.966760785708 + -0.605669511192*_Complex_I, 1.142741187156 + 0.019297308388*_Complex_I, -1.561621247893 + -0.095007722087*_Complex_I, 0.336572557763 + -0.651058510390*_Complex_I, 0.040766936719 + 1.217219328749*_Complex_I, 0.200903662048 + 0.393373958513*_Complex_I, -1.236464108144 + 0.541280738924*_Complex_I, 0.117909377974 + -0.607773139351*_Complex_I, 0.379616825601 + -0.643186918605*_Complex_I, 0.643537081891 + 0.275436892658*_Complex_I, 0.225873382688 + -0.158194256053*_Complex_I, 0.053176096756 + 1.458472268368*_Complex_I, 1.414145044178 + -0.733638770750*_Complex_I, 1.347289531912 + 0.169321860659*_Complex_I, -0.840384203303 + 0.763005504852*_Complex_I, 1.214072735988 + 1.485891717688*_Complex_I, -0.348223438412 + 1.020459174171*_Complex_I, 0.073882541886 + -0.905791314139*_Complex_I, -0.705446913782 + 0.056186574618*_Complex_I, -0.960863041873 + -0.196833332985*_Complex_I, 1.006218030516 + -0.467774405167*_Complex_I, 0.602372049969 + -2.674593305127*_Complex_I, -0.934722056514 + -0.016922494007*_Complex_I, 0.257679561629 + -0.885684235693*_Complex_I, 0.044866947149 + 0.936359293985*_Complex_I, 0.950842198317 + 1.868559062575*_Complex_I, 1.498943799171 + -0.019107821973*_Complex_I, -1.868507034816 + 0.197524971623*_Complex_I, 0.970832401725 + -0.074109462719*_Complex_I, -2.886469419266 + 0.142475981345*_Complex_I, 1.240964551237 + 0.153090872958*_Complex_I, -0.000396756859 + -1.046593294557*_Complex_I, 1.117655103664 + 1.647657701398*_Complex_I, 1.162930856009 + -0.975104959968*_Complex_I, -0.934535360620 + 0.307953402722*_Complex_I, -0.573780565126 + -0.375508524005*_Complex_I, -0.103208834185 + 2.105768262189*_Complex_I, -1.379507684252 + -0.280894989725*_Complex_I, 0.859242654654 + 0.201801911064*_Complex_I, 0.214128192305 + -0.427748749718*_Complex_I, 1.559388133754 + -2.233121573297*_Complex_I, 0.019639327733 + 0.360300645061*_Complex_I, -0.133932495128 + -0.722680847651*_Complex_I, 0.863036773382 + -2.922284619456*_Complex_I, 0.334598761557 + -0.983050027547*_Complex_I, -1.077563482460 + 0.417379502415*_Complex_I, -0.198656810153 + 0.569701104618*_Complex_I, 0.913145816840 + 2.052526155977*_Complex_I, 0.854066622796 + -0.413714533361*_Complex_I, -0.414380668765 + -1.405489197548*_Complex_I, -1.110627741502 + -1.820107908459*_Complex_I, -0.613940194705 + 1.779435308312*_Complex_I, -2.105251634607 + 0.525272681631*_Complex_I, 0.609098015750 + -0.895402748194*_Complex_I, 1.934336563550 + 0.543860167180*_Complex_I, -0.782446497605 + 0.641226314552*_Complex_I, -0.955134630524 + -0.077175268361*_Complex_I, -0.210873574493 + -1.715168716896*_Complex_I, 1.628059930554 + -1.533301168339*_Complex_I, -1.421933758706 + -0.241187651806*_Complex_I, 2.187891215143 + -0.023407875710*_Complex_I, 0.548885995861 + 0.285435244871*_Complex_I, 0.674430997216 + -0.481078429799*_Complex_I, 0.397489182610 + -0.446320110483*_Complex_I, -0.865204055951 + -0.020571209344*_Complex_I, -0.155857632710 + -1.473838050536*_Complex_I, -0.825650581473 + 0.501060420785*_Complex_I, 0.506220809313 + 1.124359364738*_Complex_I, 0.199383983129 + 0.552775919340*_Complex_I, -0.675785644869 + -0.015515289402*_Complex_I, 0.347119071389 + -0.046308125867*_Complex_I, -0.580411900444 + 0.473043358519*_Complex_I, -1.073929642005 + -1.146130174539*_Complex_I, -1.137495899690 + -1.309784871827*_Complex_I, 1.171486989096 + 1.823857109273*_Complex_I, -0.742946853968 + 0.049703242746*_Complex_I, -0.160432289828 + 1.724103887278*_Complex_I, -0.546035353551 + 0.386968779514*_Complex_I, -1.213047883956 + -0.537389928129*_Complex_I, -1.339236442910 + -1.248701576327*_Complex_I, -0.815367922604 + 0.085728302177*_Complex_I, -2.349193819868 + 0.427831727302*_Complex_I, -0.276194199790 + 1.234485714534*_Complex_I, -0.355231570763 + -0.995816467388*_Complex_I, 1.137208262430 + 0.216271557004*_Complex_I, 0.962040804090 + -1.065610794498*_Complex_I, -0.668324382362 + 0.822590130460*_Complex_I, -1.202015945307 + -1.480043875470*_Complex_I, 1.179225549720 + 1.767048172045*_Complex_I, -0.684123959923 + -0.862865878982*_Complex_I, -0.174319873616 + 0.167752215701*_Complex_I, -1.446536704664 + 1.172516467428*_Complex_I, 0.858114162859 + 2.295181364008*_Complex_I, 0.124270375245 + 0.997986406329*_Complex_I, 0.394906672949 + 1.154862665198*_Complex_I, 1.053903228740 + 1.779817113028*_Complex_I, -0.230950556520 + -0.175979989611*_Complex_I, -1.265383803223 + -0.026310311336*_Complex_I, 0.762972265227 + 1.429231386216*_Complex_I, 1.162409662447 + -1.112322698285*_Complex_I, 0.775539802471 + -1.323064642721*_Complex_I, 0.666613966503 + -0.129946108336*_Complex_I, 1.930414467502 + 0.436695033239*_Complex_I, 0.885068429064 + 0.115321831962*_Complex_I, 1.551024374006 + 0.416463074882*_Complex_I, 0.247974255137 + 0.627306468118*_Complex_I, 0.781609286510 + 0.378212834621*_Complex_I, 0.332343800329 + 0.539122959506*_Complex_I, 0.519709930109 + -1.064947224271*_Complex_I, -0.635850608190 + 1.257862397877*_Complex_I, 1.628515077193 + -1.103666746889*_Complex_I, -0.849325965524 + -1.767990899186*_Complex_I, 0.743956616560 + -2.505409755963*_Complex_I, 0.830498883146 + 0.057323145873*_Complex_I, -1.470980958211 + -1.558079958147*_Complex_I, -0.088063460329 + 0.426467567974*_Complex_I, -0.219298752127 + -0.711676070690*_Complex_I, -0.283866135348 + 1.254036523517*_Complex_I, -0.254391988290 + 0.215410095075*_Complex_I, -0.590092311740 + -1.507631350024*_Complex_I, -1.535360519901 + -0.437319427483*_Complex_I, 1.026878345705 + -0.182042614613*_Complex_I}; float complex fft_test_y317[] = { 19.891894947904 + 5.655090929781*_Complex_I, 18.838569316919 + -27.216365987549*_Complex_I, -11.140787864820 + -1.700693291107*_Complex_I, 9.248191980131 + -11.880625755527*_Complex_I, 0.877433246927 + 5.210710512463*_Complex_I, 12.613756002695 + -22.914829471885*_Complex_I, -7.522954808149 + 2.580642036625*_Complex_I, -24.806396396859 + 14.114587974426*_Complex_I, 9.875249841730 + -22.004495722041*_Complex_I, -18.222931551932 + 2.572927350772*_Complex_I, 20.867583356509 + -1.458843546852*_Complex_I, 38.916192529134 + -7.826129128685*_Complex_I, -19.618271263978 + -21.217111192894*_Complex_I, 0.549362128526 + 18.584275483073*_Complex_I, -5.258299327834 + -0.446452119776*_Complex_I, -6.830532675831 + -35.800356213084*_Complex_I, 16.124101912097 + -2.387751210287*_Complex_I, 19.602770799308 + -18.449258115561*_Complex_I, -4.933124103618 + 8.281766183665*_Complex_I, -13.560383009984 + 0.970618524872*_Complex_I, 41.610229013366 + 5.152249379736*_Complex_I, 1.415309104711 + 11.210809107531*_Complex_I, -40.441003535705 + -12.405906077032*_Complex_I, -12.530216678354 + 22.864679881966*_Complex_I, -29.573667819723 + -22.154070735316*_Complex_I, -8.933348019353 + -25.720405793092*_Complex_I, -3.072833505067 + 16.874820762270*_Complex_I, -8.751051523099 + -9.544252802963*_Complex_I, 19.619902222112 + -22.765558912475*_Complex_I, 3.204939906092 + -25.426020065167*_Complex_I, -18.600493227238 + 2.762236432333*_Complex_I, 10.833867918922 + -38.070397977737*_Complex_I, 25.869914191964 + -19.192002503531*_Complex_I, 12.052348942398 + -1.338816803484*_Complex_I, -38.656067918699 + -24.135381967263*_Complex_I, 5.700781235700 + 11.219859126000*_Complex_I, -23.338619501120 + 32.607593688928*_Complex_I, -10.686035441793 + 16.337999228208*_Complex_I, -9.517260831300 + 17.469953582495*_Complex_I, 11.452433021422 + -2.244848000851*_Complex_I, 3.355159985201 + -0.950021809091*_Complex_I, 11.960645612996 + 6.893274528846*_Complex_I, 9.585251410761 + 10.141135223678*_Complex_I, -7.050051336892 + 27.613088292755*_Complex_I, 7.367552651770 + -6.006047409882*_Complex_I, 19.902478672101 + -16.730550563777*_Complex_I, 32.759288191850 + 1.162079163303*_Complex_I, -10.679222098466 + -0.414496389670*_Complex_I, -17.167648316558 + 13.231819142930*_Complex_I, -15.270670234876 + 12.750590771914*_Complex_I, 7.808635317834 + -1.976327148026*_Complex_I, 3.659364354893 + 12.967348190608*_Complex_I, 8.516191035487 + -3.814776057042*_Complex_I, -2.967686164798 + -2.759276437723*_Complex_I, -10.217022770046 + 22.446524490020*_Complex_I, -13.759629399132 + 0.428077429397*_Complex_I, 12.108694472460 + 17.906136235301*_Complex_I, 0.500310973628 + 10.379459504754*_Complex_I, 22.170113416067 + -17.601071337137*_Complex_I, -4.547207763897 + 13.535378900333*_Complex_I, 35.073898289289 + -3.750408416097*_Complex_I, 12.960162045071 + -10.329236328497*_Complex_I, 5.155047938611 + 11.233862622741*_Complex_I, -19.366076595616 + 3.290152177759*_Complex_I, -2.547983907745 + -4.318523679571*_Complex_I, 13.079902614417 + -31.788319997011*_Complex_I, -0.294946700028 + 20.014494355305*_Complex_I, 18.602791112148 + -1.875890460773*_Complex_I, -13.396328282272 + 9.288327370031*_Complex_I, -3.117158916891 + 2.544747297232*_Complex_I, 14.226131115223 + 17.462152594662*_Complex_I, -19.578473387664 + 34.411911283259*_Complex_I, -6.579019542175 + 1.022001674347*_Complex_I, 30.972194959263 + -8.350211186911*_Complex_I, -23.959086942588 + -4.745490152344*_Complex_I, 18.433629972547 + 33.672506545950*_Complex_I, -3.583025093477 + 29.006005065761*_Complex_I, -3.421689832344 + -6.516619591564*_Complex_I, 17.468290088683 + 14.351378688148*_Complex_I, -20.170011170114 + -44.394817543067*_Complex_I, -13.150516148634 + 45.749703126153*_Complex_I, -6.345962437499 + 5.896690541701*_Complex_I, -3.508737698320 + 25.459472943049*_Complex_I, -9.590464636095 + -37.162638669309*_Complex_I, -7.707872774343 + -4.065042502767*_Complex_I, 4.310656075828 + 55.425516805330*_Complex_I, -8.841697395726 + 7.827822742296*_Complex_I, 6.538079696486 + 18.790190957680*_Complex_I, 3.052383346750 + -35.409567370640*_Complex_I, 6.790218518127 + 6.485107042363*_Complex_I, -1.939520400173 + 9.749487460014*_Complex_I, 27.335153513982 + -28.544990200718*_Complex_I, 1.310416901033 + -3.384377012660*_Complex_I, 39.882940481275 + -2.284359214074*_Complex_I, 10.547528262920 + -12.560415251324*_Complex_I, -39.735255177309 + 13.592975359455*_Complex_I, -15.339971072116 + -16.475578099072*_Complex_I, 17.033232877918 + 3.802866771597*_Complex_I, 28.013870016133 + 2.419611488016*_Complex_I, -2.265805112454 + 0.312114751003*_Complex_I, -33.149667339304 + -13.689695655857*_Complex_I, 17.388116065076 + 0.542000357078*_Complex_I, 24.899620116312 + -12.668755714836*_Complex_I, 4.917415611451 + -9.932194848538*_Complex_I, -11.738607295144 + -8.914945728892*_Complex_I, -19.712014537454 + 22.399807137247*_Complex_I, 5.053485084584 + 17.298193889941*_Complex_I, -7.079518754159 + 17.581889100321*_Complex_I, -10.281582568059 + 8.089169898931*_Complex_I, 1.422571832929 + 3.080323599470*_Complex_I, 8.605408612244 + -3.487094722779*_Complex_I, -11.890704936363 + 9.663054150701*_Complex_I, 9.768366151498 + 15.851583190991*_Complex_I, 15.643908708786 + -4.022026320351*_Complex_I, -23.153672099048 + 27.718041721476*_Complex_I, -10.673968698682 + -2.656942822276*_Complex_I, -3.084198946373 + 5.011470019270*_Complex_I, 30.294417286976 + -0.649680240512*_Complex_I, 9.336689517258 + -15.513350621571*_Complex_I, -0.332156127181 + 9.028518696767*_Complex_I, -18.028373273009 + 0.865624445339*_Complex_I, 18.478442253114 + -4.603304072176*_Complex_I, -23.690660760663 + 23.776870282847*_Complex_I, 15.985913856353 + -2.839961425057*_Complex_I, 1.572606311668 + -19.612416936799*_Complex_I, 16.810087235424 + 0.199177019879*_Complex_I, -15.975160985564 + 6.532163069799*_Complex_I, -32.272173936218 + -31.217876380070*_Complex_I, 15.826696571154 + 18.609590632164*_Complex_I, 47.902645387609 + 17.126787301492*_Complex_I, -2.541073313860 + 14.418504375704*_Complex_I, 14.540095561207 + 20.121389424019*_Complex_I, 26.277876001597 + -3.644634538637*_Complex_I, -2.512888880479 + -30.538233732588*_Complex_I, 16.529338657188 + 22.345368961768*_Complex_I, -1.812032422371 + -34.161479691113*_Complex_I, -0.453702679159 + -6.380888555304*_Complex_I, -3.152766309700 + -11.666085457234*_Complex_I, -11.122245781125 + -11.927016012323*_Complex_I, 36.608207324428 + 15.883213693451*_Complex_I, -7.991006509076 + 50.985368963626*_Complex_I, 4.226949261924 + 1.424207754420*_Complex_I, 17.463446429822 + 6.779880329142*_Complex_I, -3.489655564559 + 0.384578586369*_Complex_I, -5.888919363255 + -5.109974862115*_Complex_I, -7.227459554733 + 29.423681452522*_Complex_I, -5.599219759541 + -23.600754528481*_Complex_I, -1.449537808914 + -5.756622299277*_Complex_I, -19.475712102355 + -23.900197536654*_Complex_I, -21.448274996924 + 26.188122613033*_Complex_I, -29.449414779539 + 4.514251604734*_Complex_I, 0.711130838156 + 9.386706325613*_Complex_I, -4.964574769823 + 3.355702966205*_Complex_I, -69.341381991121 + -15.186662242307*_Complex_I, -9.570125543135 + -19.565859787554*_Complex_I, -10.294086283004 + 8.398169381304*_Complex_I, -1.885058572468 + -6.759464252726*_Complex_I, 27.070270898380 + -0.178665040288*_Complex_I, 47.866947417745 + -31.409630574884*_Complex_I, -8.921385543048 + 26.098382682234*_Complex_I, -2.790785416910 + 9.787980555385*_Complex_I, -11.714395450184 + 2.331009478742*_Complex_I, -15.110851454222 + -16.495034888485*_Complex_I, 4.191147002221 + 12.009574674807*_Complex_I, 13.441299656087 + -6.566453769009*_Complex_I, 37.589069138284 + -3.493855465671*_Complex_I, 12.583644012597 + 15.635478070296*_Complex_I, -10.233844300260 + -2.537026190645*_Complex_I, 32.544552127969 + -9.371296682693*_Complex_I, 5.840669998388 + -0.465346273045*_Complex_I, -32.889192462170 + -18.684446717050*_Complex_I, -15.105348929262 + 9.854947012189*_Complex_I, 2.561152455963 + -17.413141080242*_Complex_I, 13.746092833724 + -1.220057764138*_Complex_I, -23.803933926504 + 19.459415272545*_Complex_I, 13.809596770429 + -10.104944386386*_Complex_I, -8.303454415515 + 8.117739395766*_Complex_I, 6.133097727305 + -1.569418595484*_Complex_I, -8.760751262525 + -27.389777662710*_Complex_I, 10.131599125171 + 6.687127259801*_Complex_I, -25.519018101480 + 18.199522992831*_Complex_I, -13.233035001671 + -6.395819934405*_Complex_I, 11.700095411690 + -15.584918347062*_Complex_I, 18.906883235021 + -7.460982609320*_Complex_I, -17.459921203210 + 1.804228941706*_Complex_I, 12.317579017635 + 10.356522098016*_Complex_I, 26.023982632040 + -7.991255808237*_Complex_I, -37.779207166301 + -2.527619516503*_Complex_I, -16.084376241401 + -20.612256188135*_Complex_I, -6.114349663136 + -23.064645190863*_Complex_I, -2.116498608238 + 50.021918384600*_Complex_I, -7.117672685723 + -8.176883387504*_Complex_I, -5.412565357343 + 22.014215119309*_Complex_I, 6.088100003823 + -14.490088332571*_Complex_I, -23.952484213391 + -6.311185058243*_Complex_I, -41.692266879065 + -16.754070143984*_Complex_I, 15.044401210058 + 3.664913601471*_Complex_I, -33.750320820834 + 36.019579795022*_Complex_I, 13.347039200739 + -32.112552097269*_Complex_I, -15.461626675606 + 23.718105709185*_Complex_I, -12.296412987482 + 11.603712083795*_Complex_I, -5.811459938628 + -7.925008172416*_Complex_I, -1.192572683531 + -17.231195267270*_Complex_I, -20.865176875222 + -31.216074954599*_Complex_I, -28.168417257904 + -6.162171521961*_Complex_I, 14.071723863194 + -13.359093220787*_Complex_I, -10.855751735127 + -2.119685075188*_Complex_I, 10.100698435956 + -0.047663624125*_Complex_I, -16.742422653794 + -24.530696829578*_Complex_I, 4.000721417241 + -9.851748070066*_Complex_I, 13.784754826511 + 11.502447326859*_Complex_I, 24.102575046761 + 1.552286673184*_Complex_I, 6.070752306643 + -4.812888456253*_Complex_I, -5.300318786685 + -5.773884122203*_Complex_I, 4.177402715108 + 4.644324663894*_Complex_I, -34.005084599492 + 24.853411330269*_Complex_I, -4.077672998994 + 2.001774715846*_Complex_I, -21.978658258889 + -16.888801388499*_Complex_I, 16.217687213434 + 24.308462530919*_Complex_I, 9.698665151728 + -11.152518442318*_Complex_I, -0.713578550754 + -0.408153703877*_Complex_I, -13.404489453311 + -13.338812872852*_Complex_I, 12.438700016349 + 34.570234225070*_Complex_I, -9.926721954129 + 6.906926926113*_Complex_I, 34.152883393921 + 32.217622455379*_Complex_I, 18.232286791872 + 37.874687752978*_Complex_I, 12.000459208850 + -4.948870303603*_Complex_I, -32.687697613521 + -14.030824660001*_Complex_I, 9.549264725873 + -11.955689902942*_Complex_I, 14.839058751293 + -31.933475859189*_Complex_I, -14.754140603346 + -24.878350781691*_Complex_I, 10.712939318393 + -5.996862342613*_Complex_I, -17.907934788390 + 6.090055602127*_Complex_I, 36.124946787489 + -5.830186488894*_Complex_I, 8.800236613602 + -2.072057513781*_Complex_I, 3.437540103841 + 0.664749616099*_Complex_I, 31.950715457487 + -0.220151294656*_Complex_I, -0.045173525280 + 19.196581987850*_Complex_I, 1.870859081457 + -31.599244764015*_Complex_I, 0.209529336033 + 0.187035118051*_Complex_I, -20.188770724804 + -1.836423923991*_Complex_I, -0.878467583840 + 20.234622217282*_Complex_I, -2.102494717199 + -2.913862105328*_Complex_I, -12.424351209312 + 16.006770035694*_Complex_I, 4.029466210003 + -4.407643696893*_Complex_I, 5.945482525641 + 6.202857230453*_Complex_I, -10.003725089675 + 12.495974119472*_Complex_I, -30.517926092302 + -12.650897630264*_Complex_I, 4.362955303417 + -12.091129699738*_Complex_I, 16.312617526910 + 33.224889607577*_Complex_I, -7.191052604298 + 20.407651857657*_Complex_I, 20.796924916343 + -6.364968926767*_Complex_I, -12.625716653882 + 13.205109334295*_Complex_I, 8.088234917787 + 7.824060551408*_Complex_I, 1.922368898588 + 47.121922176668*_Complex_I, -22.856735196688 + 24.367218386007*_Complex_I, -7.383851526948 + 16.988073661561*_Complex_I, 44.161092935665 + -5.907735807977*_Complex_I, 21.472541358807 + -13.144261767738*_Complex_I, -11.542368964090 + 15.544417175199*_Complex_I, 27.503706468722 + -11.522885641815*_Complex_I, 47.558932357808 + 7.448305631246*_Complex_I, 11.766347399663 + 19.611745304561*_Complex_I, 9.190381176578 + 15.613955528574*_Complex_I, 4.579716108010 + -19.097122607568*_Complex_I, 8.259625237826 + 5.225672702106*_Complex_I, -29.407167921996 + 2.730538989362*_Complex_I, 28.823600196176 + 29.176827923246*_Complex_I, 7.192706095305 + -13.060381105412*_Complex_I, 25.710478454828 + 0.151963358956*_Complex_I, 2.912008664120 + -30.634293042262*_Complex_I, -18.887195071024 + 24.458778149068*_Complex_I, -11.270981360031 + 36.740254138082*_Complex_I, -27.910677769149 + -46.983604943585*_Complex_I, 28.541376587410 + -11.613642790751*_Complex_I, 4.477974452509 + 19.232597353019*_Complex_I, -4.293520064043 + 21.064976071666*_Complex_I, -35.598030786598 + 22.993609231670*_Complex_I, 15.465979612020 + -7.083850274044*_Complex_I, -20.864435551224 + -11.252291347107*_Complex_I, -8.098484900823 + 15.454651546399*_Complex_I, 7.922777952587 + -23.004986313444*_Complex_I, 5.362453523073 + -0.810615362821*_Complex_I, 23.691538716715 + 5.018112888735*_Complex_I, -0.840977210667 + 5.291230447587*_Complex_I, -14.732575553595 + 5.007945078325*_Complex_I, 11.153523811020 + 9.041741420055*_Complex_I, 10.332014628129 + -19.924730861837*_Complex_I, -14.993931961657 + 31.489106362903*_Complex_I, 18.595068458053 + -35.418285443670*_Complex_I, 39.450078173463 + 1.995244884889*_Complex_I, -1.199515997336 + -39.429463141214*_Complex_I, 32.594746366756 + 11.337568560792*_Complex_I, 12.403678050012 + -21.176744666160*_Complex_I, 3.346525369966 + -1.001631596928*_Complex_I, -19.825849167391 + 26.742894636469*_Complex_I, 4.915352470909 + 3.753914873323*_Complex_I, 8.679746038045 + -3.972380637551*_Complex_I, -3.287311421377 + 20.200996274143*_Complex_I, 22.907843859952 + 3.994757951688*_Complex_I, 2.844877291610 + -4.339174940613*_Complex_I, 4.103872158917 + -8.872001060599*_Complex_I, 28.989825837444 + -23.300936570044*_Complex_I, -7.955654262813 + 31.438036806524*_Complex_I, -6.389510821525 + -2.868211291181*_Complex_I, 2.583272449361 + -13.352995160958*_Complex_I, -38.239266883463 + 23.653429024344*_Complex_I, 8.079210774309 + 23.697861354779*_Complex_I, -37.713434701568 + 2.799035443775*_Complex_I, -26.751551315717 + 8.673836408974*_Complex_I, -33.613333707208 + -0.367929968698*_Complex_I, -14.541161127911 + -5.708211292132*_Complex_I, -3.393160511476 + -24.278587890684*_Complex_I, 26.111359371252 + -28.934022170518*_Complex_I, 14.009362482345 + -20.358022264859*_Complex_I, 7.316431660011 + 26.887415857021*_Complex_I, 8.199534997352 + -2.435205163079*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_32.c000066400000000000000000000105671474751757600214730ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 32-point transform // #include float complex fft_test_x32[] = { 0.010014623512 + 0.557635892111*_Complex_I, -0.206536736342 + -0.166543150147*_Complex_I, 0.538145349965 + -1.725439447290*_Complex_I, 0.302742823470 + -1.371600938217*_Complex_I, 1.002711341702 + 0.326114543577*_Complex_I, 0.141075699526 + 0.155158151624*_Complex_I, -0.607068327122 + 1.319516119806*_Complex_I, 0.368752062157 + -0.923715410356*_Complex_I, 2.103742061281 + -0.015112313666*_Complex_I, 0.161141569742 + 0.602136525051*_Complex_I, -0.450622712484 + 1.781653187693*_Complex_I, -0.135385448029 + 0.118136375039*_Complex_I, -0.881476360789 + 0.743248990846*_Complex_I, -0.470865375669 + 0.297577338949*_Complex_I, 1.578293870903 + 0.150586285410*_Complex_I, -0.582548890310 + -0.090131349592*_Complex_I, -0.728216825909 + -0.280660553441*_Complex_I, -0.405960077281 + -0.823236356122*_Complex_I, -0.689782453002 + -0.111721138015*_Complex_I, -0.483036608523 + -2.255409787531*_Complex_I, -1.773638052539 + 0.276871847058*_Complex_I, 1.768143481866 + 0.929411559777*_Complex_I, 1.598162436054 + 0.336924712326*_Complex_I, 0.025313208364 + 0.101634388542*_Complex_I, 1.295932058649 + -0.792267243573*_Complex_I, 0.197302929571 + -1.198246830820*_Complex_I, -0.674567746661 + 0.782836390216*_Complex_I, -1.155843266715 + -2.060346979162*_Complex_I, -1.174296668808 + -1.018450093532*_Complex_I, -2.374237969002 + 0.374087797223*_Complex_I, 0.773269391236 + -0.854101525457*_Complex_I, -0.320046719055 + -0.112754382318*_Complex_I}; float complex fft_test_y32[] = { -1.249387330241 + -4.946207393990*_Complex_I, 6.246388763884 + -6.773507691880*_Complex_I, -8.084921469264 + -10.845914953315*_Complex_I, 4.357263742580 + -0.359518611967*_Complex_I, 0.869129033150 + 4.810140005791*_Complex_I, -4.320755060606 + -2.990777115902*_Complex_I, -6.040916675986 + 11.391912365593*_Complex_I, 1.334419178501 + 8.684519829396*_Complex_I, 4.553475487339 + -2.672989876360*_Complex_I, 5.980003650433 + 0.810448601904*_Complex_I, -6.393705093395 + 4.226375095002*_Complex_I, -2.975901497257 + 6.587514214591*_Complex_I, -1.005810190439 + -6.128898292417*_Complex_I, 0.016624592858 + -1.973370861210*_Complex_I, 0.024605667140 + -7.634608092684*_Complex_I, 2.682037461215 + -1.379684965569*_Complex_I, 5.090591302217 + 7.901478702130*_Complex_I, 4.974928932755 + -2.673377557945*_Complex_I, 2.018958625049 + 1.429758433848*_Complex_I, -3.215930811783 + -5.513827987988*_Complex_I, 9.696021083826 + 2.712450847683*_Complex_I, -6.175824724853 + 6.515234684364*_Complex_I, -10.139408716624 + 3.456026873018*_Complex_I, 3.811736373367 + 3.481961808174*_Complex_I, -8.975590750922 + -1.092757154258*_Complex_I, 1.006822057237 + -4.766098514087*_Complex_I, -0.499087378413 + 4.387815733060*_Complex_I, -0.223489533627 + 2.032893439147*_Complex_I, 12.473346705334 + -4.826450587127*_Complex_I, 4.394902822920 + 12.095339998118*_Complex_I, -3.828535537115 + 2.263473712749*_Complex_I, -6.081522756885 + -0.365006140312*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_35.c000066400000000000000000000112431474751757600214660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 35-point transform // #include float complex fft_test_x35[] = { 0.621203985274 + -1.170486588571*_Complex_I, 0.001346936460 + 0.911992162865*_Complex_I, 0.852266167932 + -0.485602417107*_Complex_I, -1.440614617555 + -0.143907395580*_Complex_I, -0.886824740774 + -0.735649970983*_Complex_I, 0.822316647558 + -2.190416870881*_Complex_I, -0.848542045588 + 0.265512380995*_Complex_I, 0.224076450439 + -2.302360677412*_Complex_I, -0.510056035858 + -1.331941821231*_Complex_I, 1.682894720322 + 1.515017086970*_Complex_I, -0.293255187957 + 0.559255597549*_Complex_I, 1.692889886331 + -1.640844999342*_Complex_I, -1.032973350809 + 0.405524091118*_Complex_I, 0.177413388869 + -1.166118195604*_Complex_I, -0.077664879368 + -1.471655833896*_Complex_I, -0.713927870525 + 1.118966977478*_Complex_I, 3.112942596938 + 0.183067680138*_Complex_I, -2.132342418783 + 0.888305824658*_Complex_I, 0.570015793758 + -1.075297345387*_Complex_I, 0.029232277101 + -0.052772048068*_Complex_I, 0.021810229730 + 1.026136624357*_Complex_I, 0.183820954153 + 0.359011138378*_Complex_I, -0.646415125847 + 0.878859460005*_Complex_I, 0.379503797426 + 0.690555809274*_Complex_I, -1.205501520591 + -1.281704908973*_Complex_I, -0.671296057445 + -1.202380495393*_Complex_I, 1.000730854392 + 1.337218974137*_Complex_I, -0.507823699969 + 0.667041823900*_Complex_I, 0.786493220706 + 0.711624105805*_Complex_I, -0.147343975279 + -0.421666316903*_Complex_I, 1.000992786069 + 0.072055493934*_Complex_I, -0.638324259500 + 0.503386775311*_Complex_I, 1.518863022405 + -0.447779056699*_Complex_I, -0.690987494413 + 0.744128091375*_Complex_I, 0.074647158829 + -1.048901976585*_Complex_I}; float complex fft_test_y35[] = { 2.309567594431 + -5.331826820366*_Complex_I, -7.442846930878 + -4.725553620071*_Complex_I, -2.183297818919 + 6.404493143269*_Complex_I, -2.751014847029 + 2.658941664250*_Complex_I, 8.330534466967 + 0.919074147759*_Complex_I, 6.588325473188 + -2.237962814214*_Complex_I, -7.983324045653 + -4.751388462518*_Complex_I, 9.842334426677 + -4.886656356639*_Complex_I, 2.723677138226 + -1.864201873505*_Complex_I, 3.314550864796 + -2.486087207928*_Complex_I, -9.968089532702 + -11.225031015883*_Complex_I, 3.348282695100 + 3.685146610266*_Complex_I, 3.650591794608 + 7.864477419325*_Complex_I, 12.324040428213 + -2.521426915911*_Complex_I, -1.118920460046 + -5.025187742730*_Complex_I, 14.513400880941 + 11.251977643133*_Complex_I, -2.482556277234 + -3.095357211645*_Complex_I, -7.549326283090 + 3.844289159351*_Complex_I, -6.554611159279 + -1.426517057076*_Complex_I, 6.564157092619 + 4.071022052298*_Complex_I, 5.022588868136 + -15.817689097768*_Complex_I, -5.251727726400 + 2.789037545358*_Complex_I, -2.128113345135 + -15.921584799030*_Complex_I, -6.717549051974 + 1.209151038219*_Complex_I, 3.222807461576 + 5.205190352829*_Complex_I, -2.420694516532 + -6.628232249491*_Complex_I, -0.210938110900 + 1.317502940068*_Complex_I, -4.284810675111 + 4.379050426632*_Complex_I, -1.842031171135 + 3.520287066742*_Complex_I, 5.259391106033 + -9.692983760094*_Complex_I, -3.879590649031 + 2.871689364722*_Complex_I, -1.641216184114 + 4.267406466810*_Complex_I, 1.294145378923 + -2.702480168973*_Complex_I, 1.886124883788 + -3.741139781213*_Complex_I, 7.958277715545 + -3.144460685955*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_36.c000066400000000000000000000114071474751757600214710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 36-point transform // #include float complex fft_test_x36[] = { -0.515260084522 + 1.287529717076*_Complex_I, 0.587117158481 + -0.148572876243*_Complex_I, -0.782947562463 + 1.641852621518*_Complex_I, -0.526927266439 + 0.584647073200*_Complex_I, -1.531349139822 + -1.069623628897*_Complex_I, 1.018192400002 + -0.793147230271*_Complex_I, -1.074504882712 + -0.091149144200*_Complex_I, -0.401657438434 + 0.004317962559*_Complex_I, 1.259620132258 + -0.104377362194*_Complex_I, -0.102194404981 + -0.973411762169*_Complex_I, -0.895434561911 + -1.050093649832*_Complex_I, 1.026577410282 + 1.080478300358*_Complex_I, 0.691470386469 + -0.436083438367*_Complex_I, -0.230801075525 + 1.635643257519*_Complex_I, -0.121589188789 + 0.070584124184*_Complex_I, 0.332245123083 + 0.603463018191*_Complex_I, 0.098342650657 + 0.713292188052*_Complex_I, -0.653525164870 + 0.226711651388*_Complex_I, -0.486468735347 + 0.247902880597*_Complex_I, -0.092383856045 + 0.443156295025*_Complex_I, -1.207432550343 + -0.503252568552*_Complex_I, 0.680629730441 + 0.210743200774*_Complex_I, -1.655855919610 + 0.985314552623*_Complex_I, -0.635578415199 + 1.126805769525*_Complex_I, 0.429626094959 + -0.591166406548*_Complex_I, 0.843172830682 + -0.010918445865*_Complex_I, -0.130407009132 + 0.920489918178*_Complex_I, 0.879595565427 + 0.076478701355*_Complex_I, 0.407356105015 + 0.244802856694*_Complex_I, -0.247029167369 + 1.416537545584*_Complex_I, 0.001447109646 + -0.855321598060*_Complex_I, -1.005160244372 + 0.880697474487*_Complex_I, -1.506889600501 + -0.376866773437*_Complex_I, 0.595335431863 + 0.874899791600*_Complex_I, -1.720946712489 + -0.251050064927*_Complex_I, -0.304668621370 + -0.437688673914*_Complex_I}; float complex fft_test_y36[] = { -6.978283472983 + 7.583625277009*_Complex_I, -6.674217696450 + -3.304059977181*_Complex_I, -9.133615960691 + 4.553754806959*_Complex_I, 7.138280833022 + -0.461421293427*_Complex_I, 6.376807409683 + -0.306551799085*_Complex_I, 2.594166782732 + 4.623935739453*_Complex_I, 2.991096252215 + -1.709441742997*_Complex_I, 7.042547687256 + -5.210100129931*_Complex_I, -3.291195373643 + -2.837550873581*_Complex_I, 3.068320668506 + -5.673130538045*_Complex_I, 1.959771299385 + -2.235257672510*_Complex_I, -10.609066858652 + 0.928096828820*_Complex_I, 3.208839022246 + 0.484194748895*_Complex_I, 2.548602732505 + 9.743720342785*_Complex_I, 6.240917395617 + 6.571681544646*_Complex_I, -4.101181674885 + 4.039956075121*_Complex_I, -9.685452992487 + 0.380605286598*_Complex_I, -3.555255829985 + 3.488301753752*_Complex_I, -10.504163464296 + -6.018056829194*_Complex_I, -2.111740241301 + 1.705549685664*_Complex_I, 2.140088966360 + 7.541207884663*_Complex_I, 0.985036473018 + -0.558056384811*_Complex_I, -1.305685512500 + 8.210384283174*_Complex_I, 4.783233947768 + -2.666144508286*_Complex_I, 6.484426654393 + -5.252223925558*_Complex_I, -2.313461997972 + 5.743487698749*_Complex_I, -1.086778704978 + 8.029162089587*_Complex_I, 6.916062245443 + 0.764580425536*_Complex_I, -2.415195588075 + -0.073706064002*_Complex_I, -5.346986333451 + -3.512605491284*_Complex_I, -0.924055660625 + 2.282174534826*_Complex_I, -0.470350054245 + 2.031728408857*_Complex_I, 2.141016439694 + -1.773104703203*_Complex_I, -1.014341113192 + 7.641158118573*_Complex_I, -4.249655466965 + 2.206889911886*_Complex_I, 0.602106144731 + -0.611713697716*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_4.c000066400000000000000000000032041474751757600214000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 4-point transform // #include float complex fft_test_x4[] = { -2.218920151449 + -1.079004048069*_Complex_I, 0.045264423484 + 0.426155393025*_Complex_I, 0.218614474268 + -0.334711618319*_Complex_I, 2.182538230032 + 1.706944462070*_Complex_I}; float complex fft_test_y4[] = { 0.227496976335 + 0.719384188708*_Complex_I, -3.718323694762 + 1.392981376798*_Complex_I, -4.228108330697 + -3.546815521483*_Complex_I, -1.156745556672 + -2.881566236299*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_43.c000066400000000000000000000127031474751757600214670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 43-point transform // #include float complex fft_test_x43[] = { 0.086214736594 + -0.374055466225*_Complex_I, -0.398326405553 + 0.064437628903*_Complex_I, -0.086828498048 + -1.377541893939*_Complex_I, -0.014057206023 + -1.721581520365*_Complex_I, -1.130661886812 + -0.823144321334*_Complex_I, 0.265330564080 + -2.139333421737*_Complex_I, 0.987278886883 + 0.510016610694*_Complex_I, 1.388439583820 + -0.312226254937*_Complex_I, 1.314187441787 + 2.179164255828*_Complex_I, -0.134438842798 + -2.204082595282*_Complex_I, 0.245609009336 + 0.112479617279*_Complex_I, -1.038607185161 + 0.772906423002*_Complex_I, 0.816938259734 + -2.090685529624*_Complex_I, 0.975237183551 + -0.563625353818*_Complex_I, -0.941942184460 + 1.392834491457*_Complex_I, 1.369305972621 + 0.035788913101*_Complex_I, 0.274358812513 + 0.334025802789*_Complex_I, -0.187955769606 + 0.806622195637*_Complex_I, -0.435359111927 + 0.395863170294*_Complex_I, -1.059982565487 + -1.108626336147*_Complex_I, -0.085915350568 + -0.294840267490*_Complex_I, -0.202754288995 + -0.413065083074*_Complex_I, -0.607968226502 + 1.253761902790*_Complex_I, 2.921829936105 + 1.400641655759*_Complex_I, 0.493898754300 + 2.597915340403*_Complex_I, -0.939016287203 + 0.999025234458*_Complex_I, -1.213828533796 + -0.093371812474*_Complex_I, 0.049357784794 + -1.117710210403*_Complex_I, 0.291427701377 + 0.619473850471*_Complex_I, -0.297284045241 + 1.471963630624*_Complex_I, -1.204828141785 + 0.357668469775*_Complex_I, 1.214147177406 + -1.053652949447*_Complex_I, -0.669099873019 + 0.645208133613*_Complex_I, -0.669325749409 + 1.526826939113*_Complex_I, 1.388489801757 + -0.663313867864*_Complex_I, 1.528893702905 + -0.300643090523*_Complex_I, 0.969651597440 + 0.887262607328*_Complex_I, 0.961949407503 + -1.302265834141*_Complex_I, 0.025366344758 + 1.938755581562*_Complex_I, 0.012954685257 + -0.117840651513*_Complex_I, 0.422317736906 + 0.454593332125*_Complex_I, -1.225108444904 + -0.762684444639*_Complex_I, 0.510768457794 + 0.200474501150*_Complex_I}; float complex fft_test_y43[] = { 5.970664941924 + 2.123419383178*_Complex_I, -4.826258373494 + -10.530035821412*_Complex_I, -6.840438649504 + 2.195697396144*_Complex_I, -15.037444321130 + -0.498694877295*_Complex_I, -2.324178679783 + -5.588631770237*_Complex_I, -9.817989632278 + 8.215797271526*_Complex_I, 19.440508234356 + 0.725796090385*_Complex_I, -0.273833848905 + 4.924507895251*_Complex_I, 5.898110303453 + -7.584923619025*_Complex_I, -1.491058783404 + 7.983518326557*_Complex_I, -7.459786425320 + -5.471409031844*_Complex_I, 9.458054840383 + -1.411338639410*_Complex_I, -7.652963176561 + 16.470882260110*_Complex_I, 4.933008347551 + 1.752692467372*_Complex_I, 3.158349989133 + -10.520004874496*_Complex_I, 3.461440707146 + -1.053485004255*_Complex_I, 0.403169282390 + 15.216737475743*_Complex_I, 11.005277294499 + 0.924950795722*_Complex_I, -2.459303339406 + -4.952009870945*_Complex_I, -11.998504221115 + -4.269332241730*_Complex_I, -10.575401537817 + 0.521491539120*_Complex_I, -8.612771844559 + -4.765648940500*_Complex_I, 7.802134874811 + 3.882271887067*_Complex_I, 2.664085789892 + -5.430064274009*_Complex_I, 7.012256247961 + -6.119235310609*_Complex_I, -0.520208603756 + -0.845655711277*_Complex_I, 0.308220700989 + 3.533138362895*_Complex_I, -10.811305738786 + -4.238039944052*_Complex_I, 6.001274292511 + -2.592573440494*_Complex_I, 5.544361033380 + -11.920579663414*_Complex_I, -2.095258565391 + 0.336151200781*_Complex_I, -5.596706630782 + 7.291207810674*_Complex_I, 9.325757124002 + -3.598787999557*_Complex_I, 1.133897756930 + -1.612056679027*_Complex_I, -2.012305507947 + 5.032886593926*_Complex_I, -10.072407904704 + 5.354603355501*_Complex_I, 2.641399130952 + -1.713592877295*_Complex_I, 1.128116547129 + 7.394974387525*_Complex_I, 12.210114373933 + -3.041200993402*_Complex_I, -0.850951175674 + 3.946134783722*_Complex_I, -1.686631417770 + -4.776809881210*_Complex_I, -2.550902604765 + -2.082230855079*_Complex_I, 9.773642843061 + -9.294902010297*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_48.c000066400000000000000000000136671474751757600215060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 48-point transform // #include float complex fft_test_x48[] = { -1.408383409504 + 0.661990153106*_Complex_I, -0.257850483647 + -2.392863066952*_Complex_I, -0.321563284081 + 1.408168751420*_Complex_I, -1.963488918325 + -0.315363008755*_Complex_I, 0.872572043811 + -1.774358495756*_Complex_I, -1.036243090405 + 0.085162186806*_Complex_I, -0.810463329242 + 0.370726012575*_Complex_I, 0.814727688017 + -0.148930236445*_Complex_I, -0.482188504339 + -0.888806074906*_Complex_I, 0.751010250272 + 0.610241893778*_Complex_I, 1.562853718365 + 0.338170177897*_Complex_I, 0.836367957185 + -1.685869538958*_Complex_I, -0.678836393610 + -1.105381292997*_Complex_I, 1.313536222418 + -1.604103598331*_Complex_I, 0.652309130012 + -1.915192986159*_Complex_I, -0.398123599463 + 1.372136473305*_Complex_I, 2.555137160099 + 0.715094591241*_Complex_I, 1.803926723963 + -0.470162240275*_Complex_I, -1.033969686967 + -1.754083599107*_Complex_I, 0.345505105620 + 1.869665415226*_Complex_I, 0.917886037796 + 1.488788889124*_Complex_I, -0.149819207787 + 0.641387132093*_Complex_I, 0.239135545455 + 0.491166352445*_Complex_I, 0.571741246274 + 0.056534896965*_Complex_I, -0.131630105163 + -1.508920032468*_Complex_I, 1.209119501276 + -0.078706912158*_Complex_I, -0.955610498388 + 1.044137820022*_Complex_I, 0.106457806412 + -0.585542024212*_Complex_I, -1.229933443664 + -0.322249167809*_Complex_I, 0.278186189361 + 1.807684972303*_Complex_I, -1.729784506112 + -0.939519586014*_Complex_I, 0.927483189137 + 0.431322133098*_Complex_I, 0.141968377392 + -0.120521833531*_Complex_I, 0.747436107175 + -1.117297332586*_Complex_I, 0.321427506892 + 0.604553538042*_Complex_I, -1.310259971951 + 0.301350874871*_Complex_I, 0.000616127451 + 1.395956853708*_Complex_I, 0.789283665376 + -0.378417239374*_Complex_I, 1.626071060809 + -0.838198796474*_Complex_I, -0.502170615893 + -0.371786828507*_Complex_I, 0.941560993676 + 0.083132997096*_Complex_I, 0.217335920952 + -0.775367298569*_Complex_I, -1.386726382455 + 1.228033537755*_Complex_I, 0.135305964480 + 1.010214926902*_Complex_I, -0.769134001940 + -1.642182708631*_Complex_I, 0.451443995268 + -1.443277308466*_Complex_I, 0.315403114502 + 0.409584212993*_Complex_I, 0.777007938735 + 0.033642728423*_Complex_I}; float complex fft_test_y48[] = { 5.666636855245 + -5.718253686246*_Complex_I, -9.318440723038 + -11.045628239935*_Complex_I, -10.484391800934 + 10.258547835119*_Complex_I, 5.692975013010 + -0.079178697546*_Complex_I, -0.031494239726 + -3.429117974659*_Complex_I, -1.633492827483 + 6.955978741593*_Complex_I, 9.741303637543 + 2.061588265899*_Complex_I, 1.051018454307 + 11.180284489721*_Complex_I, -8.006452512021 + 0.459314562290*_Complex_I, -7.397134103296 + 6.198088361763*_Complex_I, 4.688329496623 + 1.626283668222*_Complex_I, -8.380975402709 + -3.715659857481*_Complex_I, -4.832542130429 + -9.241813561210*_Complex_I, -5.444148048877 + -5.774968307876*_Complex_I, -2.557281197147 + -8.013068178874*_Complex_I, -2.508606838763 + 3.393130955025*_Complex_I, -13.856615792482 + -8.279988253172*_Complex_I, -0.275213201833 + 9.234040467214*_Complex_I, -10.548623142987 + 1.461152259705*_Complex_I, -5.454201445127 + 5.015988800202*_Complex_I, 3.151148175752 + 16.404964892896*_Complex_I, -2.628471739476 + 12.549705973202*_Complex_I, -5.309278338161 + -1.496205611507*_Complex_I, 8.327510797620 + 9.076602173656*_Complex_I, -7.249202313653 + 0.578432313391*_Complex_I, 0.278119672993 + 6.335493150399*_Complex_I, -4.400202487177 + 4.358641062270*_Complex_I, 1.825561215029 + -10.742991731336*_Complex_I, 2.059618967411 + 5.230483842207*_Complex_I, -0.589368957248 + -0.568413649725*_Complex_I, 5.846114680415 + 3.953722464016*_Complex_I, -4.790203069855 + 5.357335572595*_Complex_I, -16.219316666593 + 5.416145069047*_Complex_I, 4.053779640014 + 14.490156426037*_Complex_I, 10.343285976607 + -19.941466772140*_Complex_I, -0.179745539698 + -6.776924924303*_Complex_I, 9.333647116859 + 2.311810446775*_Complex_I, -0.778589953827 + -7.796695480692*_Complex_I, -5.728518422011 + -0.187241621271*_Complex_I, 15.554791252022 + 3.837751365144*_Complex_I, -3.410115684107 + -2.362837725953*_Complex_I, -14.699080682437 + 4.704009521181*_Complex_I, 4.974381394298 + -3.870880098021*_Complex_I, 4.347015481178 + 1.639590273798*_Complex_I, 6.775882853829 + -8.045391749167*_Complex_I, -6.905056488040 + -1.077414483536*_Complex_I, -6.906638779165 + -3.861138554296*_Complex_I, -0.790121808651 + -0.288436445313*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_5.c000066400000000000000000000033501474751757600214030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 5-point transform // #include float complex fft_test_x5[] = { 1.043452789296 + -0.216675780077*_Complex_I, -0.039259154719 + -0.756503590362*_Complex_I, -1.378329383804 + -1.629692578129*_Complex_I, 0.695728357044 + -2.639675956000*_Complex_I, -0.019932891052 + 0.123958045411*_Complex_I}; float complex fft_test_y5[] = { 0.301659716765 + -5.118589859158*_Complex_I, 1.333681830770 + 4.279329517647*_Complex_I, -0.597668794979 + -2.985429553632*_Complex_I, 2.358478480201 + 0.936943320049*_Complex_I, 1.821112713724 + 1.804367674708*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_509.c000066400000000000000000001457161474751757600215710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 509-point transform // #include float complex fft_test_x509[] = { 0.359331995889 + -1.085301108776*_Complex_I, -1.932383412518 + 0.116856180907*_Complex_I, 0.496271262268 + 0.731796541816*_Complex_I, 0.431573865944 + 0.591703481184*_Complex_I, 0.589253369531 + -0.795072338555*_Complex_I, -0.870697944847 + -0.497562617185*_Complex_I, 1.247223411086 + 0.771429589056*_Complex_I, 0.924873577618 + -1.184353621638*_Complex_I, 0.659579079487 + 0.126294704315*_Complex_I, 1.647221437368 + -2.249906156787*_Complex_I, -1.334652205984 + -0.024425874102*_Complex_I, 0.095148747858 + -0.284583137620*_Complex_I, -2.534039905928 + 1.936731699042*_Complex_I, 0.370565605548 + -0.671454121821*_Complex_I, 0.382886168067 + 0.318205203845*_Complex_I, -1.314163630052 + 0.381239207410*_Complex_I, -0.258334295223 + 0.599344826242*_Complex_I, 1.542372805791 + -0.381018806439*_Complex_I, -0.015408662897 + 1.208686378191*_Complex_I, -3.023761214358 + -0.135651280290*_Complex_I, -0.916610967637 + 0.884088889046*_Complex_I, -2.081046862959 + 2.001230452826*_Complex_I, 1.031862595677 + 1.366475262140*_Complex_I, -0.259564882667 + 0.315307538802*_Complex_I, 0.161129496712 + -1.667686892086*_Complex_I, -1.241250123646 + 1.380715267035*_Complex_I, 0.027019787139 + 2.068943431414*_Complex_I, 0.164488255181 + -0.688316587237*_Complex_I, 1.114819509678 + -3.008077068837*_Complex_I, -1.374358189256 + 0.000217799371*_Complex_I, 1.783814617294 + -0.127391483103*_Complex_I, 1.648034611975 + -0.251680996856*_Complex_I, 1.678583258653 + 1.974165102901*_Complex_I, -0.857815837356 + -3.739419503346*_Complex_I, 1.227762010986 + -0.496092919671*_Complex_I, 0.275130781058 + 1.160971226357*_Complex_I, 0.333840127696 + 1.388036870908*_Complex_I, -0.805343489373 + 0.006883877363*_Complex_I, 0.113234013309 + 0.031253576243*_Complex_I, -0.610537915176 + 0.630710349348*_Complex_I, 1.397240850777 + -2.014373420814*_Complex_I, -0.255790837573 + 0.916792397001*_Complex_I, 0.129924388336 + -0.537587690895*_Complex_I, -0.926838068677 + 0.308336177664*_Complex_I, 3.010372178544 + -2.369144950446*_Complex_I, 1.263300917549 + -1.660219437257*_Complex_I, 0.841656993731 + 1.927041610736*_Complex_I, -0.904792064104 + -1.173048767457*_Complex_I, 0.989814388062 + 1.253071554414*_Complex_I, -0.257249205993 + -0.959941785447*_Complex_I, -1.205852496010 + 0.196179577313*_Complex_I, 1.940909824834 + -2.078512378665*_Complex_I, 0.300600588979 + 0.572506173199*_Complex_I, -0.375271364555 + -0.773019164981*_Complex_I, -0.858303843109 + -0.674765891031*_Complex_I, -1.189090659992 + 0.543093004900*_Complex_I, 2.165334883903 + 0.001082499227*_Complex_I, 2.057289953335 + -0.916206975165*_Complex_I, -0.161982761480 + -0.815858087637*_Complex_I, -1.390044285564 + -0.714076838951*_Complex_I, 0.766348194222 + 0.076251375781*_Complex_I, -0.630967707884 + 0.854026208416*_Complex_I, -1.309424118846 + 0.470225939681*_Complex_I, 0.664797780343 + -1.109803637533*_Complex_I, 3.563726896705 + 1.370311380835*_Complex_I, 0.850424444505 + -0.770251870088*_Complex_I, 0.316880772888 + -0.509312503865*_Complex_I, -1.439495581618 + -1.741765587801*_Complex_I, -1.095540513740 + 0.552478238644*_Complex_I, -0.879540480746 + -1.782154665595*_Complex_I, 1.394922475961 + 0.407153930461*_Complex_I, -1.583206834198 + 0.548532742373*_Complex_I, -0.330266310339 + 0.821466818961*_Complex_I, -1.157454328378 + 0.386301239269*_Complex_I, 0.823214183923 + 0.993600792956*_Complex_I, -0.665523708393 + -0.143306700746*_Complex_I, -2.274210663640 + -0.526858961140*_Complex_I, 0.675171584769 + 1.608754308056*_Complex_I, 0.067605428754 + 0.840683747814*_Complex_I, 0.927563962378 + 0.563153155030*_Complex_I, -0.129920407968 + 0.614536449089*_Complex_I, -0.633778727653 + 0.174141369494*_Complex_I, -0.579622089160 + -1.179631499150*_Complex_I, 3.157266013709 + 0.841577893721*_Complex_I, -1.564968432235 + 0.237536721331*_Complex_I, 0.832675154129 + 2.752538330003*_Complex_I, -1.003618718524 + -0.803502222719*_Complex_I, 1.033045390907 + -0.887091010037*_Complex_I, 0.406299848093 + -0.231522470982*_Complex_I, -1.224877731528 + 0.962620343882*_Complex_I, -0.287856500251 + -0.684348325534*_Complex_I, 0.769551121775 + 1.052171601110*_Complex_I, 1.211938362349 + -0.397315302619*_Complex_I, -1.801171069328 + 0.782481239455*_Complex_I, -0.428774166115 + 0.205654171857*_Complex_I, 0.742768169350 + 1.078779525233*_Complex_I, -0.760778783880 + -0.392123510805*_Complex_I, 0.530474251890 + 0.355891481054*_Complex_I, 1.455692020840 + 0.275438176816*_Complex_I, -0.256274791959 + -1.055463927568*_Complex_I, 1.397683977888 + -1.672842861191*_Complex_I, 1.059395488056 + -1.195826863369*_Complex_I, 0.535641711388 + -0.139593755691*_Complex_I, 0.767194249054 + 1.159606442946*_Complex_I, 0.730248752053 + 0.874096637495*_Complex_I, 0.374817248354 + 0.381042720649*_Complex_I, -1.290660859871 + -1.052408951473*_Complex_I, -0.698710060780 + -0.404862720632*_Complex_I, 0.260762012984 + -0.586144943477*_Complex_I, 0.471825306906 + 0.216309496806*_Complex_I, 0.902145392649 + 0.734793058179*_Complex_I, 0.970712066057 + 1.203301629983*_Complex_I, 0.697414298916 + -0.091399436653*_Complex_I, -0.763151612464 + -0.155822503488*_Complex_I, 0.571013025643 + -0.991520969075*_Complex_I, 0.488145846303 + 0.518072470835*_Complex_I, 0.382903596789 + -0.570642408749*_Complex_I, -0.068409602398 + -0.457729632233*_Complex_I, 0.328633596900 + -0.485642431490*_Complex_I, 1.463236532852 + -0.689222532447*_Complex_I, 0.843726237994 + 1.027737725483*_Complex_I, 0.411174457800 + 1.072703354585*_Complex_I, -0.553638496687 + 0.592560929746*_Complex_I, -0.519820674211 + 0.395335990219*_Complex_I, 0.816739721990 + 1.296561601952*_Complex_I, 0.839055358910 + 0.038232944058*_Complex_I, -1.321845319423 + 2.461463566622*_Complex_I, -1.244535108317 + -0.855331739033*_Complex_I, 0.174834515541 + -0.236103345803*_Complex_I, -0.817712897113 + 0.503960726952*_Complex_I, -0.723518973851 + 0.751673530926*_Complex_I, -0.189283180062 + 0.644019002779*_Complex_I, 0.237729751553 + 0.335607912526*_Complex_I, -0.969216001025 + -0.603266829416*_Complex_I, -0.207478679057 + -0.730339402811*_Complex_I, -0.024191569913 + -1.259252874185*_Complex_I, 1.472785074216 + -0.491418040669*_Complex_I, 0.143580527900 + -1.186038294726*_Complex_I, 0.835958076660 + 1.651209544972*_Complex_I, -1.330070431715 + 0.745655269480*_Complex_I, -2.351132556248 + 1.414206325062*_Complex_I, -0.647960722564 + 0.019824747070*_Complex_I, 0.054504089094 + -0.434505484307*_Complex_I, -1.069009000323 + 0.930859192631*_Complex_I, 2.256466805965 + 0.677754214770*_Complex_I, -1.017788464214 + 0.299270915482*_Complex_I, -1.350006249149 + 0.860365863370*_Complex_I, 0.554243078961 + 1.630321512911*_Complex_I, -1.709590344454 + -0.169567705711*_Complex_I, 0.650774374311 + 0.064592934208*_Complex_I, 1.989755256430 + 0.536482018456*_Complex_I, -0.373249333538 + -0.106134582591*_Complex_I, 0.095351627343 + -0.279297038594*_Complex_I, 0.230789928160 + 0.532796285505*_Complex_I, 0.247854968690 + -2.153358768182*_Complex_I, 0.136098798048 + 1.135668579132*_Complex_I, -0.208329927938 + 0.789350627066*_Complex_I, 0.039858273209 + -0.599940553834*_Complex_I, -0.117101531764 + 0.201275502180*_Complex_I, 0.817971264476 + -1.329760648517*_Complex_I, 0.035980481979 + -0.922818951948*_Complex_I, -1.888935382734 + -1.797450884362*_Complex_I, -0.097016985104 + -1.168628933267*_Complex_I, 0.452048304507 + -0.675116763083*_Complex_I, -1.209707805549 + 0.172148052410*_Complex_I, 1.432472352322 + 0.632406226221*_Complex_I, 2.933280640140 + 0.949590441066*_Complex_I, -0.309024453832 + 1.192611727581*_Complex_I, -0.255306372880 + 0.007559617013*_Complex_I, 0.081653931435 + -0.672920464273*_Complex_I, 0.405276164696 + -0.077841212841*_Complex_I, -0.338396874520 + 0.355225122224*_Complex_I, 0.109601214660 + 1.392547443330*_Complex_I, -1.871393476572 + 0.310989021924*_Complex_I, 0.332233956611 + 1.730122993833*_Complex_I, 1.439926026777 + -1.611064773734*_Complex_I, -1.860778448552 + 0.425384165779*_Complex_I, 0.274648666779 + 1.286600320037*_Complex_I, 0.762615580678 + -0.222402755827*_Complex_I, 0.426513801822 + 1.965805792967*_Complex_I, -0.103171697634 + -0.569960476279*_Complex_I, 1.562067509000 + -2.347766792543*_Complex_I, 0.467044769684 + 0.321342630659*_Complex_I, -1.416578640685 + -0.831113210732*_Complex_I, -0.733167805614 + 1.176375168746*_Complex_I, -1.282613845051 + -0.979773114694*_Complex_I, 0.506103347478 + -1.085270279646*_Complex_I, 2.539137831319 + 2.232625718408*_Complex_I, -1.637899545016 + 0.265528606195*_Complex_I, -1.931767882639 + 0.329066225098*_Complex_I, 0.127023806083 + 0.504962043815*_Complex_I, 0.588353928765 + -1.463911658760*_Complex_I, 0.907010785485 + -0.108879037057*_Complex_I, -0.951802902717 + -0.685757383062*_Complex_I, 1.723143501154 + -0.419300229480*_Complex_I, -0.943119843417 + 0.652144368853*_Complex_I, -0.851586780301 + -1.516257192307*_Complex_I, 0.472227887604 + 1.052236419944*_Complex_I, 0.113888251161 + -1.124587148028*_Complex_I, 0.051529667469 + -0.136410527640*_Complex_I, -0.647857223628 + 0.431204980149*_Complex_I, 1.349209612218 + -0.768179692308*_Complex_I, -0.026826971021 + -0.545234111539*_Complex_I, -0.514071604921 + -0.664124619949*_Complex_I, 0.320778745077 + 1.111997835236*_Complex_I, -0.232562962611 + -0.669159856913*_Complex_I, -0.896014800467 + 0.082046851667*_Complex_I, -0.167690950519 + -1.119443226265*_Complex_I, -0.433053084055 + -0.204133858571*_Complex_I, -1.567141147453 + -0.972571871430*_Complex_I, -1.040971048402 + 0.473975308345*_Complex_I, -1.551423307502 + -0.934406696693*_Complex_I, 1.267729903934 + 2.062089282704*_Complex_I, -0.814068862944 + -0.268491284145*_Complex_I, 0.721715833176 + -0.368317000932*_Complex_I, -0.236677967201 + -1.031498627296*_Complex_I, -0.027596539058 + -0.526943246450*_Complex_I, 0.607765602666 + 0.747238787304*_Complex_I, 0.442222664332 + -0.844428479402*_Complex_I, -0.584746227099 + 0.008876873310*_Complex_I, 0.249251666407 + 1.120945916837*_Complex_I, 0.406090989317 + -0.832304494623*_Complex_I, -1.420792340638 + 0.417700569682*_Complex_I, 0.469433523536 + -0.703036988315*_Complex_I, 0.799192929845 + 0.584252218542*_Complex_I, -0.846345284557 + -0.125059394154*_Complex_I, 0.187771816466 + 0.373470766869*_Complex_I, -2.668531322148 + 0.189825888614*_Complex_I, 0.684689436275 + 1.519032618934*_Complex_I, -0.452797714368 + 1.843053037274*_Complex_I, -0.614449241246 + -0.006236652039*_Complex_I, 0.929289964606 + 0.965819481866*_Complex_I, 0.800433661968 + 0.829558429420*_Complex_I, -1.088281420026 + -0.801332579437*_Complex_I, -0.080346758942 + 0.412114096369*_Complex_I, 1.491530334351 + -0.037720112002*_Complex_I, -1.419313834957 + 1.309423611663*_Complex_I, 0.626194884901 + 0.448698878768*_Complex_I, 1.062456184701 + -1.574268630848*_Complex_I, -0.284112227827 + 0.550018601059*_Complex_I, -0.080443635589 + -1.362211376503*_Complex_I, 0.383016098417 + 1.081967093575*_Complex_I, 0.484156075687 + -0.162493291081*_Complex_I, -0.632696839217 + -1.499586717062*_Complex_I, 1.771132365818 + -0.691460076219*_Complex_I, 1.177429509865 + -0.486631740300*_Complex_I, 0.452912528112 + 1.368403825897*_Complex_I, 0.007493867542 + -0.269397882793*_Complex_I, -1.107355722972 + 0.037650076863*_Complex_I, -0.524329801696 + 1.542074025962*_Complex_I, 0.448469395501 + 0.620253813644*_Complex_I, 0.937797278085 + 0.094893367525*_Complex_I, 0.244627220423 + -0.865982595984*_Complex_I, -0.620857271928 + 1.618502476045*_Complex_I, -0.727959747987 + -1.748132622853*_Complex_I, -1.814748553219 + 0.357659723379*_Complex_I, -1.190951476209 + -0.302683547331*_Complex_I, -0.642926196548 + -0.441431483518*_Complex_I, 0.906018063143 + -0.456267895782*_Complex_I, 1.658412527962 + 0.602929674812*_Complex_I, -1.372573150919 + -0.165247494352*_Complex_I, 0.701050669178 + 0.784117117798*_Complex_I, -1.093947418964 + -2.169417895648*_Complex_I, -0.619306010978 + 0.346306836794*_Complex_I, -1.153602396000 + 0.310559458662*_Complex_I, 1.857961002742 + 1.662749378565*_Complex_I, 0.726892056406 + 0.559412940831*_Complex_I, 0.618501787181 + 0.753344508665*_Complex_I, 0.060088823625 + -1.132388678000*_Complex_I, -0.790715886898 + 1.256189591885*_Complex_I, -1.346611550340 + -1.002213804884*_Complex_I, -0.153748736848 + -1.273877582585*_Complex_I, -1.102237529635 + -1.113178017398*_Complex_I, -0.526084982723 + 1.255781208343*_Complex_I, -0.738929991536 + 1.454321302002*_Complex_I, -1.015352909554 + 0.057528759460*_Complex_I, 0.675998598897 + -0.143860246243*_Complex_I, 0.189558927003 + 0.513691656677*_Complex_I, 0.009183574378 + 0.963901374647*_Complex_I, -0.163787067951 + -1.522554558143*_Complex_I, 0.302708128196 + 0.904573259262*_Complex_I, 0.975710589669 + -1.011907000330*_Complex_I, -0.117268931532 + 0.858171829955*_Complex_I, -1.306428434179 + 0.113727230388*_Complex_I, -0.959251067394 + 0.253171642011*_Complex_I, 0.898435910380 + 0.293195734212*_Complex_I, -0.621680975624 + -0.582564866291*_Complex_I, 0.179461744683 + 0.209868112155*_Complex_I, -0.203784114877 + -0.011115684099*_Complex_I, 1.795424157294 + -0.117231500488*_Complex_I, 0.015989098360 + -0.642768987364*_Complex_I, -1.375016631330 + -2.085463142461*_Complex_I, -0.655990108553 + 0.722884678316*_Complex_I, 1.172312994480 + -0.355468862899*_Complex_I, -0.564442301948 + 0.323979441156*_Complex_I, 0.899045729865 + -1.148993122117*_Complex_I, 1.045854100254 + 1.711078921366*_Complex_I, 0.592020255938 + 0.219085296351*_Complex_I, 0.118211086528 + -1.123504917557*_Complex_I, 0.233426106939 + -1.883587119594*_Complex_I, -0.301438222142 + -0.697732158432*_Complex_I, 0.312117398590 + -0.010728436711*_Complex_I, -0.956339212238 + 0.275577083186*_Complex_I, 1.086666854829 + -1.181802410378*_Complex_I, 1.074818739604 + -0.636045956563*_Complex_I, 0.644130821770 + -0.481626402565*_Complex_I, 0.055564592606 + -0.355383569012*_Complex_I, -1.710794754131 + -0.311499134725*_Complex_I, -1.357530095316 + 1.586038700811*_Complex_I, 0.643883320289 + -1.661496495893*_Complex_I, 0.916591063253 + 0.463263213793*_Complex_I, 0.795060678890 + 0.253692839397*_Complex_I, -0.353293483561 + -0.793786778605*_Complex_I, 1.523091692648 + 1.009541299320*_Complex_I, -0.351467193764 + -0.233882680674*_Complex_I, -1.006204919749 + -1.722099827433*_Complex_I, -0.425646600377 + -0.067539377037*_Complex_I, -2.152456912795 + 0.355174573898*_Complex_I, -1.397998826498 + 0.043192513073*_Complex_I, 0.463250457123 + 0.785418638026*_Complex_I, 0.551007796000 + -0.600950335023*_Complex_I, 1.336913064335 + 0.299718316993*_Complex_I, 0.576007704981 + -0.703000454871*_Complex_I, 0.501091983740 + 0.079592846760*_Complex_I, 0.178571647134 + -0.055720934489*_Complex_I, 0.843544810635 + 0.526236292547*_Complex_I, 1.354311088400 + -0.480046041766*_Complex_I, -1.121411263124 + -0.220337368903*_Complex_I, 0.018969956960 + -0.526588981826*_Complex_I, -0.874090913826 + 1.731623994129*_Complex_I, -1.108295529258 + 1.163520621835*_Complex_I, -0.656720377715 + 0.245096653391*_Complex_I, 0.625251262223 + 1.662769471886*_Complex_I, 0.503819391123 + -1.441549149924*_Complex_I, -0.164837089741 + -0.715463798642*_Complex_I, 0.355362378583 + 2.159694721953*_Complex_I, -0.008848280750 + -0.018260892822*_Complex_I, -0.136686667816 + 1.182755498355*_Complex_I, -0.136433742988 + 0.851417981048*_Complex_I, -0.395460120756 + 0.812014412771*_Complex_I, 0.025308338705 + 0.630907052235*_Complex_I, 1.006681294297 + 1.783315896794*_Complex_I, -0.402626477026 + 0.776761257059*_Complex_I, -1.317690399125 + 0.130484673594*_Complex_I, -0.868791706762 + -0.642771615764*_Complex_I, 0.137146795180 + -0.102157755198*_Complex_I, 1.633710393863 + -0.768782548860*_Complex_I, -0.867759427420 + 1.601477458878*_Complex_I, -1.157703488657 + -0.206031874994*_Complex_I, 0.041016911327 + -1.180389310249*_Complex_I, -0.189738035969 + -0.713067619743*_Complex_I, 0.933408353482 + 1.194576784859*_Complex_I, 0.514861178855 + 0.368016550894*_Complex_I, 0.881690626307 + 2.753761417447*_Complex_I, -0.133670635264 + 1.543292970173*_Complex_I, 2.091596895159 + -0.093690078394*_Complex_I, -1.188956830982 + -0.114523278237*_Complex_I, -0.053197690454 + 0.907571243350*_Complex_I, 0.401291232622 + -0.415340086801*_Complex_I, -0.681924799342 + 0.669543900292*_Complex_I, 0.530696047517 + -0.997585317896*_Complex_I, -0.533192039121 + -1.431729688530*_Complex_I, 0.536364895113 + 1.169805471895*_Complex_I, -1.016375434615 + -1.450239121127*_Complex_I, -1.561071693564 + -0.170486342837*_Complex_I, -0.183747193975 + -0.977837337154*_Complex_I, -0.181940033627 + -0.248171826564*_Complex_I, -0.328526087010 + -0.030637600322*_Complex_I, -1.002704137273 + -0.085997551664*_Complex_I, 1.368038996286 + -0.141325193319*_Complex_I, 0.403836121556 + 2.008528522943*_Complex_I, -0.810518568790 + -0.149400127852*_Complex_I, -0.693120904958 + -1.117715197785*_Complex_I, 1.558993909095 + -2.012078672111*_Complex_I, 0.029046234836 + -1.049286048426*_Complex_I, 0.790327688876 + 0.101616687460*_Complex_I, -0.401919211737 + -0.430529168165*_Complex_I, 0.287473232440 + -0.564999246068*_Complex_I, 1.716421030546 + -0.404965480273*_Complex_I, 0.050376052116 + 0.795529162825*_Complex_I, -1.281143070062 + 0.808984215487*_Complex_I, -2.314127686421 + -0.020801982220*_Complex_I, 1.606737133361 + 0.283817403079*_Complex_I, 0.355463854549 + 0.044155238023*_Complex_I, -1.076907023070 + 0.442916691766*_Complex_I, 0.087222702651 + 1.349524189157*_Complex_I, -1.625272715780 + 0.294000847904*_Complex_I, 2.355923230363 + 0.786258163154*_Complex_I, 0.590797134194 + -1.524824299804*_Complex_I, -0.247232063439 + 0.027525184425*_Complex_I, 0.422150431137 + 0.191460073698*_Complex_I, 0.333205469444 + 0.566695459783*_Complex_I, 2.040179995474 + -0.033523279638*_Complex_I, 1.708801210517 + -0.514673828477*_Complex_I, -1.148367840353 + 0.175705040636*_Complex_I, -0.208810451052 + 1.955963982995*_Complex_I, 0.277462389542 + 0.341691402206*_Complex_I, 1.115415958264 + 0.268951601110*_Complex_I, 0.039043618322 + 1.093842223424*_Complex_I, 0.154656090432 + -2.528281845522*_Complex_I, -0.169580739559 + 1.232275509700*_Complex_I, -0.117411131677 + -1.002389093350*_Complex_I, 0.035928732692 + 2.439878625945*_Complex_I, -0.332442060919 + 0.086411580288*_Complex_I, 1.801599291824 + -0.728371893507*_Complex_I, 2.510167669033 + 0.293277743476*_Complex_I, 1.336012143828 + 0.553373968985*_Complex_I, 0.179581375233 + 0.219695624924*_Complex_I, 0.593263517685 + 0.407445722133*_Complex_I, 0.684624183099 + 0.589697664907*_Complex_I, -2.496382874468 + 0.024438752127*_Complex_I, -2.222694698779 + 1.701453939912*_Complex_I, 0.154420002119 + -1.338536134506*_Complex_I, 0.256365846642 + -0.981555435302*_Complex_I, 0.646498405245 + 1.015323083702*_Complex_I, 1.816099125502 + -0.873689502536*_Complex_I, 0.973113786206 + 0.638143551822*_Complex_I, 1.082802452802 + 0.054273301693*_Complex_I, -1.477958702052 + -1.876253882821*_Complex_I, -1.509174430498 + -1.366946689175*_Complex_I, 0.770200379893 + -0.037358369644*_Complex_I, 0.020528472364 + 0.071112924686*_Complex_I, 1.163573145482 + 0.270667445496*_Complex_I, -0.685276141620 + 1.042179563446*_Complex_I, -1.450457525407 + -0.619572993396*_Complex_I, -1.087848848412 + 0.747504403403*_Complex_I, 0.182987452127 + 0.130972663746*_Complex_I, -0.146555893049 + 0.691910395951*_Complex_I, -1.735762675547 + -0.761410376033*_Complex_I, 0.130810608875 + -1.132633564866*_Complex_I, 0.393865724887 + -0.821588251430*_Complex_I, 1.287503514649 + -0.355212207325*_Complex_I, 0.319345692829 + -1.117466320715*_Complex_I, 0.418623558075 + -1.759140288875*_Complex_I, 1.041852719916 + 0.176006788980*_Complex_I, -0.297227854618 + 0.227296263697*_Complex_I, -0.164089543129 + -1.043612906074*_Complex_I, 0.008690483342 + 1.110377157604*_Complex_I, -0.219664588199 + 0.427614664824*_Complex_I, 1.343587074840 + 0.375898274813*_Complex_I, 1.490739162431 + 0.021350208856*_Complex_I, 0.945367199263 + 0.180821025970*_Complex_I, 0.522231273825 + -0.497986782057*_Complex_I, 0.523336519862 + -0.933508311700*_Complex_I, 0.496982629732 + 1.473461947118*_Complex_I, -0.003062144935 + -0.162840951249*_Complex_I, 0.984875642474 + -0.848717378538*_Complex_I, -0.461516263319 + -0.685745084807*_Complex_I, -1.175877458107 + -0.177846365813*_Complex_I, -0.932200203193 + 1.107705439242*_Complex_I, 1.406397814811 + 0.054681766136*_Complex_I, 1.109360316168 + -1.679067648707*_Complex_I, 0.924696326741 + 0.067692426194*_Complex_I, -0.000830800316 + -0.473092403298*_Complex_I, -0.731674917791 + -0.551769981624*_Complex_I, -0.569303781517 + -0.006801228336*_Complex_I, 0.110391386502 + -1.899793883492*_Complex_I, 0.814109796724 + -0.160466492041*_Complex_I, 1.138698851351 + -0.625131274654*_Complex_I, -1.963957708898 + 0.775152493271*_Complex_I, -1.659897790238 + 1.056053755857*_Complex_I, -0.649474775762 + 1.460655545851*_Complex_I, -0.741388571452 + -1.820826399375*_Complex_I, -1.572911393570 + 1.569354704216*_Complex_I, 0.744026763162 + 0.835499539241*_Complex_I, 0.095754291390 + 0.796930944242*_Complex_I, 0.507814608179 + 0.818154740321*_Complex_I, -0.383708274783 + -0.068423423510*_Complex_I, -0.888346025964 + 0.571095503271*_Complex_I, 0.925179546159 + -1.052147910287*_Complex_I, -0.438552116998 + -0.225556401800*_Complex_I, 1.164226743249 + 0.148695281475*_Complex_I, 0.964606990498 + 0.259930491349*_Complex_I, -0.343680793432 + 0.578310893020*_Complex_I, 0.093080205932 + 1.723388863831*_Complex_I, -0.756655985085 + 0.681598873690*_Complex_I, 0.939758986711 + 0.011205851149*_Complex_I, -0.141899272761 + 0.521507574016*_Complex_I, -0.716208197806 + 1.303295936061*_Complex_I, -0.813031307398 + 1.372568923775*_Complex_I, 1.023111911832 + -0.701776162450*_Complex_I, -0.059513464951 + -0.562779118569*_Complex_I, -1.783877678017 + 1.123340885741*_Complex_I, -0.129189002044 + 0.152272891142*_Complex_I, 0.594929872664 + 0.920537744435*_Complex_I, 0.958591761922 + 1.041651647113*_Complex_I, 0.496121593665 + -0.038971974072*_Complex_I, 0.184620294659 + -2.865914521972*_Complex_I, -0.173289102032 + 1.628057214738*_Complex_I, -1.450876580978 + -1.542121010661*_Complex_I, -0.585624617416 + -0.000140441111*_Complex_I, -0.165171139738 + -0.792078084035*_Complex_I, 1.008588335837 + 2.483679153708*_Complex_I, -1.101668002181 + -0.867864575222*_Complex_I, 1.778741775885 + 1.238012027547*_Complex_I, 0.418624110589 + -0.516903858622*_Complex_I, -0.623664358679 + 0.685852774278*_Complex_I, 1.473049190104 + -0.824653187025*_Complex_I, -1.125651402746 + -0.051861075402*_Complex_I, 0.942173492837 + 0.284253723912*_Complex_I, 1.468609011081 + 0.872878783090*_Complex_I, -0.523118553730 + 0.065885163104*_Complex_I, -1.209516269354 + 1.712795511905*_Complex_I, -0.164914664862 + -1.060198690347*_Complex_I, 0.081083509872 + 0.514122164431*_Complex_I, 0.014993899314 + -0.421407997613*_Complex_I, 0.921737261188 + -0.891135385409*_Complex_I, -0.186548224004 + 0.410695725270*_Complex_I, -0.138866088362 + -0.530179759052*_Complex_I}; float complex fft_test_y509[] = { 15.695701816574 + 18.430646076972*_Complex_I, 17.496535538521 + 6.323908273548*_Complex_I, -15.330535795607 + -16.826373817993*_Complex_I, -22.995137994536 + 5.848541065489*_Complex_I, -29.715938835044 + 12.754412174777*_Complex_I, 10.901257286656 + -8.716929489684*_Complex_I, -19.628646037487 + 19.226286624799*_Complex_I, -20.480875354016 + -31.897908691975*_Complex_I, 35.124732513036 + 16.324491517218*_Complex_I, 46.193539420959 + 25.851763792302*_Complex_I, 5.792757151559 + -12.926180930790*_Complex_I, -22.013847261245 + -5.613610031493*_Complex_I, 9.404166069447 + -0.019908771755*_Complex_I, 8.201675624257 + -8.967673070400*_Complex_I, 15.181089874097 + -6.297364574465*_Complex_I, 14.570696506052 + -1.051310941558*_Complex_I, -1.882106797398 + -5.240669196133*_Complex_I, -14.868309562238 + 6.106637681928*_Complex_I, -15.129890494726 + -2.984311531498*_Complex_I, 4.030179316698 + -51.075734845707*_Complex_I, -34.365285768090 + 9.975973436808*_Complex_I, -10.705381975285 + -9.109285126921*_Complex_I, -9.128619721470 + -32.793223942182*_Complex_I, -3.884615181749 + 5.589810405219*_Complex_I, -53.818876953386 + 9.826695061389*_Complex_I, 7.391928508119 + -6.174427305668*_Complex_I, -9.942167986468 + -39.833241210704*_Complex_I, -1.462704472474 + -2.725068915079*_Complex_I, -8.330269618062 + -2.806674135719*_Complex_I, 25.194669213199 + 30.149530622780*_Complex_I, 24.265507703667 + 35.899758345115*_Complex_I, 8.921289067584 + 4.788182047802*_Complex_I, -43.846571049868 + -11.381289894906*_Complex_I, 30.751599932238 + 20.081621692604*_Complex_I, 12.282504139594 + -23.757854873259*_Complex_I, 29.365318997990 + -23.868021174550*_Complex_I, -18.191992659645 + 23.039066554514*_Complex_I, -26.138981350472 + -27.807762467872*_Complex_I, 4.906806518050 + -64.830853635320*_Complex_I, 17.645400306096 + 6.438919813853*_Complex_I, -8.877478921993 + 22.121925579022*_Complex_I, -8.857083278794 + 2.248345191669*_Complex_I, -10.165898578719 + 14.029663983838*_Complex_I, -4.760350989354 + 14.471217793420*_Complex_I, 10.088121839257 + 10.378681492497*_Complex_I, 8.818549764286 + 28.002638865768*_Complex_I, 15.815201542566 + -8.171918556057*_Complex_I, 11.043628161039 + -4.557146048106*_Complex_I, -15.424873625059 + -1.742974782342*_Complex_I, 5.374423440509 + 15.897637103576*_Complex_I, 10.405830658480 + 5.110319843375*_Complex_I, -26.501807327618 + -12.862253830222*_Complex_I, 8.361320271594 + -12.127500776378*_Complex_I, -7.065209772913 + -13.109659416735*_Complex_I, 6.150458328525 + 21.558378724678*_Complex_I, 19.192390552195 + 57.078335145777*_Complex_I, 16.247539210043 + -5.178795721988*_Complex_I, -2.182213653083 + -31.382522380551*_Complex_I, -3.317969463714 + -1.385753951871*_Complex_I, 24.974480529165 + 22.521516957567*_Complex_I, 29.614215910955 + 22.614533535316*_Complex_I, 6.616213388437 + -6.945021315685*_Complex_I, -21.081077266042 + 27.911030510024*_Complex_I, -16.921827301441 + 18.479208860530*_Complex_I, 8.043988870051 + -36.113906522591*_Complex_I, 41.917272128407 + 26.843086076462*_Complex_I, -13.727079990761 + 5.205402325839*_Complex_I, -4.984705459021 + -6.291381865515*_Complex_I, -2.300982364859 + -21.708353496884*_Complex_I, 32.721343545850 + -16.032669392585*_Complex_I, 0.519352193540 + 45.753678340865*_Complex_I, 31.562265581157 + -4.268866755468*_Complex_I, -40.236062083037 + -2.384241501530*_Complex_I, -30.936637211857 + 3.338370340206*_Complex_I, -21.959385231675 + 0.895928669913*_Complex_I, 7.483781797051 + -52.076927900468*_Complex_I, -64.519015760392 + 10.979148490947*_Complex_I, -28.029903074937 + 7.946066875195*_Complex_I, -0.807954143368 + 10.641591910611*_Complex_I, 34.165604774109 + -19.071113266579*_Complex_I, 10.309282793998 + -14.648195920539*_Complex_I, 26.307206562160 + 3.878504634615*_Complex_I, -21.207352431217 + 12.063691363252*_Complex_I, -54.243540120475 + -0.287217034895*_Complex_I, -32.080496755198 + 30.540317997631*_Complex_I, 9.760803073410 + 16.055868478901*_Complex_I, -16.078558738770 + -5.356833086497*_Complex_I, 36.213555936943 + -24.363868386505*_Complex_I, -10.697416407844 + 24.319983619540*_Complex_I, 17.684302893605 + -12.378065186883*_Complex_I, 41.844539573965 + -46.705571091504*_Complex_I, -24.945971628906 + -10.079221453585*_Complex_I, -10.513894508491 + -4.599940107164*_Complex_I, 26.189867010892 + -17.124071629849*_Complex_I, -34.363585674086 + -4.077385676473*_Complex_I, -32.102375469900 + 18.736917526908*_Complex_I, -20.887619654518 + -54.461316084166*_Complex_I, 0.064775230615 + 24.195856216286*_Complex_I, 32.270028792805 + 48.132373628158*_Complex_I, -1.916807810798 + -12.903225028783*_Complex_I, -1.669256173251 + 16.652308679485*_Complex_I, -3.071210123118 + 18.164002571879*_Complex_I, 17.931710499892 + -13.922708426108*_Complex_I, 19.373112705930 + 8.858054642852*_Complex_I, 1.712477146172 + -34.349666851373*_Complex_I, 3.720328613972 + -37.016904392694*_Complex_I, 5.546925594994 + -0.892192373145*_Complex_I, -22.124438618468 + -41.843458261756*_Complex_I, -19.235688566387 + -2.162824631740*_Complex_I, 21.783941115220 + -6.695594391248*_Complex_I, 33.493805068723 + 62.763842873419*_Complex_I, -10.896810929881 + -8.404131804641*_Complex_I, 18.216817415924 + -33.590802005326*_Complex_I, -25.763824584844 + -6.302405967415*_Complex_I, -15.929448259002 + 49.656053432255*_Complex_I, -2.645182567345 + 3.823015231654*_Complex_I, 33.565352588744 + -14.801476451303*_Complex_I, 34.780028538088 + 14.782512818128*_Complex_I, 22.270348337592 + 17.396233784708*_Complex_I, -23.998646351712 + -2.572970386926*_Complex_I, -5.212660897164 + -38.032125746868*_Complex_I, -5.937127593805 + -21.823373120555*_Complex_I, 12.376774565444 + 33.920254294747*_Complex_I, 19.629474738185 + -7.562284518099*_Complex_I, -25.524838793958 + -25.917842984307*_Complex_I, 7.908690793819 + 53.160190581823*_Complex_I, -22.547459647000 + -31.810110557445*_Complex_I, 14.825411801114 + -2.623765490622*_Complex_I, 21.016615330301 + 22.000151402955*_Complex_I, -3.127363744257 + -13.350072969695*_Complex_I, -57.702154359177 + -15.154831462388*_Complex_I, -13.446876000722 + -13.069388640893*_Complex_I, -2.176317185084 + 17.496721580831*_Complex_I, -54.132263906341 + 16.018239354033*_Complex_I, -3.699736432956 + 27.741980074527*_Complex_I, -7.311559889274 + -20.665154049268*_Complex_I, 6.161991265193 + -5.267960280914*_Complex_I, -0.083765300728 + -15.394352140009*_Complex_I, -10.209228018076 + -6.471795099909*_Complex_I, -0.812704485184 + -3.943529308850*_Complex_I, -3.174962269778 + -37.702639197964*_Complex_I, 14.138710546364 + 11.048967022727*_Complex_I, 6.870463853253 + 10.314002260772*_Complex_I, 3.221828051661 + 51.234801230509*_Complex_I, -2.186983936437 + 38.473329840101*_Complex_I, 13.533239595473 + 16.037592135971*_Complex_I, 39.103943522729 + 7.078614835194*_Complex_I, 30.565445217772 + 12.659846713522*_Complex_I, 30.303359360199 + -34.312315640466*_Complex_I, -20.057347170511 + 50.200448109342*_Complex_I, 15.117190448180 + 7.835893578929*_Complex_I, -15.209082571565 + 10.364865373220*_Complex_I, 9.144422828705 + -66.027702727533*_Complex_I, -18.356336362499 + -27.596404803404*_Complex_I, -21.642296590182 + -23.328234101983*_Complex_I, -38.679552975441 + -27.294969526274*_Complex_I, -17.537683264549 + 11.145767113244*_Complex_I, -28.415217286677 + 2.450538508370*_Complex_I, -7.839159290091 + 9.590153493395*_Complex_I, -4.077913680565 + 3.514849319651*_Complex_I, 36.547874214296 + -13.621221107484*_Complex_I, 14.644978554755 + -21.980389507971*_Complex_I, -3.073299724899 + -8.758687284937*_Complex_I, 35.118241555864 + -42.903789231571*_Complex_I, -22.783245832308 + -9.082081737025*_Complex_I, -25.929291660507 + 18.758508598154*_Complex_I, 33.025142390877 + 5.904152955421*_Complex_I, 11.948227318252 + 2.161590454494*_Complex_I, -1.006102550557 + -28.161894386541*_Complex_I, 45.136250419544 + 3.976787326589*_Complex_I, -33.291978336755 + 0.798986604330*_Complex_I, 11.265970488150 + -1.327315667000*_Complex_I, 3.519436365736 + 16.927952719295*_Complex_I, -33.602300462457 + 32.163188907263*_Complex_I, -8.361310619248 + -8.809090782568*_Complex_I, 11.294901581957 + -4.245164072484*_Complex_I, 14.566011481616 + 26.519668998172*_Complex_I, 14.769898592012 + 56.527707423485*_Complex_I, 33.116957851259 + -1.090132926951*_Complex_I, 20.848136410578 + 10.345884350214*_Complex_I, 18.958342797158 + 6.566708563840*_Complex_I, 15.396069027712 + -31.284159225464*_Complex_I, 2.886181696729 + 18.205515439993*_Complex_I, 2.258601161648 + -12.548779081296*_Complex_I, 18.639723094734 + -13.486140556024*_Complex_I, -11.071519074610 + -19.339094005264*_Complex_I, 16.895170033002 + -9.987185658559*_Complex_I, -3.870068718996 + 22.233540496971*_Complex_I, 8.964139966565 + -27.313941129646*_Complex_I, -17.059785268381 + -4.400625859198*_Complex_I, -6.175147302779 + 30.096445776903*_Complex_I, 18.669084089316 + 6.968259188573*_Complex_I, 7.657184873046 + -41.697203143381*_Complex_I, -33.549050077833 + 24.392895555181*_Complex_I, 13.852529446346 + -24.121363551436*_Complex_I, -8.184532144280 + -21.955892305419*_Complex_I, -19.335525950576 + 31.604135153122*_Complex_I, 30.219851790692 + 9.312089638267*_Complex_I, -9.099736227858 + 10.891340718152*_Complex_I, 8.000001281397 + -11.689007297193*_Complex_I, 15.301942508385 + -30.427794390813*_Complex_I, -7.727208416300 + 13.998979881879*_Complex_I, -6.394185171364 + 3.146108002402*_Complex_I, 9.252474513141 + -16.461589767495*_Complex_I, 26.863242542498 + 24.608331497751*_Complex_I, 46.975091007265 + -22.976780803246*_Complex_I, -46.543917156055 + 15.869672486948*_Complex_I, -4.728161553855 + 29.037018944500*_Complex_I, 4.070927662548 + -36.042387888924*_Complex_I, 14.921971168495 + 30.690814385233*_Complex_I, 35.791446149577 + 4.619796889845*_Complex_I, 2.303273709336 + 11.205822209351*_Complex_I, 8.168201691579 + -10.908743400107*_Complex_I, -0.043567851626 + 24.059334278527*_Complex_I, 7.466916906592 + 18.610504314019*_Complex_I, 7.031977571019 + -9.358602921852*_Complex_I, 5.391773391774 + -0.966245883858*_Complex_I, 3.392189608224 + -10.986430122434*_Complex_I, 34.562609814015 + 40.520419348321*_Complex_I, -9.427806154592 + 14.449317738714*_Complex_I, -28.980935248249 + 35.723542184020*_Complex_I, -25.087680212574 + -12.353756547678*_Complex_I, -10.456225394292 + 26.299032407868*_Complex_I, -3.551781425808 + 36.487758403775*_Complex_I, -13.555856836256 + 11.377498259126*_Complex_I, -5.711875186735 + 63.014002174535*_Complex_I, 8.802482546452 + -9.877617002550*_Complex_I, 12.398023754693 + -17.252746153510*_Complex_I, 48.590307765142 + -39.869959281353*_Complex_I, -4.228834590895 + -16.849706340702*_Complex_I, 1.157565934241 + 10.439891849608*_Complex_I, 6.162905961542 + -42.121455332219*_Complex_I, 18.623319771899 + 6.782479204326*_Complex_I, 40.359667537403 + -5.227038429096*_Complex_I, 3.960846512784 + -2.184979700635*_Complex_I, -11.294281203268 + 1.462688924503*_Complex_I, 4.235940899795 + -5.069039031037*_Complex_I, -19.757480291431 + -19.995127344309*_Complex_I, 9.293994179429 + 30.574726633130*_Complex_I, -11.912765926945 + 1.982525086253*_Complex_I, 32.506223545239 + -17.228481622244*_Complex_I, 23.261121675341 + -41.619757453530*_Complex_I, -16.699711374017 + 17.184396509178*_Complex_I, -30.981944222728 + 18.381540125799*_Complex_I, -28.134836328395 + -9.882313867372*_Complex_I, -40.216518853122 + 7.954899537374*_Complex_I, -17.952578865387 + 27.478809719211*_Complex_I, -28.849862783745 + 0.512912610070*_Complex_I, 21.721522411732 + -6.115881482201*_Complex_I, -82.815498795687 + -8.942733727142*_Complex_I, 3.740277816696 + -14.522905567941*_Complex_I, -35.229732095265 + 26.709488731346*_Complex_I, 11.290125122898 + 24.224877496545*_Complex_I, -16.635941007754 + 8.630637395391*_Complex_I, 22.134876007936 + 2.574582351782*_Complex_I, 33.251774617807 + 5.457413908840*_Complex_I, -3.124095302802 + -30.945315750230*_Complex_I, 25.380261145256 + -12.895408190578*_Complex_I, 29.590560891351 + -35.336175817647*_Complex_I, 23.190389336153 + -51.584432366600*_Complex_I, 23.182126536797 + -30.991661680296*_Complex_I, -37.142295822241 + 7.721940476748*_Complex_I, 26.833304952389 + 15.281809854672*_Complex_I, 3.795011817607 + 47.705908075813*_Complex_I, 44.822699796166 + 4.630736159645*_Complex_I, 20.899042041270 + 2.487657439412*_Complex_I, 8.742060078106 + 9.864203556590*_Complex_I, 16.980059178338 + 35.222546217902*_Complex_I, -19.255543627730 + 9.410996006466*_Complex_I, 21.517616907420 + 26.338377945165*_Complex_I, 48.642251867035 + 6.924884525443*_Complex_I, 23.548326097336 + 10.784367397399*_Complex_I, -11.550545599595 + -22.108959248798*_Complex_I, 16.733078720638 + -6.587000041071*_Complex_I, -24.552765736255 + 20.310652954928*_Complex_I, 17.292953612417 + 29.643678070378*_Complex_I, 9.373109698654 + 24.904713123755*_Complex_I, 25.238503675115 + -15.183892795659*_Complex_I, -1.508310287534 + -32.049583340956*_Complex_I, -1.442670825788 + -39.824563428950*_Complex_I, 3.230145000210 + -25.420530195927*_Complex_I, 13.229685977004 + -14.075607613923*_Complex_I, -19.526361502130 + -29.370000953029*_Complex_I, -21.782631521002 + -37.617721671791*_Complex_I, 27.816003478663 + 24.303079202481*_Complex_I, -43.381077867759 + 24.837480951743*_Complex_I, -9.560217395595 + 2.382563375055*_Complex_I, -1.168465306817 + 1.589115227489*_Complex_I, 52.542490127417 + 1.424383301004*_Complex_I, -10.794625364629 + -19.749473263855*_Complex_I, 26.168847841768 + -26.658825280073*_Complex_I, 4.233092270819 + -48.303662607018*_Complex_I, -5.014341149907 + -33.130134324155*_Complex_I, 9.190470374905 + -26.953795736734*_Complex_I, -2.846241405053 + -0.651859597413*_Complex_I, -20.225979212962 + -24.560140693339*_Complex_I, -10.802336686843 + 51.446188240204*_Complex_I, -9.492345818087 + -27.286465734423*_Complex_I, -24.394227434292 + 36.495286678206*_Complex_I, -4.610288224660 + 13.785902137795*_Complex_I, 25.266817655154 + 8.853318181494*_Complex_I, -1.108114899344 + -8.902780819762*_Complex_I, -34.949213732955 + 16.304692482063*_Complex_I, 12.401176411050 + -49.617470306114*_Complex_I, 13.450715987122 + 23.780568951393*_Complex_I, 0.327891662517 + 20.945521301723*_Complex_I, -24.347872941432 + -20.261920769569*_Complex_I, -3.742508301325 + 15.297035114593*_Complex_I, 20.157765205649 + -2.771550168366*_Complex_I, -26.861338262008 + 10.330263597466*_Complex_I, -19.103391377917 + 29.070399414699*_Complex_I, 33.355739256457 + 0.786653290415*_Complex_I, -15.811410357704 + 12.334342632002*_Complex_I, -31.067213179934 + 4.812703947794*_Complex_I, -38.464666136613 + -9.734460624273*_Complex_I, -27.018641211199 + -10.676307399360*_Complex_I, 10.601332462223 + 12.602266185181*_Complex_I, -14.863945203402 + 18.405001560411*_Complex_I, 6.151006234331 + -1.325265142280*_Complex_I, 10.654450023041 + 24.877489064003*_Complex_I, 7.753711320427 + -24.877496668386*_Complex_I, 14.215523169674 + 15.750750989795*_Complex_I, 10.063422021746 + 49.306566727230*_Complex_I, -83.835199786581 + -35.146747496108*_Complex_I, -0.218459362048 + -0.770721115796*_Complex_I, 22.431242892732 + -36.430877828612*_Complex_I, 17.435164403992 + -17.764746880777*_Complex_I, -18.336005961075 + -40.785661916947*_Complex_I, -9.708667273758 + -6.212236081880*_Complex_I, 15.661415503945 + -23.058769144173*_Complex_I, 6.754601945166 + -19.307935713609*_Complex_I, 21.850846235150 + 8.741417315883*_Complex_I, 25.652896421543 + 2.796534004126*_Complex_I, -1.843079544502 + 1.784869908972*_Complex_I, -2.568058272174 + -31.336348759351*_Complex_I, -23.530597236048 + 17.793870333201*_Complex_I, 41.700575857144 + 9.089193485713*_Complex_I, 44.662282998158 + -3.699022752392*_Complex_I, 29.042445473764 + -11.349519417295*_Complex_I, -7.073983554684 + 29.402856163434*_Complex_I, 19.939374137561 + -20.731019858441*_Complex_I, -27.044678373347 + -39.264065270489*_Complex_I, 20.211317017215 + 41.386816030545*_Complex_I, 1.043164784676 + -2.519947587522*_Complex_I, -6.375700266136 + -29.785712929923*_Complex_I, -27.700591743931 + 16.461560631605*_Complex_I, 10.095278660268 + 2.666042949098*_Complex_I, 6.614197587453 + -36.267409940122*_Complex_I, 3.024977063712 + 22.518622158190*_Complex_I, 22.730131517026 + 14.937191189086*_Complex_I, 0.061498915482 + -33.204005635365*_Complex_I, 3.246333795519 + 12.298349815877*_Complex_I, 5.921582958906 + 20.790686987339*_Complex_I, 22.777331137604 + 6.555360530677*_Complex_I, 21.199065974566 + 30.692801789200*_Complex_I, -1.064699299018 + -30.735783458333*_Complex_I, 1.711968922160 + 2.764830482799*_Complex_I, 57.479865205031 + 14.741051010187*_Complex_I, -5.222691142638 + -12.945556728288*_Complex_I, 24.618941208703 + -8.335156868108*_Complex_I, 5.362345191955 + -29.659123854849*_Complex_I, -13.759594910763 + -2.839225605024*_Complex_I, -0.744944069183 + 9.536259763486*_Complex_I, -7.266281313994 + -9.788530410618*_Complex_I, -16.072026028887 + 16.172115574565*_Complex_I, -6.901619139003 + -7.747255335591*_Complex_I, -16.302588968059 + -9.014933207001*_Complex_I, -9.878306363842 + -19.984075902846*_Complex_I, 2.088664771255 + -8.999802528190*_Complex_I, -21.345209871678 + -33.541210734395*_Complex_I, 12.617534995502 + -12.378687252061*_Complex_I, 10.047409736042 + -6.607933917427*_Complex_I, 9.334831941537 + 10.948924308348*_Complex_I, 25.695968260034 + 7.063988558158*_Complex_I, -9.625298547784 + 16.677076422518*_Complex_I, -3.108963319630 + 3.376941849928*_Complex_I, -47.044223301845 + -22.447723404064*_Complex_I, 6.172396063478 + 3.130567372603*_Complex_I, -12.391233504725 + -18.965209575430*_Complex_I, 7.816421386094 + -18.829210484343*_Complex_I, 2.299165958987 + 21.664313726413*_Complex_I, 23.073574880632 + -40.647794133271*_Complex_I, 11.788478207223 + 10.388520650659*_Complex_I, 2.495494346482 + -40.903748493834*_Complex_I, 9.204196215081 + 3.731305183829*_Complex_I, -11.705334181886 + -5.698373301119*_Complex_I, -10.576847226819 + -24.400174262686*_Complex_I, 1.125349170571 + -42.931316430041*_Complex_I, -34.927593970119 + 15.363588886694*_Complex_I, -5.051369474478 + 57.553472286872*_Complex_I, -17.737882109182 + 20.993190450070*_Complex_I, 37.177637689060 + 16.991173325998*_Complex_I, 44.283601354742 + 17.412222591528*_Complex_I, 36.495623940354 + -20.061033291263*_Complex_I, -0.821113211121 + -3.092318774340*_Complex_I, -22.377701901316 + -16.198210370561*_Complex_I, 12.319993479497 + -21.923811281565*_Complex_I, 15.511676349072 + -9.483307137734*_Complex_I, 20.189875802738 + -17.301968082172*_Complex_I, -5.805824615680 + -36.079316378374*_Complex_I, 30.255637146078 + -44.362762846218*_Complex_I, -20.832965183425 + -7.304495538217*_Complex_I, -13.022907320332 + -57.530437725034*_Complex_I, -10.564105798288 + -34.560059804429*_Complex_I, 21.361954258419 + -36.855969871716*_Complex_I, 4.506530938557 + 32.048954769246*_Complex_I, -33.027950438924 + 28.211482991964*_Complex_I, -29.352439177975 + 26.783042078482*_Complex_I, -28.424459734912 + -8.558362358430*_Complex_I, -19.967959416569 + 10.959195107292*_Complex_I, -23.791686165010 + 32.501306546259*_Complex_I, -33.216256571387 + 2.738726266389*_Complex_I, 8.569384712402 + 1.130870024297*_Complex_I, 28.525451062286 + 17.073062203997*_Complex_I, -1.502286920189 + -10.160446478808*_Complex_I, -6.861394365693 + 36.910381121986*_Complex_I, -6.268440765630 + -17.493038905156*_Complex_I, 11.322039030102 + -23.206689618074*_Complex_I, -8.701154518730 + 34.222038681525*_Complex_I, -24.669027160846 + -36.326555770368*_Complex_I, 20.943711343327 + -24.033336369879*_Complex_I, 29.209555657259 + -20.413413259064*_Complex_I, -2.572238542979 + -20.816303598934*_Complex_I, -1.994249544729 + 23.007487924841*_Complex_I, -44.905945955860 + 29.216643846282*_Complex_I, -24.062162530228 + 12.109221679204*_Complex_I, -12.180111153692 + 17.875695962678*_Complex_I, 20.435116656247 + 5.797199859832*_Complex_I, 3.493004564937 + -5.812772133417*_Complex_I, -27.034394973848 + 24.948810080561*_Complex_I, 21.936211599800 + -5.553436322258*_Complex_I, -4.478679537619 + -2.641131963451*_Complex_I, 5.120700840097 + 6.186528528634*_Complex_I, -47.624247374659 + -34.895963725954*_Complex_I, -43.479965560285 + 10.001886840601*_Complex_I, -20.718614873021 + 24.908643623897*_Complex_I, 9.472646766463 + -4.586461637219*_Complex_I, 9.294883958873 + 5.219642918744*_Complex_I, 24.547287109336 + 15.988189397184*_Complex_I, 12.811611969328 + -60.146862637486*_Complex_I, 33.520279815394 + 29.907221430910*_Complex_I, -14.152533165001 + -16.446995449346*_Complex_I, 23.465425390528 + -4.669981744595*_Complex_I, -29.290184394031 + -6.824899055323*_Complex_I, 36.044925366731 + 39.699979702815*_Complex_I, 45.609805078654 + -0.363597033482*_Complex_I, 12.247988815457 + -6.993931713410*_Complex_I, 14.744368729437 + 4.566968366531*_Complex_I, -3.612287261480 + -31.882623904258*_Complex_I, -4.625837065570 + -49.204985934025*_Complex_I, 10.369874666738 + 23.286668162235*_Complex_I, -29.995409795889 + 22.748837275811*_Complex_I, 7.693482749378 + 12.894738140873*_Complex_I, -74.632562519909 + -20.685236968252*_Complex_I, 24.465299052921 + -16.879295578319*_Complex_I, -17.287451187811 + -5.253265233981*_Complex_I, -12.792544818057 + -22.347701435426*_Complex_I, -30.500042038025 + -6.625643844530*_Complex_I, -25.032206738905 + -11.617648580783*_Complex_I, -33.767830120583 + -19.967382042671*_Complex_I, 8.352625196160 + -0.210944382477*_Complex_I, -2.824794695557 + 7.815259159406*_Complex_I, -30.449907818874 + -38.156235692042*_Complex_I, 34.223672868260 + 5.423974272822*_Complex_I, -3.473532089262 + -45.188663541294*_Complex_I, 1.929635364775 + -17.899772348612*_Complex_I, -17.366629103993 + 63.817371804672*_Complex_I, -23.515133356267 + -0.250964260288*_Complex_I, -26.558406280873 + 5.464454223022*_Complex_I, 7.459074663716 + -5.360173061781*_Complex_I, -2.740551125358 + -28.954513936397*_Complex_I, 26.831634155936 + 7.298762429258*_Complex_I, 26.189721830795 + 13.528176613886*_Complex_I, 0.552527132215 + 12.528332436204*_Complex_I, -18.980402436415 + 14.388413407600*_Complex_I, -2.948074258737 + -26.092284933664*_Complex_I, 11.237345817375 + 40.862341094348*_Complex_I, -31.224869298160 + 17.176727608508*_Complex_I, 2.721793055983 + -9.744545888653*_Complex_I, -0.776323448517 + -40.995023347911*_Complex_I, -49.192082010750 + 11.872769267713*_Complex_I, -43.807462185673 + -6.259081354893*_Complex_I, -2.175065114292 + 6.493046453358*_Complex_I, 23.334296943174 + 19.135612282249*_Complex_I, -6.817794711121 + 3.642740073112*_Complex_I, 11.873498813840 + 37.496197060973*_Complex_I, 14.779256218032 + -13.159994239230*_Complex_I, -19.232512636676 + 5.916208467040*_Complex_I, -0.581631693027 + 22.531394609402*_Complex_I, 1.544210909483 + 14.296122579802*_Complex_I, 7.044576628257 + -10.190237629704*_Complex_I, -4.813365711741 + 7.129670574765*_Complex_I, 41.167970529260 + -12.916981484001*_Complex_I, 26.669078124418 + -15.501207232456*_Complex_I, 12.492422072442 + -9.037015700661*_Complex_I, 17.418311261915 + 11.203344744823*_Complex_I, 18.500273199469 + 19.568644933327*_Complex_I, -23.216101473541 + -2.306087143311*_Complex_I, -1.651207984446 + 1.920560461483*_Complex_I, 22.032664625569 + -67.269204021659*_Complex_I, 2.687054355440 + -6.150483980195*_Complex_I, -42.445780624117 + -52.847480030760*_Complex_I, -18.575368994624 + -11.378786258777*_Complex_I, 12.874123481209 + 11.199236114650*_Complex_I, 6.553360933113 + -7.014357063713*_Complex_I, 24.351668075370 + 32.239707779122*_Complex_I, -3.293543380713 + 15.964518188392*_Complex_I, -15.175792848341 + -2.924538577813*_Complex_I, 17.561582795484 + -3.560828531875*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_6.c000066400000000000000000000035141474751757600214060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 6-point transform // #include float complex fft_test_x6[] = { -0.946868805918 + 0.048419613876*_Complex_I, -1.426556442325 + 1.356194807524*_Complex_I, 0.262357323076 + 1.594616904796*_Complex_I, -1.032912520662 + 0.046391595464*_Complex_I, -0.271359734201 + -2.390517158747*_Complex_I, -0.288151144041 + 0.071324517238*_Complex_I}; float complex fft_test_y6[] = { -3.703491324072 + 0.726430280150*_Complex_I, 3.797148775593 + 1.637413185851*_Complex_I, -3.456423352393 + 1.227102112087*_Complex_I, 1.791748889984 + -2.221391560299*_Complex_I, 1.220570696725 + -1.669098764217*_Complex_I, -5.330766521347 + 0.590062429687*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_63.c000066400000000000000000000166231474751757600214760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 63-point transform // #include float complex fft_test_x63[] = { -0.165065089334 + 1.102101871091*_Complex_I, -0.981973148546 + 0.541468656777*_Complex_I, -0.253554650102 + -0.121332795252*_Complex_I, 0.944969891304 + -0.207365910694*_Complex_I, 0.435801732783 + 1.116850636842*_Complex_I, -2.058668461583 + 1.768420128659*_Complex_I, 0.404062083774 + -1.055764673267*_Complex_I, -1.173590903686 + 0.058528368777*_Complex_I, -0.598414155862 + -0.497560622574*_Complex_I, -1.861198860149 + 0.229658791022*_Complex_I, -2.562456370500 + 0.495624931472*_Complex_I, 0.673656989316 + 2.905410000205*_Complex_I, 0.867056802014 + 1.798292948964*_Complex_I, -2.078980954663 + 0.098338397564*_Complex_I, -0.330038784071 + 0.481340360434*_Complex_I, 1.276384585521 + 1.297002232435*_Complex_I, 0.261810533047 + -1.797403878425*_Complex_I, -2.153713373163 + -0.426579749412*_Complex_I, 0.065709110586 + -0.887295333513*_Complex_I, -0.504714672950 + -0.491403278968*_Complex_I, 0.314910052074 + -0.711703174875*_Complex_I, 0.817545815846 + 2.684246900528*_Complex_I, 0.899097356674 + 2.316804935463*_Complex_I, 1.234132120370 + -0.619880076717*_Complex_I, 0.791329122849 + -1.491623691612*_Complex_I, -1.543373050418 + -0.676542277175*_Complex_I, 0.671442701409 + 0.216191301849*_Complex_I, 0.131373689049 + 0.579119405459*_Complex_I, -0.372079387235 + -0.810986260520*_Complex_I, 0.509295824480 + 2.533724020332*_Complex_I, 1.724705779066 + 0.166621824873*_Complex_I, 1.578021811166 + 0.495673960042*_Complex_I, -0.388517506381 + 0.654051926694*_Complex_I, 0.780148148992 + -1.186745985806*_Complex_I, -0.998699640841 + -2.290498316764*_Complex_I, 1.225655499248 + 0.539258663300*_Complex_I, 0.647174747272 + -1.701050133294*_Complex_I, -1.961810462975 + -0.885111538141*_Complex_I, 0.708722105215 + 2.298722273781*_Complex_I, 0.003407269436 + -0.160897403251*_Complex_I, -1.461677661847 + 0.035003203295*_Complex_I, -0.003031847788 + 0.263418857310*_Complex_I, -0.921189208563 + -0.548149166993*_Complex_I, 1.607243811931 + 1.460044138769*_Complex_I, 1.474955000858 + -0.319625335378*_Complex_I, -1.479420038984 + 0.442261731228*_Complex_I, -0.501705519202 + -0.107677110586*_Complex_I, -0.555052849202 + -2.288466181238*_Complex_I, 0.115695886330 + 0.958546419969*_Complex_I, -0.272372848704 + -0.160652497732*_Complex_I, 0.329785731274 + -0.424936229335*_Complex_I, 0.480745655276 + 1.205406168541*_Complex_I, 0.070825951395 + 2.104542991271*_Complex_I, -0.006185321246 + 0.587388482318*_Complex_I, -0.694069041213 + 0.770735193308*_Complex_I, 0.908386043892 + -1.602236263851*_Complex_I, -0.699555084329 + 0.976937982289*_Complex_I, -0.954674992562 + -0.016401236894*_Complex_I, -0.309302754137 + 0.958214618988*_Complex_I, -0.127271579222 + 1.856678631720*_Complex_I, -0.871347344939 + -2.036988579664*_Complex_I, 0.135839855058 + -0.627341937358*_Complex_I, -0.335848209970 + -2.547865701465*_Complex_I}; float complex fft_test_y63[] = { -7.089662066859 + 9.296545614813*_Complex_I, -8.501752827269 + 5.888942352564*_Complex_I, 3.278359396134 + 3.509899786067*_Complex_I, 5.034502581381 + -10.325422246173*_Complex_I, 0.779395837363 + -11.641131257781*_Complex_I, 6.583373182868 + -0.765170650399*_Complex_I, 7.673022911242 + 5.376349934527*_Complex_I, 6.901124231347 + -11.572359190453*_Complex_I, -12.551588348101 + -5.650836104556*_Complex_I, 13.135291423808 + -9.005088743334*_Complex_I, 6.256581548275 + 7.656394164588*_Complex_I, -9.007597317001 + 6.540328187752*_Complex_I, 5.970311877450 + 11.718061229294*_Complex_I, 3.567004157825 + 0.672928597121*_Complex_I, -14.427943038803 + 8.900678790697*_Complex_I, 1.056847529506 + 3.528462625077*_Complex_I, 13.620920754920 + 14.305922963856*_Complex_I, 8.760078200432 + 11.222488908434*_Complex_I, 5.722531558556 + 7.234622735459*_Complex_I, -5.247983376866 + -11.345081644681*_Complex_I, 1.314257740811 + 1.904662960921*_Complex_I, 0.730895747988 + 5.589496067590*_Complex_I, 6.527229987789 + -10.176960210420*_Complex_I, -4.341510788445 + -8.731233871509*_Complex_I, 7.581071089827 + -9.540336644811*_Complex_I, 4.648868334483 + -7.155035929172*_Complex_I, -2.205072254220 + 17.534621681153*_Complex_I, 6.858512702532 + 3.813829755562*_Complex_I, 0.193418696750 + 11.693363675036*_Complex_I, 5.619907773283 + 4.653892039135*_Complex_I, -1.855582230893 + 10.861851324746*_Complex_I, 14.627670681377 + -2.489204973764*_Complex_I, 0.605824410285 + -7.016190132363*_Complex_I, 2.624656390216 + 3.561441210498*_Complex_I, 0.709206425704 + 12.728091932012*_Complex_I, -3.982794699993 + 6.878915353589*_Complex_I, -13.376734767433 + 1.691306437014*_Complex_I, -2.349794152830 + -0.330132617385*_Complex_I, -3.726616620789 + 15.817788395019*_Complex_I, -16.729175354871 + -8.409111133317*_Complex_I, 17.882515293846 + -3.208404044366*_Complex_I, -7.470918853421 + 18.877686110403*_Complex_I, 12.668798353590 + -9.060907565117*_Complex_I, -6.220564671186 + -5.153664668923*_Complex_I, -1.712331740792 + -15.816196915449*_Complex_I, -11.816550492910 + 12.590312098504*_Complex_I, 5.948638061621 + 10.638444837386*_Complex_I, 13.008103746204 + -15.557670122101*_Complex_I, -13.266957624044 + 3.898836567164*_Complex_I, -1.862920665209 + -4.724933699937*_Complex_I, -4.695828593392 + 9.661188336137*_Complex_I, -7.542434926702 + 17.373541879534*_Complex_I, 1.008284652559 + 2.011360297386*_Complex_I, -6.854631802630 + -4.014486905376*_Complex_I, -6.668218293484 + 4.636855650199*_Complex_I, 3.172812378583 + -20.418734887614*_Complex_I, -23.330375903759 + -12.181015318516*_Complex_I, 6.267118807644 + 17.748053544942*_Complex_I, -8.369069881119 + 5.704956182541*_Complex_I, 9.266781179990 + -5.431082220535*_Complex_I, -2.621123339590 + -4.576508645033*_Complex_I, 3.116382580437 + -13.991211520556*_Complex_I, -15.293666222030 + 1.998407515632*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_64.c000066400000000000000000000167671474751757600215100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 64-point transform // #include float complex fft_test_x64[] = { -0.021754290353 + -0.612017802190*_Complex_I, 0.484276408753 + 0.753944723650*_Complex_I, -1.051031916820 + 0.166448506301*_Complex_I, 0.185316597591 + -0.053758419799*_Complex_I, -0.775208247301 + -1.344741618220*_Complex_I, 1.008977328193 + 0.309312932614*_Complex_I, 0.225467083836 + -1.771870588253*_Complex_I, 0.469982216778 + -1.560265270836*_Complex_I, 0.015796870295 + 0.514270976406*_Complex_I, 0.021523250463 + -1.531865633331*_Complex_I, 0.374810770914 + -1.819295376215*_Complex_I, -0.271362317574 + 1.223581370818*_Complex_I, 1.095264083148 + 0.119410767188*_Complex_I, 0.176833870554 + -0.357067009123*_Complex_I, -0.844150660609 + -0.402483548788*_Complex_I, 0.121027264669 + -1.289015413302*_Complex_I, 0.263581726117 + -1.020960568111*_Complex_I, -1.850367234488 + 0.252491065243*_Complex_I, 0.180744535235 + 0.799594483178*_Complex_I, -0.844109705065 + -0.510108698929*_Complex_I, -0.036218762055 + 1.294869055398*_Complex_I, 0.258512790360 + 0.568441072457*_Complex_I, 1.626275624183 + 0.634319322667*_Complex_I, 0.322617919951 + 0.212628458295*_Complex_I, 0.160934986434 + -0.163540330171*_Complex_I, 1.047849823612 + -0.095800483192*_Complex_I, 0.481794672802 + -0.457172404256*_Complex_I, 0.129133928192 + 0.091760813424*_Complex_I, -0.060049809575 + 0.184851257642*_Complex_I, -1.806557059379 + -0.712577972074*_Complex_I, -1.514896468556 + -0.698585251055*_Complex_I, 1.839754692918 + 0.489376426678*_Complex_I, -1.243735376399 + 1.952793219096*_Complex_I, 0.254245070501 + 1.389680075711*_Complex_I, 0.692307414060 + 1.566188401796*_Complex_I, -0.194903488026 + -0.439000848041*_Complex_I, 1.668407720772 + -0.910104238535*_Complex_I, -0.575848786837 + 0.375593796515*_Complex_I, 0.429092097669 + -0.640962925803*_Complex_I, -1.534318288920 + -1.204243660541*_Complex_I, 1.340275852733 + -1.091482736862*_Complex_I, -0.683541799234 + 1.328028176092*_Complex_I, 0.346674268228 + -1.556024203629*_Complex_I, 0.808325600843 + 0.879310154017*_Complex_I, -1.083115089529 + 0.217436971911*_Complex_I, 0.208798197538 + 1.065533831174*_Complex_I, -0.075819341427 + -1.489702533787*_Complex_I, -0.768117108951 + -0.395669850882*_Complex_I, -0.171257456484 + -1.684427171232*_Complex_I, 0.008638877159 + 0.828227749071*_Complex_I, -0.907835739258 + 1.661585546412*_Complex_I, -0.842311802407 + 0.128045074908*_Complex_I, -0.480781325156 + -0.060205164274*_Complex_I, -0.332968153644 + -0.725579827560*_Complex_I, 0.385831273126 + -0.734953099969*_Complex_I, 0.078244895870 + 0.187320802435*_Complex_I, 0.822725278030 + 1.761602936253*_Complex_I, 0.854139534803 + -0.447804374730*_Complex_I, 1.139585202373 + 0.594363516587*_Complex_I, -0.327644569515 + -1.601512234292*_Complex_I, 0.066470112247 + 0.272352995689*_Complex_I, -0.233514955808 + 0.151832081236*_Complex_I, 0.804170356884 + 0.191021429001*_Complex_I, -0.141790367715 + 0.873289762818*_Complex_I}; float complex fft_test_y64[] = { 1.725198076750 + -4.343291505303*_Complex_I, -1.306135600819 + -7.829723137959*_Complex_I, -5.438260077023 + 4.634490918041*_Complex_I, -1.955793027433 + 4.362156087676*_Complex_I, -8.012216700915 + 8.400026452278*_Complex_I, -4.952000692368 + 3.096434501516*_Complex_I, 5.298208914176 + 4.534862681807*_Complex_I, -0.880561110671 + -1.467056178833*_Complex_I, 11.861836819015 + -0.544519325409*_Complex_I, -1.503603146027 + 8.809918042520*_Complex_I, -5.363184446773 + 9.548803374715*_Complex_I, -6.505800504816 + -7.798968990377*_Complex_I, 14.636787307656 + -0.228256068710*_Complex_I, 0.052560363405 + -12.014345616554*_Complex_I, -1.959253467557 + 8.402198459668*_Complex_I, -6.980453925187 + -6.436081969205*_Complex_I, 5.388968837267 + 3.576485581891*_Complex_I, 1.433883925658 + -1.990690693711*_Complex_I, 0.745585452676 + -3.797939482423*_Complex_I, 2.695240683264 + -0.969955745711*_Complex_I, -6.338874171853 + -7.732858525855*_Complex_I, 11.298952810793 + -13.037152643099*_Complex_I, -15.351176639589 + 9.947482416391*_Complex_I, -5.345010122884 + 0.498205314186*_Complex_I, -4.369620686268 + 0.751093800562*_Complex_I, 7.632293961493 + 0.946244674824*_Complex_I, -2.209404645076 + -8.887676077977*_Complex_I, 9.546753476599 + -11.691028922291*_Complex_I, -10.473480711255 + 0.645167184977*_Complex_I, 9.912509001236 + -22.116979184633*_Complex_I, 7.805895621936 + 2.010265856692*_Complex_I, -7.638461665175 + 0.687493859037*_Complex_I, 5.983512814381 + -4.711548846349*_Complex_I, 1.432584757253 + 2.618196841573*_Complex_I, -16.409812005381 + 2.126260364995*_Complex_I, -4.891966320361 + 4.829626903245*_Complex_I, -3.218785198666 + -4.443535570591*_Complex_I, 2.772033282272 + -1.143468987354*_Complex_I, -8.913495498818 + 3.327029248182*_Complex_I, 8.015679354394 + -3.131930356460*_Complex_I, 1.419572328954 + -0.132902166668*_Complex_I, 3.850100186885 + 9.527061186961*_Complex_I, 0.681611518886 + 4.259777024769*_Complex_I, 12.246604521898 + -0.790289131992*_Complex_I, 3.241695686006 + -15.727090004602*_Complex_I, -9.932323330295 + -0.102559333310*_Complex_I, -2.411503210251 + -0.408856287097*_Complex_I, 1.884210002432 + 7.477017352531*_Complex_I, -6.852334636700 + 3.198788969708*_Complex_I, 1.141049818230 + 1.542427926488*_Complex_I, 0.732333269451 + -1.802063276954*_Complex_I, -6.450414970103 + -2.758985609350*_Complex_I, -3.738653299253 + -7.196005387959*_Complex_I, 7.300969515165 + -7.844893935009*_Complex_I, 8.053617788503 + 5.389482632745*_Complex_I, 9.227999871537 + -2.302018386805*_Complex_I, -5.824592830409 + -0.544198322926*_Complex_I, -3.152065877231 + -6.410831104251*_Complex_I, -1.003575490144 + 23.308352736314*_Complex_I, 1.725485190234 + -10.960063101324*_Complex_I, -14.199659988605 + 7.198846575963*_Complex_I, 4.186354051025 + -2.044041800204*_Complex_I, 14.017389932813 + 2.146139910120*_Complex_I, 4.242720273094 + -3.627670543295*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_7.c000066400000000000000000000036601474751757600214110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 7-point transform // #include float complex fft_test_x7[] = { 0.325737557343 + 0.347762560645*_Complex_I, -0.464568614672 + 1.344201995758*_Complex_I, -1.458140194879 + 0.983317270098*_Complex_I, 1.679041515327 + 1.025013762005*_Complex_I, -0.178483024495 + -0.711524629930*_Complex_I, 0.986194459374 + -1.709315563086*_Complex_I, 0.387998802736 + -1.150726066104*_Complex_I}; float complex fft_test_y7[] = { 1.277780500734 + 0.128729329387*_Complex_I, 4.360250363806 + 2.591163135631*_Complex_I, 1.609972293897 + 2.377175130550*_Complex_I, 0.436888889637 + -3.701058823864*_Complex_I, -0.903757801309 + 3.003131513942*_Complex_I, 1.797162255231 + -0.068636624441*_Complex_I, -6.298133600593 + -1.896165736688*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_79.c000066400000000000000000000217231474751757600215020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 79-point transform // #include float complex fft_test_x79[] = { -0.831644933479 + -1.369566252119*_Complex_I, 1.382261515245 + 0.344632239578*_Complex_I, 1.522173067917 + -0.879128649493*_Complex_I, 0.412263305825 + -2.214373495146*_Complex_I, 0.167471424272 + 2.442885876862*_Complex_I, -0.995700286447 + -0.269798312873*_Complex_I, -0.495500240228 + -1.483255164915*_Complex_I, -1.294110579031 + 0.198434791977*_Complex_I, -0.725558739350 + 0.113152102484*_Complex_I, 0.245130536761 + -1.776484046331*_Complex_I, -0.902695579029 + -0.321701515101*_Complex_I, 0.612573133829 + 0.706900606440*_Complex_I, -1.446805571584 + 0.549130825767*_Complex_I, 0.779487733787 + 1.006717179605*_Complex_I, 0.482652400616 + -0.602577004101*_Complex_I, -0.075416135474 + 0.994234640494*_Complex_I, 1.169794509155 + 0.142737162623*_Complex_I, -0.552532601786 + -0.192607542361*_Complex_I, 0.410837027020 + -0.565889656334*_Complex_I, 0.141957082162 + -0.801461876260*_Complex_I, -0.593199921160 + 0.901175943982*_Complex_I, -1.360958657407 + -0.483045804780*_Complex_I, -1.919982203277 + 0.057049812902*_Complex_I, 0.597068489025 + 1.216028879537*_Complex_I, 0.553702635589 + 1.236264938570*_Complex_I, -0.600595429992 + 0.147163421599*_Complex_I, 0.311936436694 + -0.216250614525*_Complex_I, -1.091501993588 + 0.833497783365*_Complex_I, 1.744199597330 + 0.588786957660*_Complex_I, 2.530575868723 + 1.039372684186*_Complex_I, 1.028391846884 + -0.023635041523*_Complex_I, 1.289280692909 + -1.032658504022*_Complex_I, -0.717633308140 + -0.744729509226*_Complex_I, 0.305920738055 + 0.657498377749*_Complex_I, -1.129964121827 + -0.435663177627*_Complex_I, 1.648005569065 + 1.195099617541*_Complex_I, -2.115562921407 + -1.910525019001*_Complex_I, -0.596385890353 + 0.887009643025*_Complex_I, -0.230825994339 + -0.188182502664*_Complex_I, 0.263886383603 + -0.439257543266*_Complex_I, -0.523070205646 + 0.777409974948*_Complex_I, -0.219529035132 + 1.383569408478*_Complex_I, -0.718591132998 + 0.789138773979*_Complex_I, -0.584598456206 + 0.201764886974*_Complex_I, -0.569756495022 + -0.592160140902*_Complex_I, 0.187040275696 + 1.071817729923*_Complex_I, -0.157385303066 + -0.207843225364*_Complex_I, 1.277595054999 + -0.235819967829*_Complex_I, -0.096458535032 + 0.092010581965*_Complex_I, 0.359513513761 + 0.945023449614*_Complex_I, -0.907097860111 + 0.645605162871*_Complex_I, -0.651303141773 + 2.145291744091*_Complex_I, 0.114198590617 + 1.903139164821*_Complex_I, -0.079111313379 + 0.022610329502*_Complex_I, -1.170099271217 + -0.560852156056*_Complex_I, -0.857261592064 + 0.764585655287*_Complex_I, -0.308274947188 + 0.793759490894*_Complex_I, 1.075701520371 + 0.665603485423*_Complex_I, 0.121769228873 + 1.080351294531*_Complex_I, 1.775909597196 + -0.152691005919*_Complex_I, 1.592857837122 + 1.642268527260*_Complex_I, 0.206041280093 + 0.680507676427*_Complex_I, -0.447718650910 + -1.049968522775*_Complex_I, -1.571476809016 + 0.131194680122*_Complex_I, 1.668956017050 + -0.788549453555*_Complex_I, -1.464619492806 + -0.514115875797*_Complex_I, 2.085001980617 + 0.514847563050*_Complex_I, 0.928930120111 + -0.581073787447*_Complex_I, 0.446239202479 + -0.653366428964*_Complex_I, 1.064861444804 + -0.041135862801*_Complex_I, 0.072500637635 + 1.082811081123*_Complex_I, -1.400912797632 + -0.318643643314*_Complex_I, -0.475876438927 + 0.416837808588*_Complex_I, -0.066362697792 + 0.020225742927*_Complex_I, -0.153794040015 + -0.251785474065*_Complex_I, -1.237542116335 + 0.809600386690*_Complex_I, 0.871326964554 + 0.924351961256*_Complex_I, -2.389508044422 + -0.601457844861*_Complex_I, 0.080578131708 + 0.388813172800*_Complex_I}; float complex fft_test_y79[] = { -2.198332092440 + 12.650658598176*_Complex_I, -6.456670989242 + -7.479301674890*_Complex_I, -2.895336385229 + 1.221846928494*_Complex_I, -4.636342294176 + -0.801909581371*_Complex_I, -9.731802903280 + -5.232001275010*_Complex_I, 6.761030360809 + -1.721885218978*_Complex_I, 1.867893673405 + -10.436764472711*_Complex_I, 7.129857916226 + -15.261303660272*_Complex_I, 16.581711031970 + 5.179082607705*_Complex_I, -16.126836936739 + -5.300370279404*_Complex_I, -4.576577504775 + -12.699766318030*_Complex_I, -7.579093623452 + -12.405022376124*_Complex_I, -1.692330593182 + -8.516631597504*_Complex_I, -6.195245930268 + 0.070273567822*_Complex_I, 1.551185200774 + -5.151973196311*_Complex_I, -7.892299216869 + -6.606437030189*_Complex_I, 11.038003489600 + 4.657211823028*_Complex_I, 7.075974564323 + 0.545694748078*_Complex_I, -6.869510368707 + -0.939533375646*_Complex_I, -12.801782277417 + 4.703619318878*_Complex_I, 4.730103334639 + 3.588402018073*_Complex_I, 4.302722751897 + 5.818086352910*_Complex_I, 2.141745733069 + -1.961941960610*_Complex_I, 5.318048536295 + -0.010643144676*_Complex_I, 10.574791653730 + -2.110839910741*_Complex_I, 18.403982142892 + -4.968829844315*_Complex_I, -4.861819678415 + 0.167673326078*_Complex_I, -2.630720570170 + 1.594403564449*_Complex_I, 0.363441779769 + -10.436412333140*_Complex_I, -8.279198460723 + -3.380426807459*_Complex_I, -0.740797623754 + -2.814734090095*_Complex_I, -9.827753678018 + -12.010129525106*_Complex_I, 0.873038175248 + -1.031218712521*_Complex_I, -8.699339400800 + 12.933077680277*_Complex_I, -5.053719376427 + 3.839008815587*_Complex_I, -17.469957324379 + -0.249103089343*_Complex_I, 3.184401964192 + 3.862169536519*_Complex_I, 0.438203015374 + -2.050441604463*_Complex_I, -14.617902230891 + 13.404027008609*_Complex_I, -3.326663756629 + -9.464457202630*_Complex_I, -16.780077393079 + 4.427043334783*_Complex_I, 2.414049361911 + -12.349549334690*_Complex_I, -2.071827347449 + 0.131158553257*_Complex_I, 12.619462722043 + 3.785353059626*_Complex_I, 0.681152626465 + -5.767839231705*_Complex_I, -2.536944134501 + -4.990736350292*_Complex_I, -9.887559098728 + -30.445442814418*_Complex_I, -8.158210630371 + -2.609637272072*_Complex_I, 14.923059038703 + 2.059503206139*_Complex_I, 4.682549931928 + -0.864654149312*_Complex_I, 3.308241623127 + -8.932248210446*_Complex_I, -7.447372005399 + -15.848177608870*_Complex_I, 11.470445857602 + -17.244634800179*_Complex_I, -0.352198189530 + -5.465835457604*_Complex_I, 0.595131131258 + 1.784167835328*_Complex_I, -4.958773866897 + 1.052005175981*_Complex_I, -8.549314756256 + 10.245571680581*_Complex_I, -13.074676867355 + -9.163782974489*_Complex_I, -2.244945835090 + 13.220346166155*_Complex_I, -4.198374817495 + 10.065229182925*_Complex_I, -0.700355709960 + 6.827087899627*_Complex_I, 2.412030908809 + -6.042014368503*_Complex_I, -1.467215162979 + 16.669129234939*_Complex_I, 1.755798753328 + -6.540065639162*_Complex_I, -6.456991908144 + -7.304947059496*_Complex_I, -2.375547326101 + 18.123374474356*_Complex_I, 6.311057482521 + -9.358027340793*_Complex_I, 2.466570091641 + 5.305925828815*_Complex_I, 0.001957161866 + 18.960020221647*_Complex_I, -3.859854792754 + -4.745420470903*_Complex_I, 2.984060727978 + -4.759922601530*_Complex_I, 4.314065539668 + -4.099188676984*_Complex_I, -4.122177040779 + 6.664910801689*_Complex_I, 4.892466468902 + 19.707013122151*_Complex_I, 21.618605295806 + -12.301445853986*_Complex_I, -0.720795540227 + 3.447422417270*_Complex_I, 6.265639354108 + 13.611595323686*_Complex_I, -11.081101178789 + -14.511845349920*_Complex_I, 4.451917671114 + -12.130333484146*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_8.c000066400000000000000000000040241474751757600214050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 8-point transform // #include float complex fft_test_x8[] = { 1.143832659273 + 0.058730029889*_Complex_I, -0.094390429919 + 0.229144161540*_Complex_I, -0.231936945111 + 0.250418514706*_Complex_I, 0.180568135767 + -0.869698396678*_Complex_I, -0.345282052584 + 1.176003338020*_Complex_I, 0.544428216952 + -0.610473584454*_Complex_I, 0.928035714223 + 0.647778401795*_Complex_I, 0.441211141066 + -1.176622015089*_Complex_I}; float complex fft_test_y8[] = { 2.566466439667 + -0.294719550271*_Complex_I, 1.635071437815 + 1.055386414782*_Complex_I, 1.767442826430 + 0.508277941207*_Complex_I, 2.964612333261 + -2.017902163711*_Complex_I, 0.422832311935 + 4.560580119089*_Complex_I, 0.548438211721 + -0.969987712376*_Complex_I, -1.562539151277 + 0.164794961607*_Complex_I, 0.808336864628 + -2.536589771219*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_9.c000066400000000000000000000041701474751757600214100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 9-point transform // #include float complex fft_test_x9[] = { 0.318149471742 + -0.872622265472*_Complex_I, 0.380460329361 + 0.204662364547*_Complex_I, -0.569767779072 + -0.271995206036*_Complex_I, 1.334787120105 + -0.238015105170*_Complex_I, -0.644864052383 + 0.948536285238*_Complex_I, -0.489784794370 + 0.158143326416*_Complex_I, 1.783096398872 + -2.166235062454*_Complex_I, -0.138901921376 + -0.646377338691*_Complex_I, -0.257444231274 + 0.857372365765*_Complex_I}; float complex fft_test_y9[] = { 1.715730541604 + -2.026530635857*_Complex_I, 1.685963762512 + 0.399226582084*_Complex_I, -4.115380429157 + 1.255898079784*_Complex_I, 4.091196716626 + -4.693323087763*_Complex_I, -1.668677608930 + -1.439432143007*_Complex_I, -2.523905986916 + -0.920217192051*_Complex_I, 4.501171713926 + -3.110763575667*_Complex_I, 1.269999384456 + 3.193455688437*_Complex_I, -2.092752848444 + -0.511914105207*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_92.c000066400000000000000000000243471474751757600215020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 92-point transform // #include float complex fft_test_x92[] = { -1.533248238739 + -0.465630703218*_Complex_I, -0.249958865116 + 0.582751340535*_Complex_I, -0.052014206281 + 0.945510877668*_Complex_I, 0.566817251755 + 0.873302572342*_Complex_I, -1.076106091336 + -0.264177557543*_Complex_I, 0.170852437277 + -0.619571758149*_Complex_I, 0.440747636244 + -0.170212602153*_Complex_I, 0.354775561873 + -0.272786796202*_Complex_I, 1.853177639448 + -1.188389922347*_Complex_I, 0.410907829911 + -0.451660724815*_Complex_I, -0.650435006722 + 1.672142963707*_Complex_I, -0.488214214181 + -0.805655420589*_Complex_I, -0.731929006826 + 1.054082992594*_Complex_I, -0.288141810907 + 0.209057566980*_Complex_I, -0.611240793053 + 1.293902538452*_Complex_I, -1.776441085660 + 0.958157296522*_Complex_I, -0.692307740144 + 0.075952098739*_Complex_I, 0.179804764868 + 1.730521926975*_Complex_I, -0.314045230459 + 1.905941797877*_Complex_I, 1.110105359337 + 1.465687036226*_Complex_I, -1.650241785564 + -2.376992111936*_Complex_I, 1.355816874526 + -2.252579556526*_Complex_I, 1.314750282984 + 0.595272183468*_Complex_I, 0.387080055146 + 0.205073570108*_Complex_I, -1.088814882881 + 1.793386020599*_Complex_I, -0.720166712307 + 0.890262821808*_Complex_I, -0.062602073879 + -0.031786415520*_Complex_I, -0.888507446134 + -0.536607709525*_Complex_I, -0.510561833378 + -0.675309226502*_Complex_I, 0.453615728261 + -0.387399412056*_Complex_I, 2.033274332370 + 1.120734915608*_Complex_I, 0.361177016452 + 0.840380849208*_Complex_I, 0.907153428882 + 0.117975673876*_Complex_I, 0.959754000635 + -0.182686914078*_Complex_I, -1.880157998612 + 1.024007596710*_Complex_I, -0.355239481254 + -1.157943305297*_Complex_I, 0.732180611349 + 0.476767076883*_Complex_I, 0.217871850693 + 0.378282281897*_Complex_I, 0.708348214996 + 1.015785074730*_Complex_I, 1.376611167796 + 0.025670694927*_Complex_I, 0.795489734327 + 2.447726960093*_Complex_I, -0.401589815356 + -1.887124361666*_Complex_I, -0.332674038856 + 0.654292754224*_Complex_I, 0.050773204061 + 1.851727945919*_Complex_I, 1.040820725747 + 0.163264568160*_Complex_I, -0.473870168659 + -0.135085060425*_Complex_I, -0.405218690036 + -0.210036331236*_Complex_I, -1.048228113315 + 1.224144846525*_Complex_I, -1.039363245830 + 0.571242521536*_Complex_I, 0.434387333441 + -0.667088930502*_Complex_I, 1.323498894566 + 0.321341399415*_Complex_I, -0.111430629981 + -0.911660421532*_Complex_I, -2.119793066060 + -0.604468380769*_Complex_I, -0.759768309222 + -1.196195111817*_Complex_I, -0.117965675009 + -0.853563152009*_Complex_I, 0.776854555180 + -1.044436698117*_Complex_I, -0.208543038837 + -0.719688047768*_Complex_I, 0.329085055714 + -0.731568530556*_Complex_I, 0.948200526516 + 0.778615477506*_Complex_I, -1.004787748593 + -1.447117819386*_Complex_I, -0.370036778975 + -1.041283005778*_Complex_I, 0.278647623179 + 0.132465770957*_Complex_I, -0.241472714303 + -0.804153723576*_Complex_I, -2.065839345003 + -0.285350361634*_Complex_I, 0.709097179382 + 1.197671609730*_Complex_I, -0.276234692523 + -0.085308137997*_Complex_I, -0.892034005938 + 1.470177172557*_Complex_I, 2.111093179577 + 0.214091335543*_Complex_I, 0.348125157569 + 0.660499475216*_Complex_I, -0.440004517499 + -0.381421105771*_Complex_I, -0.121445816759 + -0.900682972998*_Complex_I, 0.219762835492 + 0.024815977673*_Complex_I, -0.179837662261 + 0.545204347104*_Complex_I, 0.575266794792 + -0.857820948237*_Complex_I, -0.665258207110 + -0.142008087173*_Complex_I, 0.926210675302 + 0.676996743235*_Complex_I, -0.358453435398 + 0.218721578288*_Complex_I, 0.465198395168 + 0.321437159886*_Complex_I, -0.700888464307 + 0.026867992734*_Complex_I, 0.077912840097 + -0.700256177377*_Complex_I, 0.814218687572 + -0.237318115696*_Complex_I, 0.735605726247 + -0.843989440195*_Complex_I, 0.326456107919 + 1.621890601713*_Complex_I, 0.279920713907 + 1.255568802945*_Complex_I, -0.587220611906 + 0.854502071021*_Complex_I, 0.287904397154 + 1.370012449616*_Complex_I, 0.262419514043 + 0.783285944590*_Complex_I, -0.960094532334 + -1.295021304935*_Complex_I, 1.282525406387 + -0.543459424061*_Complex_I, -0.533518221919 + -0.066344323134*_Complex_I, -1.343771938200 + -0.320382155842*_Complex_I, -0.432681592095 + 0.159701208438*_Complex_I}; float complex fft_test_y92[] = { -2.518102271573 + 10.044654216417*_Complex_I, 6.643542265073 + 4.256887583025*_Complex_I, -11.918532524663 + 7.755442009935*_Complex_I, 7.568118092597 + -13.006486128008*_Complex_I, -18.363301435074 + -1.152166283835*_Complex_I, -5.786681211618 + -13.408541093492*_Complex_I, -8.010496951983 + 2.213039809355*_Complex_I, -1.411436744972 + 0.130962118237*_Complex_I, 7.222128824656 + 8.763744480410*_Complex_I, 13.775439027085 + 2.076241093317*_Complex_I, 6.773877664536 + -6.756550626162*_Complex_I, -7.137502543426 + 22.613697101003*_Complex_I, 9.970236986411 + 8.723751585267*_Complex_I, 3.388712243523 + -19.707507460853*_Complex_I, -22.698345626199 + -8.699233708477*_Complex_I, 2.966129501632 + -5.083169407361*_Complex_I, 0.748694115570 + 1.246761748677*_Complex_I, 7.286176947585 + -17.177394603147*_Complex_I, -4.640184708188 + -4.742141169474*_Complex_I, -15.653012036283 + 3.723708191064*_Complex_I, -0.304540600637 + 8.131182330682*_Complex_I, 6.514836424576 + -3.631934956688*_Complex_I, 14.631671446075 + -12.918654725994*_Complex_I, -9.079675359871 + -12.980498823161*_Complex_I, -2.396312070783 + -0.555311616694*_Complex_I, -5.516481227937 + 5.537031351170*_Complex_I, 16.946789253652 + -11.802977753669*_Complex_I, -9.863602251151 + 17.961504389879*_Complex_I, -1.089641984420 + 8.797684899764*_Complex_I, -3.199834226297 + -5.263692533431*_Complex_I, 3.613039090453 + 21.668260647267*_Complex_I, 4.356502756142 + 3.769573390222*_Complex_I, -11.010076007411 + -0.606073476312*_Complex_I, 1.249394309031 + 10.604580497016*_Complex_I, 0.432971670642 + -8.028445673142*_Complex_I, 1.772492721651 + -3.463373418618*_Complex_I, -12.314467825833 + -13.413674383092*_Complex_I, -4.796108671665 + -1.279659252444*_Complex_I, -4.135554898661 + 6.501150787072*_Complex_I, 4.235361817536 + 7.284416823675*_Complex_I, 4.645716809901 + -20.010236546155*_Complex_I, -11.820881373135 + -3.121702955852*_Complex_I, -1.176033491231 + -12.716343647780*_Complex_I, 0.309217041323 + 1.171408626241*_Complex_I, 7.362816400606 + 0.244428623814*_Complex_I, -5.010068913978 + -5.765683583933*_Complex_I, -6.876294123140 + 17.669794480924*_Complex_I, -3.948263111315 + -6.648206550629*_Complex_I, 2.175533159130 + -1.121668038664*_Complex_I, 10.506942679678 + 0.132441506635*_Complex_I, -6.051550803688 + -3.522998291999*_Complex_I, -12.716395512066 + -1.993147768949*_Complex_I, 0.716905419911 + -2.118308817826*_Complex_I, -6.214220320215 + 9.890190258116*_Complex_I, -3.496757347797 + 0.760118583470*_Complex_I, -0.165689780061 + 9.326952571297*_Complex_I, 3.608065605999 + 1.223288778006*_Complex_I, -15.368180054772 + 4.696419623807*_Complex_I, 6.532262844351 + -15.337625047848*_Complex_I, 11.463488167992 + -13.033909534322*_Complex_I, -3.089385178638 + 2.386958780173*_Complex_I, -8.764516788755 + -15.458094712422*_Complex_I, 5.161844954690 + 3.690438400691*_Complex_I, 7.483979541054 + 5.496267849787*_Complex_I, -3.191656352209 + -2.378455932485*_Complex_I, 3.346071918545 + -5.947101296914*_Complex_I, -7.911752024929 + 15.534843484634*_Complex_I, 4.990245834162 + -8.000769949862*_Complex_I, 3.430754206047 + -6.541036958204*_Complex_I, 3.819396364706 + -6.492827881304*_Complex_I, -5.791806578535 + -3.103857093968*_Complex_I, -0.378045544744 + 7.208602763143*_Complex_I, -6.569094552634 + -15.273087240577*_Complex_I, 2.045385676585 + 5.705039211157*_Complex_I, -3.551170334917 + -9.324062375092*_Complex_I, -3.762304723821 + 6.431485809437*_Complex_I, -13.592727599777 + -3.762490773764*_Complex_I, 14.293467882786 + 15.519778083180*_Complex_I, 7.838444610094 + -5.394721016744*_Complex_I, -6.164859647536 + 2.323160141970*_Complex_I, -6.775035839038 + 3.176555591565*_Complex_I, 3.450970697637 + 5.952471575141*_Complex_I, -9.694440566030 + 17.192480020342*_Complex_I, -4.389843029510 + -14.424868721698*_Complex_I, -13.182552822942 + -10.208834890358*_Complex_I, -15.936588561479 + 10.544520991017*_Complex_I, -14.982276290696 + 9.596052705212*_Complex_I, 2.219118227020 + -0.954468671057*_Complex_I, 8.714041016800 + 4.805998810501*_Complex_I, -6.362077161917 + -2.563077169544*_Complex_I, 5.636818008460 + -11.718358270750*_Complex_I, -12.128080581717 + 5.291433812970*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_data_96.c000066400000000000000000000251671474751757600215070ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data for 96-point transform // #include float complex fft_test_x96[] = { 0.231855789328 + 0.392790591230*_Complex_I, 0.454049797380 + 0.679061446432*_Complex_I, 0.528744029877 + -0.002005026486*_Complex_I, 0.585153010445 + -0.548050212091*_Complex_I, -0.688324957589 + -1.837254802682*_Complex_I, -1.210661843723 + -0.571711786295*_Complex_I, 1.276297465652 + -1.918840937281*_Complex_I, 0.903361922100 + -1.011460232753*_Complex_I, 0.477567600087 + 1.205903424233*_Complex_I, -0.786388960666 + 1.649160493258*_Complex_I, -0.690114487232 + 0.189150053367*_Complex_I, -0.123298428085 + 1.440273117047*_Complex_I, -1.824871622703 + -0.028412622663*_Complex_I, -0.005824551846 + -1.985955234017*_Complex_I, 0.441673373932 + 2.184282527711*_Complex_I, -0.302888535198 + 0.442593100570*_Complex_I, -1.138671997435 + 0.800927463670*_Complex_I, -0.113113592732 + 0.764107269897*_Complex_I, -1.301467098151 + 1.879202303512*_Complex_I, 1.216552799598 + 1.187277605073*_Complex_I, -0.414624947172 + -0.192700931033*_Complex_I, 0.157426358097 + -0.883438491265*_Complex_I, 1.314432283757 + -2.209536410386*_Complex_I, 0.115962402453 + 0.100570503666*_Complex_I, -0.184110258490 + -0.274585396498*_Complex_I, 1.182232744060 + -0.525435229715*_Complex_I, 1.369228680727 + -1.296270108729*_Complex_I, 0.679139800457 + 0.521729684119*_Complex_I, 1.466742696053 + -1.109181731398*_Complex_I, 0.423928449957 + 0.893374724805*_Complex_I, 0.097387993047 + -1.166367457697*_Complex_I, -0.319951780834 + 0.333472678246*_Complex_I, -0.851035928014 + 1.174430249645*_Complex_I, -0.741367318352 + 0.683540921651*_Complex_I, 0.063169486746 + 0.571172676088*_Complex_I, -1.973683326170 + -1.139982408570*_Complex_I, -0.176533972367 + 2.303718667820*_Complex_I, 1.427168284563 + 0.147925345978*_Complex_I, 0.168590812490 + 1.242460845878*_Complex_I, -0.463999677511 + -0.037151173794*_Complex_I, -2.536137467463 + -1.681395390537*_Complex_I, -0.968155862697 + 1.560777014683*_Complex_I, 0.679881050576 + 1.356938443072*_Complex_I, 0.882676978778 + -0.850244916120*_Complex_I, 0.356671274755 + -0.673629272452*_Complex_I, 0.770786696014 + 1.394669751828*_Complex_I, 1.879418388790 + -1.423104148622*_Complex_I, -1.625009605282 + 1.071684804070*_Complex_I, 0.523881317301 + -1.877721023134*_Complex_I, -0.810889778170 + 0.977110976206*_Complex_I, 1.184940081921 + 1.172520365453*_Complex_I, 0.614349326074 + 0.102072818821*_Complex_I, -0.022137672632 + -1.083247965012*_Complex_I, -0.608327216411 + -0.797618802167*_Complex_I, 1.718428073949 + -1.056519198093*_Complex_I, 0.060567885123 + 1.676707157575*_Complex_I, -0.495113579030 + 0.653357680357*_Complex_I, -0.854188871032 + 0.411288746049*_Complex_I, -0.410417801407 + 0.607919306211*_Complex_I, -1.442853726865 + -1.517927421271*_Complex_I, 0.274363566701 + 0.446776625735*_Complex_I, -0.625143151100 + 1.305210751509*_Complex_I, 1.212571305417 + 0.002561202196*_Complex_I, 0.964380743057 + -0.130831945021*_Complex_I, -1.467000571347 + -0.173752863470*_Complex_I, -0.361064943808 + -0.453821406270*_Complex_I, -0.435558558438 + -0.349465935625*_Complex_I, 1.160653554933 + 0.097609577607*_Complex_I, 0.824326827067 + -0.141377219902*_Complex_I, 0.151294380041 + 0.722300985052*_Complex_I, -0.160268192079 + 2.322410769696*_Complex_I, 1.756726727738 + -0.285586369209*_Complex_I, -1.614230674187 + -0.241407720255*_Complex_I, -0.035193854160 + -0.456767111405*_Complex_I, 1.997549686826 + 0.610571776676*_Complex_I, -1.013290679060 + 1.072224366678*_Complex_I, 0.966131190541 + 1.156926252511*_Complex_I, -0.085548688965 + -1.173983462045*_Complex_I, -1.258925646165 + 0.570319789600*_Complex_I, -0.009163839577 + -0.458346841578*_Complex_I, 0.328942919560 + -0.410428744477*_Complex_I, 1.359093898482 + -0.077096836434*_Complex_I, 0.269427793307 + 1.756132969724*_Complex_I, -1.612257645892 + 1.531514720616*_Complex_I, 1.344264226102 + 0.027502937744*_Complex_I, 1.369576658531 + 0.382536868127*_Complex_I, 0.172747665849 + 0.388258199964*_Complex_I, -0.226008514710 + -0.315160242926*_Complex_I, 0.150075935489 + 0.260574914740*_Complex_I, -0.170611752947 + -1.382717411879*_Complex_I, -1.216483547464 + -0.767792980333*_Complex_I, -1.976466005823 + 0.458969099499*_Complex_I, -0.645507778235 + 2.051797937683*_Complex_I, 0.981465939529 + 2.517091270417*_Complex_I, 1.174746235178 + -1.612669537430*_Complex_I, 0.896264508571 + 0.843449048976*_Complex_I}; float complex fft_test_y96[] = { 4.609981707790 + 14.165957863955*_Complex_I, -2.663372690989 + 3.381865489792*_Complex_I, -6.250889898983 + 0.856018997500*_Complex_I, 4.388447703102 + 0.709127580060*_Complex_I, 10.524498612708 + -15.765075233017*_Complex_I, -21.883023288862 + -5.754013136199*_Complex_I, -3.032497734395 + 3.435059152768*_Complex_I, 10.141510735231 + 6.569590619684*_Complex_I, -3.943788049939 + 4.985622407622*_Complex_I, -8.471948591549 + 3.436253039913*_Complex_I, -8.880296739352 + 18.329925169953*_Complex_I, 8.081550419966 + 4.959140273664*_Complex_I, 1.902048356207 + 12.753862442288*_Complex_I, 23.710137236631 + -5.734748416060*_Complex_I, 18.967547060099 + 2.261420011861*_Complex_I, -13.117649377758 + 5.255774731680*_Complex_I, 2.565218803705 + -25.049831530536*_Complex_I, 0.395850231743 + -4.532129398987*_Complex_I, 6.995600852169 + -7.386596256854*_Complex_I, -2.132719003770 + 6.698594558144*_Complex_I, -9.929306991332 + 6.869396317874*_Complex_I, 11.346428057260 + 15.752032502527*_Complex_I, -10.078874711603 + -6.207899239799*_Complex_I, -4.061971394211 + 1.001130636914*_Complex_I, -13.995272885614 + -4.455343352338*_Complex_I, 4.451519347892 + 7.926049461659*_Complex_I, 16.857007165977 + 8.029468101958*_Complex_I, 6.827258648561 + 14.930217154284*_Complex_I, -0.559549304382 + 8.208567303238*_Complex_I, -3.551940117450 + -7.211758268580*_Complex_I, 1.734999071287 + -3.632491293309*_Complex_I, -7.304392369767 + -14.527214303395*_Complex_I, -11.262783549629 + -1.605589170344*_Complex_I, -11.512374272203 + 16.561245028560*_Complex_I, 7.482726055364 + -2.727439658405*_Complex_I, 15.246746816163 + 17.569026228008*_Complex_I, -15.136445648942 + -1.722052787143*_Complex_I, -0.596784032900 + 1.036483442957*_Complex_I, -8.295090222700 + -14.787777542426*_Complex_I, -10.388667668932 + -3.677948124346*_Complex_I, 1.442374069335 + 2.369895137413*_Complex_I, -11.286677919418 + -0.442216831320*_Complex_I, -4.258359681535 + -5.877299409944*_Complex_I, 8.474879358850 + 11.133599053803*_Complex_I, 4.521324398684 + -5.575361516985*_Complex_I, -10.852733452716 + -8.187793263992*_Complex_I, 10.282241432010 + -14.787653906149*_Complex_I, -0.967326508687 + 1.045774363086*_Complex_I, 5.315060279059 + -6.564076763307*_Complex_I, -14.103481813190 + 7.024414693592*_Complex_I, 7.672189491846 + -8.914876516755*_Complex_I, 5.234244256475 + 3.602992887989*_Complex_I, -0.039164279610 + -30.448360387467*_Complex_I, -16.064792699661 + 6.718770045507*_Complex_I, 4.235111030143 + 2.478115209729*_Complex_I, -9.198909959126 + -8.290580416319*_Complex_I, 10.578975231033 + 2.559822357827*_Complex_I, 9.243136171627 + -9.377891910936*_Complex_I, 5.862895817529 + 0.431692246149*_Complex_I, -11.618990491528 + 17.539850472094*_Complex_I, -1.161363450862 + -2.941910938932*_Complex_I, -1.268260133904 + 1.005441709892*_Complex_I, 31.421272506426 + -0.240397785028*_Complex_I, -10.921843261114 + 10.855028296636*_Complex_I, 6.680208942916 + 7.902869278527*_Complex_I, 9.744767683416 + -15.653561656933*_Complex_I, 11.963236965081 + 2.757863055376*_Complex_I, -0.657516528727 + -1.513346377612*_Complex_I, -5.778133404808 + 0.380938385839*_Complex_I, 3.001034357249 + -0.472690292826*_Complex_I, 4.361975174738 + -0.082813022517*_Complex_I, 7.393956533023 + 3.595190860536*_Complex_I, -16.383681435953 + -0.148093500883*_Complex_I, 15.448535613211 + 13.699034854832*_Complex_I, -26.046188537886 + 4.672758210947*_Complex_I, -25.431394530510 + 19.149176229623*_Complex_I, 0.452366402127 + -9.284164787222*_Complex_I, -8.853642184491 + 7.831408406510*_Complex_I, -6.688478485009 + -3.439251128678*_Complex_I, -6.810859551138 + -8.440912926245*_Complex_I, -19.102617555696 + 6.927486844509*_Complex_I, 8.934833377990 + -11.564936252737*_Complex_I, -7.393024014592 + -0.714887967192*_Complex_I, -0.719859551514 + -13.605720898747*_Complex_I, -17.742142235287 + -12.458797479604*_Complex_I, 15.978186136167 + 5.980922906846*_Complex_I, 10.780516210769 + -5.413148370626*_Complex_I, 18.156965553233 + -2.629625388886*_Complex_I, 16.391744903218 + 7.895225147305*_Complex_I, 6.290790245017 + 6.997124329976*_Complex_I, 3.689747766167 + 11.534985962311*_Complex_I, 9.391595767018 + 17.298374496500*_Complex_I, 25.027955260120 + -7.023151206389*_Complex_I, -5.241064162059 + -8.249917715987*_Complex_I, -0.085493630186 + -3.829269584478*_Complex_I, 3.782595963629 + -0.412071285666*_Complex_I}; liquid-dsp-1.7.0/src/fft/tests/data/fft_r2rdata_27.c000066400000000000000000000142051474751757600221160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft r2r (real-to-real) data // // 27-point real even/odd dft data float fftdata_r2r_x27[] = { 1.00000000e+00, 9.67720449e-01, 8.74232948e-01, 7.29134023e-01, 5.46968460e-01, 3.45309585e-01, 1.42522618e-01, -4.44371328e-02, -2.01871306e-01, -3.20590228e-01, -3.96443307e-01, -4.30132151e-01, -4.26421911e-01, -3.92946303e-01, -3.38838935e-01, -2.73413390e-01, -2.05070078e-01, -1.40540510e-01, -8.45066383e-02, -3.95672210e-02, -6.47628168e-03, 1.54448878e-02, 2.78246514e-02, 3.27720679e-02, 3.24839540e-02, 2.89606918e-02, 2.38370150e-02 }; // REDFT00 float fftdata_r2r_REDFT00_y27[] = { 1.90807498e+00, 6.92315578e+00, 1.18128624e+01, 5.63927364e+00, 6.24250948e-01, 6.22979142e-02, -2.71553919e-02, 1.96029730e-02, -1.47504276e-02, 1.15671754e-02, -9.38177109e-03, 7.82203674e-03, -6.67411089e-03, 5.80593944e-03, -5.13643026e-03, 4.61196899e-03, -4.19497490e-03, 3.86145711e-03, -3.59269325e-03, 3.37751862e-03, -3.20415385e-03, 3.06731090e-03, -2.96133757e-03, 2.88200378e-03, -2.82669067e-03, 2.79450417e-03, -2.78437138e-03 }; // REDFT10 float fftdata_r2r_REDFT10_y27[] = { 2.93191195e+00, 7.81435204e+00, 1.25262451e+01, 5.87700558e+00, 3.13943624e-01, -2.23003000e-01, -1.98579907e-01, -9.58713368e-02, -9.68946069e-02, -5.19125164e-02, -5.74545190e-02, -3.24527398e-02, -3.75072435e-02, -2.18437612e-02, -2.58425809e-02, -1.53105119e-02, -1.83160957e-02, -1.09222922e-02, -1.30745629e-02, -7.76020437e-03, -9.17540491e-03, -5.33153862e-03, -6.08742610e-03, -3.34636122e-03, -3.48186493e-03, -1.61480904e-03, -1.13347173e-03 }; // REDFT01 float fftdata_r2r_REDFT01_y27[] = { 3.24506021e+00, 1.02413387e+01, 1.02888603e+01, 2.94090056e+00, 3.01434755e-01, -3.94552648e-02, 4.12662849e-02, -3.65541428e-02, 3.23217735e-02, -2.86298655e-02, 2.54328623e-02, -2.26499923e-02, 2.02035718e-02, -1.80307329e-02, 1.60805881e-02, -1.43106822e-02, 1.26882717e-02, -1.11882668e-02, 9.78851132e-03, -8.47033411e-03, 7.21932389e-03, -6.02424145e-03, 4.87267971e-03, -3.75625165e-03, 2.66467361e-03, -1.59203156e-03, 5.29353623e-04 }; // REDFT11 float fftdata_r2r_REDFT11_y27[] = { 4.32605982e+00, 1.13771296e+01, 1.02061100e+01, 2.13518620e+00, -1.33218557e-01, -2.76073009e-01, -8.56223330e-02, -1.44742057e-01, -2.83730812e-02, -9.47302654e-02, -7.39809964e-03, -6.90608099e-02, 2.49255938e-03, -5.37654683e-02, 7.92805944e-03, -4.37831581e-02, 1.13052810e-02, -3.68458964e-02, 1.36666447e-02, -3.17945704e-02, 1.55290905e-02, -2.79758442e-02, 1.71851665e-02, -2.49931645e-02, 1.88217703e-02, -2.25886870e-02, 2.05794629e-02 }; // RODFT00 float fftdata_r2r_RODFT00_y27[] = { -3.07457280e+00, 4.34810066e+00, 1.09639254e+01, 7.64511538e+00, 4.62730789e+00, 3.26789522e+00, 2.68699503e+00, 2.17084169e+00, 1.91607285e+00, 1.60684299e+00, 1.45886230e+00, 1.24392998e+00, 1.14396501e+00, 9.81968999e-01, 9.06752288e-01, 7.78145194e-01, 7.16473997e-01, 6.10574782e-01, 5.56297779e-01, 4.66658950e-01, 4.16026711e-01, 3.38447809e-01, 2.88945198e-01, 2.20500469e-01, 1.70261383e-01, 1.08778238e-01, 5.62527180e-02 }; // RODFT10 float fftdata_r2r_RODFT10_y27[] = { -3.45587444e+00, 3.69455957e+00, 1.00895662e+01, 7.11557245e+00, 4.58258820e+00, 3.34214282e+00, 2.84152031e+00, 2.34757495e+00, 2.14987850e+00, 1.85646343e+00, 1.76226008e+00, 1.56126976e+00, 1.51575768e+00, 1.36674178e+00, 1.34836006e+00, 1.23211598e+00, 1.23075652e+00, 1.13685036e+00, 1.14728224e+00, 1.06952679e+00, 1.08892000e+00, 1.02343559e+00, 1.05029333e+00, 9.94573593e-01, 1.02823102e+00, 9.80662346e-01, 1.02105260e+00 }; // RODFT01 float fftdata_r2r_RODFT01_y27[] = { -2.61891890e+00, -4.18362617e-02, 9.58289337e+00, 9.41432190e+00, 5.27894020e+00, 3.62661290e+00, 2.76587272e+00, 2.31010056e+00, 1.92357457e+00, 1.67965138e+00, 1.44504440e+00, 1.28557563e+00, 1.12212110e+00, 1.00580621e+00, 8.81629765e-01, 7.90346980e-01, 6.89975739e-01, 6.14315927e-01, 5.29168069e-01, 4.63644713e-01, 3.88459831e-01, 3.29564214e-01, 2.60825515e-01, 2.06111193e-01, 1.41254663e-01, 8.88549462e-02, 2.58288011e-02 }; // RODFT11 float fftdata_r2r_RODFT11_y27[] = { -2.72205544e+00, -1.06129467e+00, 8.21426964e+00, 9.14769840e+00, 5.52553558e+00, 3.88690162e+00, 3.03581023e+00, 2.59010696e+00, 2.22776008e+00, 2.00389194e+00, 1.79835343e+00, 1.66311359e+00, 1.53181064e+00, 1.44247937e+00, 1.35311365e+00, 1.29120958e+00, 1.22834873e+00, 1.18450797e+00, 1.13985527e+00, 1.10885823e+00, 1.07762277e+00, 1.05639505e+00, 1.03571594e+00, 1.02242053e+00, 1.01060724e+00, 1.00419796e+00, 1.00035369e+00 }; liquid-dsp-1.7.0/src/fft/tests/data/fft_r2rdata_32.c000066400000000000000000000157211474751757600221160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft r2r (real-to-real) data // // 32-point real even/odd dft data float fftdata_r2r_x32[] = { 1.00000000e+00, 9.76961553e-01, 9.09556091e-01, 8.02746117e-01, 6.64265335e-01, 5.03880322e-01, 3.32481116e-01, 1.61105037e-01, -3.40424648e-08, -1.42174676e-01, -2.58936524e-01, -3.46311510e-01, -4.02897298e-01, -4.29679066e-01, -4.29643869e-01, -4.07258183e-01, -3.67879450e-01, -3.17172974e-01, -2.60592192e-01, -2.02966005e-01, -1.48217648e-01, -9.92199481e-02, -5.77765778e-02, -2.47062612e-02, 1.25687316e-09, 1.69803519e-02, 2.72917245e-02, 3.22119817e-02, 3.30718160e-02, 3.11258435e-02, 2.74662171e-02, 2.29759347e-02 }; // REDFT00 float fftdata_r2r_REDFT00_y32[] = { 2.27039862e+00, 8.13895798e+00, 1.40223389e+01, 6.84894085e+00, 7.96620846e-01, 7.64858574e-02, -3.17813009e-02, 2.30059568e-02, -1.72815435e-02, 1.35012688e-02, -1.08927619e-02, 9.02237184e-03, -7.63727259e-03, 6.58483105e-03, -5.76706184e-03, 5.12006786e-03, -4.60112654e-03, 4.17934125e-03, -3.83267412e-03, 3.54650151e-03, -3.30836512e-03, 3.10952030e-03, -2.94351298e-03, 2.80511752e-03, -2.69039162e-03, 2.59574503e-03, -2.51914933e-03, 2.45943666e-03, -2.41351128e-03, 2.37989426e-03, -2.36272812e-03, 2.35617161e-03 }; // REDFT10 float fftdata_r2r_REDFT10_y32[] = { 3.29337406e+00, 9.03484726e+00, 1.47411804e+01, 7.09897327e+00, 4.95285779e-01, -2.08808795e-01, -2.04274148e-01, -9.34088752e-02, -1.00554205e-01, -5.08193560e-02, -6.01783060e-02, -3.20817754e-02, -3.97967622e-02, -2.19255462e-02, -2.79445965e-02, -1.57238189e-02, -2.03754716e-02, -1.16170188e-02, -1.51962955e-02, -8.72472394e-03, -1.14511019e-02, -6.57916535e-03, -8.60831141e-03, -4.91373613e-03, -6.35385327e-03, -3.56272981e-03, -4.48495522e-03, -2.41775438e-03, -2.86681950e-03, -1.40333176e-03, -1.39808655e-03, -4.60088253e-04 }; // REDFT01 float fftdata_r2r_REDFT01_y32[] = { 3.84605742e+00, 1.21377001e+01, 1.21945066e+01, 3.48508573e+00, 3.57804537e-01, -4.74350490e-02, 4.97081988e-02, -4.42513935e-02, 3.93650271e-02, -3.51234674e-02, 3.14703509e-02, -2.83105075e-02, 2.55550444e-02, -2.31280141e-02, 2.09678225e-02, -1.90287828e-02, 1.72705650e-02, -1.56631656e-02, 1.41822286e-02, -1.28069818e-02, 1.15218461e-02, -1.03116995e-02, 9.16616712e-03, -8.07419885e-03, 7.02799764e-03, -6.01985678e-03, 5.04441932e-03, -4.09346819e-03, 3.16351652e-03, -2.24826857e-03, 1.34513900e-03, -4.47750092e-04 }; // REDFT11 float fftdata_r2r_REDFT11_y32[] = { 4.92722511e+00, 1.32802725e+01, 1.21282454e+01, 2.68794346e+00, -7.75258020e-02, -2.84586310e-01, -7.88819566e-02, -1.52703851e-01, -2.31686458e-02, -1.01293720e-01, -3.44139524e-03, -7.46235624e-02, 5.45739289e-03, -5.86049184e-02, 1.00630848e-02, -4.80872169e-02, 1.27020460e-02, -4.07497510e-02, 1.43614262e-02, -3.54013182e-02, 1.55183356e-02, -3.13723050e-02, 1.64255053e-02, -2.82586850e-02, 1.72268860e-02, -2.58033480e-02, 1.80160627e-02, -2.38352567e-02, 1.88578963e-02, -2.22345591e-02, 1.98070407e-02, -2.09140405e-02 }; // RODFT00 float fftdata_r2r_RODFT00_y32[] = { -3.80376291e+00, 4.75984573e+00, 1.26453495e+01, 8.96690750e+00, 5.51104832e+00, 3.91941833e+00, 3.23827934e+00, 2.63059449e+00, 2.33582568e+00, 1.97329426e+00, 1.80615771e+00, 1.55536008e+00, 1.44624805e+00, 1.25815463e+00, 1.17955160e+00, 1.03102541e+00, 9.69759405e-01, 8.48199964e-01, 7.97134459e-01, 6.94987476e-01, 6.49889886e-01, 5.62294245e-01, 5.20456970e-01, 4.44106996e-01, 4.03675139e-01, 3.36212277e-01, 2.95823514e-01, 2.35492110e-01, 1.94067836e-01, 1.39503479e-01, 9.61183906e-02, 4.62093353e-02 }; // RODFT10 float fftdata_r2r_RODFT10_y32[] = { -4.18236399e+00, 4.10336685e+00, 1.17561054e+01, 8.40457535e+00, 5.42492485e+00, 3.95339370e+00, 3.35005546e+00, 2.76342392e+00, 2.52070665e+00, 2.17183208e+00, 2.05204034e+00, 1.81259131e+00, 1.75025475e+00, 1.57222724e+00, 1.54146743e+00, 1.40205300e+00, 1.39061260e+00, 1.27737224e+00, 1.27877247e+00, 1.18427241e+00, 1.19484186e+00, 1.11434531e+00, 1.13192439e+00, 1.06226850e+00, 1.08557940e+00, 1.02458429e+00, 1.05290902e+00, 9.99043226e-01, 1.03204751e+00, 9.84234095e-01, 1.02187860e+00, 9.79380608e-01 }; // RODFT01 float fftdata_r2r_RODFT01_y32[] = { -3.14800310e+00, -4.45067883e-01, 1.08461933e+01, 1.10677624e+01, 6.34346628e+00, 4.38031149e+00, 3.35651875e+00, 2.81504726e+00, 2.36018848e+00, 2.07406235e+00, 1.80141354e+00, 1.61707830e+00, 1.43000770e+00, 1.29786718e+00, 1.15834939e+00, 1.05674410e+00, 9.46406841e-01, 8.64174008e-01, 7.72926450e-01, 7.03647554e-01, 6.25416100e-01, 5.65090656e-01, 4.95949268e-01, 4.41907734e-01, 3.79158407e-01, 3.29515547e-01, 2.71191031e-01, 2.24530101e-01, 1.69109464e-01, 1.24305725e-01, 7.05337524e-02, 2.66184807e-02 }; // RODFT11 float fftdata_r2r_RODFT11_y32[] = { -3.24692512e+00, -1.44892704e+00, 9.45565414e+00, 1.07434196e+01, 6.54239464e+00, 4.59986401e+00, 3.58518982e+00, 3.05150127e+00, 2.61707282e+00, 2.34726048e+00, 2.09873915e+00, 1.93409348e+00, 1.77332234e+00, 1.66290724e+00, 1.55142403e+00, 1.47315228e+00, 1.39249706e+00, 1.33510482e+00, 1.27525985e+00, 1.23238277e+00, 1.18744755e+00, 1.15523088e+00, 1.12153363e+00, 1.09753525e+00, 1.07270765e+00, 1.05533838e+00, 1.03783357e+00, 1.02606010e+00, 1.01488125e+00, 1.00805402e+00, 1.00260448e+00, 1.00036693e+00 }; liquid-dsp-1.7.0/src/fft/tests/data/fft_r2rdata_8.c000066400000000000000000000057661474751757600220510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft r2r (real-to-real) data // // 8-point real even/odd dft data float fftdata_r2r_x8[] = { 0.0000000000, 1.0000000000, 2.0000000000, 3.0000000000, 4.0000000000, 5.0000000000, 6.0000000000, 7.0000000000}; // REDFT00 float fftdata_r2r_REDFT00_y8[] = { 49.0000000000, -20.1956693581, -0.0000000000, -2.5724165284, -0.0000000000, -1.2319141135, -0.0000000000, -1.0000000000}; // REDFT10 float fftdata_r2r_REDFT10_y8[] = { 56.0000000000, -25.7692920908, 0.0000000000, -2.6938192036, 0.0000000000, -0.8036116149, 0.0000000000, -0.2028092910}; // REDFT01 float fftdata_r2r_REDFT01_y8[] = { 29.1819286410, -32.3061136840, 12.7168729872, -10.9904036256, 5.7286734878, -4.9189401648, 1.8807638636, -1.2927815051}; // REDFT11 float fftdata_r2r_REDFT11_y8[] = { 24.7243981823, -31.5148535947, 13.9257769120, -12.7826885392, 9.1714938314, -8.8071984223, 7.6789810021, -7.5857732734}; // RODFT00 float fftdata_r2r_RODFT00_y8[] = { 39.6989727373, -24.7272967751, 12.1243556530, -10.7257823333, 5.8736974182, -5.1961524227, 2.5477916399, -1.5869428264}; // RODFT10 float fftdata_r2r_RODFT10_y8[] = { 35.8808162684, -20.9050074380, 12.5996671239, -11.3137084990, 8.4188284171, -8.6591376023, 7.1371381075, -8.0000000000}; // RODFT01 float fftdata_r2r_RODFT01_y8[] = { 41.8902640723, -9.2302062214, 0.3792058953, -2.4608789465, 0.0160780480, -1.1773622132, 0.2426629216, -0.6033416816}; // RODFT11 float fftdata_r2r_RODFT11_y8[] = { 46.6916824794, -7.4005942194, 0.9237106918, -1.7485238108, -0.1159888643, -0.8699819349, -0.3640003929, -0.5519032668}; liquid-dsp-1.7.0/src/fft/tests/fft_composite_autotest.c000066400000000000000000000047211474751757600232720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_composite_autotest.c : test FFTs of 'composite' length (not // prime, not of form 2^m) // #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/fft/tests/fft_runtest.h" // // AUTOTESTS: n-point ffts // void autotest_fft_10() { fft_test( fft_test_x10, fft_test_y10, 10); } void autotest_fft_21() { fft_test( fft_test_x21, fft_test_y21, 21); } void autotest_fft_22() { fft_test( fft_test_x22, fft_test_y22, 22); } void autotest_fft_24() { fft_test( fft_test_x24, fft_test_y24, 24); } void autotest_fft_26() { fft_test( fft_test_x26, fft_test_y26, 26); } void autotest_fft_30() { fft_test( fft_test_x30, fft_test_y30, 30); } void autotest_fft_35() { fft_test( fft_test_x35, fft_test_y35, 35); } void autotest_fft_36() { fft_test( fft_test_x36, fft_test_y36, 36); } void autotest_fft_48() { fft_test( fft_test_x48, fft_test_y48, 48); } void autotest_fft_63() { fft_test( fft_test_x63, fft_test_y63, 63); } void autotest_fft_92() { fft_test( fft_test_x92, fft_test_y92, 92); } void autotest_fft_96() { fft_test( fft_test_x96, fft_test_y96, 96); } void autotest_fft_120() { fft_test( fft_test_x120, fft_test_y120, 120); } void autotest_fft_130() { fft_test( fft_test_x130, fft_test_y130, 130); } void autotest_fft_192() { fft_test( fft_test_x192, fft_test_y192, 192); } liquid-dsp-1.7.0/src/fft/tests/fft_prime_autotest.c000066400000000000000000000034001474751757600223750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_prime_autotest.c : test FFTs of prime length // #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/fft/tests/fft_runtest.h" // // AUTOTESTS: n-point ffts // void autotest_fft_17() { fft_test( fft_test_x17, fft_test_y17, 17); } void autotest_fft_43() { fft_test( fft_test_x43, fft_test_y43, 43); } void autotest_fft_79() { fft_test( fft_test_x79, fft_test_y79, 79); } void autotest_fft_157() { fft_test( fft_test_x157, fft_test_y157, 157); } void autotest_fft_317() { fft_test( fft_test_x317, fft_test_y317, 317); } void autotest_fft_509() { fft_test( fft_test_x509, fft_test_y509, 509); } liquid-dsp-1.7.0/src/fft/tests/fft_r2r_autotest.c000066400000000000000000000115571474751757600220020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // include data sets #include "fft_runtest.h" // autotest helper function void fft_r2r_test(float * _x, float * _test, unsigned int _n, unsigned int _kind) { int _flags = 0; float tol=1e-4f; unsigned int i; float y[_n]; // compute real even/odd FFT fftplan q = fft_create_plan_r2r_1d(_n, _x, y, _kind, _flags); fft_execute(q); // print results if (liquid_autotest_verbose) { printf("%12s %12s\n", "expected", "actual"); for (i=0; i<_n; i++) printf("%12.8f %12.8f\n", _test[i], y[i]); } // validate results for (i=0; i<_n; i++) CONTEND_DELTA( y[i], _test[i], tol); // destroy plans fft_destroy_plan(q); } // // AUTOTESTS: 8-point real-to-real ffts // void autotest_fft_r2r_REDFT00_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_REDFT00_y8, 8, LIQUID_FFT_REDFT00); } void autotest_fft_r2r_REDFT10_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_REDFT10_y8, 8, LIQUID_FFT_REDFT10); } void autotest_fft_r2r_REDFT01_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_REDFT01_y8, 8, LIQUID_FFT_REDFT01); } void autotest_fft_r2r_REDFT11_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_REDFT11_y8, 8, LIQUID_FFT_REDFT11); } void autotest_fft_r2r_RODFT00_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_RODFT00_y8, 8, LIQUID_FFT_RODFT00); } void autotest_fft_r2r_RODFT10_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_RODFT10_y8, 8, LIQUID_FFT_RODFT10); } void autotest_fft_r2r_RODFT01_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_RODFT01_y8, 8, LIQUID_FFT_RODFT01); } void autotest_fft_r2r_RODFT11_n8() { fft_r2r_test(fftdata_r2r_x8, fftdata_r2r_RODFT11_y8, 8, LIQUID_FFT_RODFT11); } // // AUTOTESTS: 32-point real-to-real ffts // void autotest_fft_r2r_REDFT00_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_REDFT00_y32, 32, LIQUID_FFT_REDFT00); } void autotest_fft_r2r_REDFT10_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_REDFT10_y32, 32, LIQUID_FFT_REDFT10); } void autotest_fft_r2r_REDFT01_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_REDFT01_y32, 32, LIQUID_FFT_REDFT01); } void autotest_fft_r2r_REDFT11_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_REDFT11_y32, 32, LIQUID_FFT_REDFT11); } void autotest_fft_r2r_RODFT00_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_RODFT00_y32, 32, LIQUID_FFT_RODFT00); } void autotest_fft_r2r_RODFT10_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_RODFT10_y32, 32, LIQUID_FFT_RODFT10); } void autotest_fft_r2r_RODFT01_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_RODFT01_y32, 32, LIQUID_FFT_RODFT01); } void autotest_fft_r2r_RODFT11_n32() { fft_r2r_test(fftdata_r2r_x32, fftdata_r2r_RODFT11_y32, 32, LIQUID_FFT_RODFT11); } // // AUTOTESTS: 27-point real-to-real ffts // void autotest_fft_r2r_REDFT00_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_REDFT00_y27, 27, LIQUID_FFT_REDFT00); } void autotest_fft_r2r_REDFT10_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_REDFT10_y27, 27, LIQUID_FFT_REDFT10); } void autotest_fft_r2r_REDFT01_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_REDFT01_y27, 27, LIQUID_FFT_REDFT01); } void autotest_fft_r2r_REDFT11_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_REDFT11_y27, 27, LIQUID_FFT_REDFT11); } void autotest_fft_r2r_RODFT00_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_RODFT00_y27, 27, LIQUID_FFT_RODFT00); } void autotest_fft_r2r_RODFT10_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_RODFT10_y27, 27, LIQUID_FFT_RODFT10); } void autotest_fft_r2r_RODFT01_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_RODFT01_y27, 27, LIQUID_FFT_RODFT01); } void autotest_fft_r2r_RODFT11_n27() { fft_r2r_test(fftdata_r2r_x27, fftdata_r2r_RODFT11_y27, 27, LIQUID_FFT_RODFT11); } liquid-dsp-1.7.0/src/fft/tests/fft_radix2_autotest.c000066400000000000000000000035001474751757600224530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_radix2_autotest.c : test power-of-two transforms // #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/fft/tests/fft_runtest.h" // // AUTOTESTS: power-of-two transforms // void autotest_fft_2() { fft_test( fft_test_x2, fft_test_y2, 2); } void autotest_fft_4() { fft_test( fft_test_x4, fft_test_y4, 4); } void autotest_fft_8() { fft_test( fft_test_x8, fft_test_y8, 8); } void autotest_fft_16() { fft_test( fft_test_x16, fft_test_y16, 16); } void autotest_fft_32() { fft_test( fft_test_x32, fft_test_y32, 32); } void autotest_fft_64() { fft_test( fft_test_x64, fft_test_y64, 64); } liquid-dsp-1.7.0/src/fft/tests/fft_runtest.c000066400000000000000000000041571474751757600210470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // autotest helper function // _x : fft input array // _test : expected fft output // _n : fft size void fft_test(float complex * _x, float complex * _test, unsigned int _n) { int _method = 0; float tol=2e-4f; unsigned int i; float complex y[_n], z[_n]; // compute FFT fftplan pf = fft_create_plan(_n, _x, y, LIQUID_FFT_FORWARD, _method); fft_execute(pf); // compute IFFT fftplan pr = fft_create_plan(_n, y, z, LIQUID_FFT_BACKWARD, _method); fft_execute(pr); // normalize inverse for (i=0; i<_n; i++) z[i] /= (float) _n; // validate results float fft_error, ifft_error; for (i=0; i<_n; i++) { fft_error = cabsf( y[i] - _test[i] ); ifft_error = cabsf( _x[i] - z[i] ); CONTEND_DELTA( fft_error, 0, tol); CONTEND_DELTA( ifft_error, 0, tol); } // destroy plans fft_destroy_plan(pf); fft_destroy_plan(pr); } liquid-dsp-1.7.0/src/fft/tests/fft_runtest.h000066400000000000000000000120401474751757600210420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest fft data definitions // #ifndef __LIQUID_FFT_DATA_H__ #define __LIQUID_FFT_DATA_H__ // autotest helper function // _x : fft input array // _test : expected fft output // _n : fft size void fft_test(float complex * _x, float complex * _test, unsigned int _n); // // autotest datasets // // extern float complex fft_test_x2[]; extern float complex fft_test_y2[]; extern float complex fft_test_x3[]; extern float complex fft_test_y3[]; extern float complex fft_test_x4[]; extern float complex fft_test_y4[]; extern float complex fft_test_x5[]; extern float complex fft_test_y5[]; extern float complex fft_test_x6[]; extern float complex fft_test_y6[]; extern float complex fft_test_x7[]; extern float complex fft_test_y7[]; extern float complex fft_test_x8[]; extern float complex fft_test_y8[]; extern float complex fft_test_x9[]; extern float complex fft_test_y9[]; // extern float complex fft_test_x10[]; extern float complex fft_test_y10[]; extern float complex fft_test_x16[]; extern float complex fft_test_y16[]; extern float complex fft_test_x17[]; extern float complex fft_test_y17[]; extern float complex fft_test_x20[]; extern float complex fft_test_y20[]; extern float complex fft_test_x21[]; extern float complex fft_test_y21[]; extern float complex fft_test_x22[]; extern float complex fft_test_y22[]; extern float complex fft_test_x24[]; extern float complex fft_test_y24[]; extern float complex fft_test_x26[]; extern float complex fft_test_y26[]; extern float complex fft_test_x30[]; extern float complex fft_test_y30[]; extern float complex fft_test_x32[]; extern float complex fft_test_y32[]; extern float complex fft_test_x35[]; extern float complex fft_test_y35[]; extern float complex fft_test_x36[]; extern float complex fft_test_y36[]; extern float complex fft_test_x43[]; extern float complex fft_test_y43[]; extern float complex fft_test_x48[]; extern float complex fft_test_y48[]; extern float complex fft_test_x63[]; extern float complex fft_test_y63[]; extern float complex fft_test_x64[]; extern float complex fft_test_y64[]; extern float complex fft_test_x79[]; extern float complex fft_test_y79[]; extern float complex fft_test_x92[]; extern float complex fft_test_y92[]; extern float complex fft_test_x96[]; extern float complex fft_test_y96[]; // extern float complex fft_test_x120[]; extern float complex fft_test_y120[]; extern float complex fft_test_x130[]; extern float complex fft_test_y130[]; extern float complex fft_test_x157[]; extern float complex fft_test_y157[]; extern float complex fft_test_x192[]; extern float complex fft_test_y192[]; extern float complex fft_test_x317[]; extern float complex fft_test_y317[]; extern float complex fft_test_x509[]; extern float complex fft_test_y509[]; // 8-point real even/odd dft data extern float fftdata_r2r_x8[]; extern float fftdata_r2r_REDFT00_y8[]; extern float fftdata_r2r_REDFT10_y8[]; extern float fftdata_r2r_REDFT01_y8[]; extern float fftdata_r2r_REDFT11_y8[]; extern float fftdata_r2r_RODFT00_y8[]; extern float fftdata_r2r_RODFT10_y8[]; extern float fftdata_r2r_RODFT01_y8[]; extern float fftdata_r2r_RODFT11_y8[]; // 27-point real even/odd dft data extern float fftdata_r2r_x27[]; extern float fftdata_r2r_REDFT00_y27[]; extern float fftdata_r2r_REDFT10_y27[]; extern float fftdata_r2r_REDFT01_y27[]; extern float fftdata_r2r_REDFT11_y27[]; extern float fftdata_r2r_RODFT00_y27[]; extern float fftdata_r2r_RODFT10_y27[]; extern float fftdata_r2r_RODFT01_y27[]; extern float fftdata_r2r_RODFT11_y27[]; // 32-point real even/odd dft data extern float fftdata_r2r_x32[]; extern float fftdata_r2r_REDFT00_y32[]; extern float fftdata_r2r_REDFT10_y32[]; extern float fftdata_r2r_REDFT01_y32[]; extern float fftdata_r2r_REDFT11_y32[]; extern float fftdata_r2r_RODFT00_y32[]; extern float fftdata_r2r_RODFT10_y32[]; extern float fftdata_r2r_RODFT01_y32[]; extern float fftdata_r2r_RODFT11_y32[]; #endif // __LIQUID_FFT_DATA_H__ liquid-dsp-1.7.0/src/fft/tests/fft_shift_autotest.c000066400000000000000000000041601474751757600224020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" void autotest_fft_shift_4() { float complex x[] = { 0 + 0*_Complex_I, 1 + 1*_Complex_I, 2 + 2*_Complex_I, 3 + 3*_Complex_I }; float complex test[] = { 2 + 2*_Complex_I, 3 + 3*_Complex_I, 0 + 0*_Complex_I, 1 + 1*_Complex_I }; fft_shift(x,4); CONTEND_SAME_DATA(x,test,4*sizeof(float complex)); } void autotest_fft_shift_8() { float complex x[] = { 0 + 0*_Complex_I, 1 + 1*_Complex_I, 2 + 2*_Complex_I, 3 + 3*_Complex_I, 4 + 4*_Complex_I, 5 + 5*_Complex_I, 6 + 6*_Complex_I, 7 + 7*_Complex_I }; float complex test[] = { 4 + 4*_Complex_I, 5 + 5*_Complex_I, 6 + 6*_Complex_I, 7 + 7*_Complex_I, 0 + 0*_Complex_I, 1 + 1*_Complex_I, 2 + 2*_Complex_I, 3 + 3*_Complex_I }; fft_shift(x,8); CONTEND_SAME_DATA(x,test,8*sizeof(float complex)); } liquid-dsp-1.7.0/src/fft/tests/fft_small_autotest.c000066400000000000000000000033301474751757600223730ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fft_small_autotest.c : test small transforms // #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/fft/tests/fft_runtest.h" // // AUTOTESTS: small FFTs // void autotest_fft_3() { fft_test( fft_test_x4, fft_test_y4, 4); } void autotest_fft_5() { fft_test( fft_test_x5, fft_test_y5, 5); } void autotest_fft_6() { fft_test( fft_test_x6, fft_test_y6, 6); } void autotest_fft_7() { fft_test( fft_test_x7, fft_test_y7, 7); } void autotest_fft_9() { fft_test( fft_test_x9, fft_test_y9, 9); } liquid-dsp-1.7.0/src/fft/tests/gen_fft_data.m000066400000000000000000000046371474751757600211220ustar00rootroot00000000000000% generate fft data for autotests function gen_fft_data(n); n = round(n); x = randn(1,n) + j*randn(1,n); y = fft(x); % print results filename = ['fft_data_' num2str(n) '.c']; fid = fopen(filename,'w'); fprintf(fid,'/* Copyright (c) 2007 - 2015 Joseph Gaeddert\n'); fprintf(fid,' *\n'); fprintf(fid,' * Permission is hereby granted, free of charge, to any person obtaining a copy\n'); fprintf(fid,' * of this software and associated documentation files (the "Software"), to deal\n'); fprintf(fid,' * in the Software without restriction, including without limitation the rights\n'); fprintf(fid,' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'); fprintf(fid,' * copies of the Software, and to permit persons to whom the Software is\n'); fprintf(fid,' * furnished to do so, subject to the following conditions:\n'); fprintf(fid,' * \n'); fprintf(fid,' * The above copyright notice and this permission notice shall be included in\n'); fprintf(fid,' * all copies or substantial portions of the Software.\n'); fprintf(fid,' *\n'); fprintf(fid,' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n'); fprintf(fid,' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n'); fprintf(fid,' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n'); fprintf(fid,' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n'); fprintf(fid,' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n'); fprintf(fid,' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n'); fprintf(fid,' * THE SOFTWARE.\n'); fprintf(fid,' */\n'); fprintf(fid,'\n'); fprintf(fid,'//\n'); fprintf(fid,'// autotest fft data for %u-point transform\n', n); fprintf(fid,'//\n'); fprintf(fid,'\n'); fprintf(fid,'#include \n'); fprintf(fid,'\n'); fprintf(fid,'float complex fft_test_x%d[] = {\n',n); for i=1:n, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(x(i)), imag(x(i))); if i==n, fprintf(fid,'};\n'); else, fprintf(fid,',\n'); end; end; fprintf(fid,'\n'); fprintf(fid,'float complex fft_test_y%d[] = {\n',n); for i=1:n, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(y(i)), imag(y(i))); if i==n, fprintf(fid,'};\n'); else, fprintf(fid,',\n'); end; end; fprintf(fid,'\n'); fclose(fid); printf('results written to %s\n', filename); liquid-dsp-1.7.0/src/fft/tests/gen_fft_files.m000066400000000000000000000003641474751757600213040ustar00rootroot00000000000000% generate fft data for autotests n = [2, 3, 4, 5, 6, 7, 8, 9,... 10, 16, 17, 20, 21, 22, 24, 26,... 30, 32, 35, 36, 43, 48, 63, 64, 79, 92, 96,... 120, 130, 157, 192, 317, 509] for i=1:length(n), gen_fft_data(n(i)); end; liquid-dsp-1.7.0/src/fft/tests/spgram_autotest.c000066400000000000000000000421111474751757600217150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // test spectral periodogram (spgram) objects #include #include "autotest/autotest.h" #include "liquid.internal.h" void testbench_spgramcf_noise(unsigned int _nfft, unsigned int _wlen, unsigned int _delay, int _wtype, float _noise_floor) { unsigned int num_samples = 2000*_nfft; // number of samples to generate float nstd = powf(10.0f,_noise_floor/20.0f); // noise std. dev. float tol = 0.5f; // error tolerance [dB] if (liquid_autotest_verbose) { printf(" spgramcf test (noise): nfft=%6u, wtype=%24s, noise floor=%6.1f\n", _nfft, liquid_window_str[_wtype][1], _noise_floor); } // create spectral periodogram spgramcf q = NULL; if (_wlen==0 || _delay==0 || _wtype==LIQUID_WINDOW_UNKNOWN) q = spgramcf_create_default(_nfft); else q = spgramcf_create(_nfft, _wtype, _wlen, _delay); unsigned int i; for (i=0; i nfft/2-10 && i < nfft/2+10 ? 8.0f : noise_floor + 3.0f; if (liquid_autotest_verbose) printf("%6u : %8.2f < %8.2f < %8.2f\n", i, mask_lo, psd[i], mask_hi); CONTEND_GREATER_THAN( psd[i], mask_lo ); CONTEND_LESS_THAN ( psd[i], mask_hi ); } // free memory free(buf); } // check spectral periodogram operation where the input size is much shorter // than the transform size void autotest_spgramcf_short() { unsigned int nfft = 1200; // transform size unsigned int num_samples = 200; // number of samples to generate float noise_floor = -20.0f; float nstd = powf(10.0f,noise_floor/20.0f); // noise std. dev. float complex * buf = (float complex*)malloc(num_samples*sizeof(float complex)); unsigned int i; for (i=0; i %8.2f\n", 0.0f, psd[nfft_2], mask_lo); CONTEND_GREATER_THAN( psd[nfft_2], mask_lo ); // free memory free(buf); } // check copy method void autotest_spgramcf_copy() { unsigned int nfft = 1200; // transform size unsigned int num_samples = 9600; // number of samples to generate float nstd = 0.1f; // noise standard deviation // create object with some odd properties spgramcf q0 = spgramcf_create(nfft, LIQUID_WINDOW_KAISER, 960, 373); // generate a bunch of random noise samples unsigned int i; for (i=0; i #include #include "autotest/autotest.h" #include "liquid.internal.h" void autotest_spwaterfall_invalid_config() { #ifdef LIQUID_STRICT_EXIT AUTOTEST_WARN("spwaterfall test not run with strict mode enabled"); return; #endif AUTOTEST_WARN("testing spwaterfall invalid configurations; ignore printed errors"); // default configurations unsigned int nfft = 1200; int wtype = LIQUID_WINDOW_HAMMING; unsigned int wlen = 800; unsigned int delay = 200; unsigned int time = 960; // test invalid configurations, normal construction CONTEND_ISNULL(spwaterfallcf_create( 1, wtype, wlen, delay, time)) CONTEND_ISNULL(spwaterfallcf_create(nfft, wtype, 0, delay, time)) CONTEND_ISNULL(spwaterfallcf_create(nfft, wtype, nfft+1, delay, time)) CONTEND_ISNULL(spwaterfallcf_create(nfft, LIQUID_WINDOW_KBD, 801, delay, time)) CONTEND_ISNULL(spwaterfallcf_create(nfft, wtype, wlen, 0, time)) CONTEND_ISNULL(spwaterfallcf_create(nfft, wtype, wlen, delay, 0)) // test invalid configurations, default construction CONTEND_ISNULL(spwaterfallcf_create_default( 0, time)) CONTEND_ISNULL(spwaterfallcf_create_default(nfft, 0)) // create proper object but test invalid internal configurations spwaterfallcf q = spwaterfallcf_create_default(540, 320); CONTEND_INEQUALITY(LIQUID_OK, spwaterfallcf_set_rate(q, -10e6)) spwaterfallcf_destroy(q); } int testbench_spwaterfallcf_compare(const void * _v0, const void * _v1) { return *(float*)_v0 > *(float*)_v1 ? 1 : -1; } void testbench_spwaterfallcf_noise(unsigned int _nfft, unsigned int _window_len, unsigned int _delay, unsigned int _time, float _noise_floor) { unsigned int num_samples = 4*_nfft*_time; // number of samples to generate float nstd = powf(10.0f,_noise_floor/20.0f); // noise std. dev. float tol = 4.0f; // error tolerance [dB] TODO: drop tolerance to 0.5 dB int _wtype = LIQUID_WINDOW_HAMMING; // create spectral periodogram spwaterfallcf q = spwaterfallcf_create(_nfft, _wtype, _window_len, _delay, _time); unsigned int i; for (i=0; i #include #include "liquid.h" // Helper function to keep code base small void fftfilt_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // adjust number of iterations: *_num_iterations = *_num_iterations * 5 / (_n*logf(_n)); if (*_num_iterations < 1) *_num_iterations = 1; // generate coefficients unsigned int h_len = _n+1; float h[h_len]; unsigned long int i; for (i=0; i #include "liquid.h" // Helper function to keep code base small void firdecim_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _M, unsigned int _h_len) { // normalize number of iterations *_num_iterations /= _h_len; if (*_num_iterations < 1) *_num_iterations = 1; float h[_h_len]; unsigned int i; for (i=0; i<_h_len; i++) h[i] = 1.0f; firdecim_crcf q = firdecim_crcf_create(_M,h,_h_len); // initialize input float complex x[_M]; for (i=0; i<_M; i++) x[i] = (i%2) ? 1.0f : -1.0f; float complex y; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { firdecim_crcf_execute(q, x, &y); firdecim_crcf_execute(q, x, &y); firdecim_crcf_execute(q, x, &y); firdecim_crcf_execute(q, x, &y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firdecim_crcf_destroy(q); } #define FIRDECIM_CRCF_BENCHMARK_API(M,H_LEN) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firdecim_crcf_bench(_start, _finish, _num_iterations, M, H_LEN); } void benchmark_firdecim_crcf_m2_h8 FIRDECIM_CRCF_BENCHMARK_API(2, 8) void benchmark_firdecim_crcf_m4_h16 FIRDECIM_CRCF_BENCHMARK_API(4, 16) void benchmark_firdecim_crcf_m8_h32 FIRDECIM_CRCF_BENCHMARK_API(8, 32) void benchmark_firdecim_crcf_m16_h64 FIRDECIM_CRCF_BENCHMARK_API(16,64) void benchmark_firdecim_cccf_m32_h128 FIRDECIM_CRCF_BENCHMARK_API(32,128) liquid-dsp-1.7.0/src/filter/bench/firfilt_crcf_benchmark.c000066400000000000000000000056231474751757600235740ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void firfilt_crcf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // adjust number of iterations: // cycles/trial ~ 107 + 4.3*_n *_num_iterations *= 1000; *_num_iterations /= (unsigned int)(107+4.3*_n); // generate coefficients float h[_n]; unsigned long int i; for (i=0; i<_n; i++) h[i] = randnf(); // create filter object firfilt_crcf f = firfilt_crcf_create(h,_n); // generate input vector float complex x[4]; for (i=0; i<4; i++) x[i] = randnf() + _Complex_I*randnf(); // output vector float complex y[4]; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { firfilt_crcf_push(f, x[0]); firfilt_crcf_execute(f, &y[0]); firfilt_crcf_push(f, x[1]); firfilt_crcf_execute(f, &y[1]); firfilt_crcf_push(f, x[2]); firfilt_crcf_execute(f, &y[2]); firfilt_crcf_push(f, x[3]); firfilt_crcf_execute(f, &y[3]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firfilt_crcf_destroy(f); } #define FIRFILT_CRCF_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firfilt_crcf_bench(_start, _finish, _num_iterations, N); } void benchmark_firfilt_crcf_4 FIRFILT_CRCF_BENCHMARK_API(4) void benchmark_firfilt_crcf_8 FIRFILT_CRCF_BENCHMARK_API(8) void benchmark_firfilt_crcf_16 FIRFILT_CRCF_BENCHMARK_API(16) void benchmark_firfilt_crcf_32 FIRFILT_CRCF_BENCHMARK_API(32) void benchmark_firfilt_crcf_64 FIRFILT_CRCF_BENCHMARK_API(64) liquid-dsp-1.7.0/src/filter/bench/firhilb_benchmark.c000066400000000000000000000047361474751757600225630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void firhilbf_decim_bench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _m) { // normalize number of trials *_num_iterations *= 20; *_num_iterations /= liquid_nextpow2(_m+1); // create hilber transform object firhilbf q = firhilbf_create(_m,60.0f); float x[] = {1.0f, -1.0f}; float complex y; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { firhilbf_decim_execute(q,x,&y); firhilbf_decim_execute(q,x,&y); firhilbf_decim_execute(q,x,&y); firhilbf_decim_execute(q,x,&y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firhilbf_destroy(q); } #define FIRHILB_DECIM_BENCHMARK_API(M) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firhilbf_decim_bench(_start, _finish, _num_iterations, M); } void benchmark_firhilbf_decim_m3 FIRHILB_DECIM_BENCHMARK_API(3) // m=3 void benchmark_firhilbf_decim_m5 FIRHILB_DECIM_BENCHMARK_API(5) // m=5 void benchmark_firhilbf_decim_m9 FIRHILB_DECIM_BENCHMARK_API(9) // m=9 void benchmark_firhilbf_decim_m13 FIRHILB_DECIM_BENCHMARK_API(13) // m=13 liquid-dsp-1.7.0/src/filter/bench/firinterp_crcf_benchmark.c000066400000000000000000000053651474751757600241420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void firinterp_crcf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _M, unsigned int _h_len) { // normalize number of iterations *_num_iterations *= 80; *_num_iterations /= _h_len; if (*_num_iterations < 1) *_num_iterations = 1; float h[_h_len]; unsigned int i; for (i=0; i<_h_len; i++) h[i] = 1.0f; firinterp_crcf q = firinterp_crcf_create(_M,h,_h_len); float complex y[_M]; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { firinterp_crcf_execute(q,1.0f,y); firinterp_crcf_execute(q,1.0f,y); firinterp_crcf_execute(q,1.0f,y); firinterp_crcf_execute(q,1.0f,y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firinterp_crcf_destroy(q); } #define FIRINTERP_CRCF_BENCHMARK_API(M,H_LEN) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firinterp_crcf_bench(_start, _finish, _num_iterations, M, H_LEN); } void benchmark_firinterp_crcf_m2_h8 FIRINTERP_CRCF_BENCHMARK_API(2, 8) void benchmark_firinterp_crcf_m4_h16 FIRINTERP_CRCF_BENCHMARK_API(4, 16) void benchmark_firinterp_crcf_m8_h32 FIRINTERP_CRCF_BENCHMARK_API(8, 32) void benchmark_firinterp_crcf_m16_h64 FIRINTERP_CRCF_BENCHMARK_API(16,64) void benchmark_firinterp_crcf_m32_h128 FIRINTERP_CRCF_BENCHMARK_API(32,128) liquid-dsp-1.7.0/src/filter/bench/iirdecim_crcf_benchmark.c000066400000000000000000000061421474751757600237170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void iirdecim_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _M, unsigned int _order) { // normalize number of iterations *_num_iterations /= _order; if (*_num_iterations < 1) *_num_iterations = 1; // create decimator from prototype liquid_iirdes_filtertype ftype = LIQUID_IIRDES_BUTTER; liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; liquid_iirdes_format format = LIQUID_IIRDES_SOS; float fc = 0.5f / (float)_M; float f0 = 0.0f; float Ap = 0.1f; float As = 60.0f; iirdecim_crcf q = iirdecim_crcf_create_prototype(_M,ftype,btype,format,_order,fc,f0,Ap,As); // initialize input float complex x[_M]; unsigned int i; for (i=0; i<_M; i++) x[i] = (i%2) ? 1.0f : -1.0f; float complex y; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { iirdecim_crcf_execute(q, x, &y); iirdecim_crcf_execute(q, x, &y); iirdecim_crcf_execute(q, x, &y); iirdecim_crcf_execute(q, x, &y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; iirdecim_crcf_destroy(q); } #define IIRDECIM_CRCF_BENCHMARK_API(M,ORDER) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { iirdecim_crcf_bench(_start, _finish, _num_iterations, M, ORDER); } void benchmark_iirdecim_crcf_M2 IIRDECIM_CRCF_BENCHMARK_API(2, 5) void benchmark_iirdecim_crcf_M4 IIRDECIM_CRCF_BENCHMARK_API(4, 5) void benchmark_iirdecim_crcf_M8 IIRDECIM_CRCF_BENCHMARK_API(8, 5) void benchmark_iirdecim_crcf_M16 IIRDECIM_CRCF_BENCHMARK_API(16,5) void benchmark_iirdecim_cccf_M32 IIRDECIM_CRCF_BENCHMARK_API(32,5) liquid-dsp-1.7.0/src/filter/bench/iirfilt_crcf_benchmark.c000066400000000000000000000121141474751757600235700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void iirfilt_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _order, unsigned int _format) { unsigned int i; // scale number of iterations (trials) if (_format == LIQUID_IIRDES_TF) { // cycles/trial ~ 128 + 15.3*_order; *_num_iterations *= 1000; *_num_iterations /= (unsigned int)(128 + 15.3*_order); } else { // cycles/trial ~ 93 + 53.3*_order *_num_iterations *= 800; *_num_iterations /= (unsigned int)(93 + 53.3*_order); } // create filter object from prototype float fc = 0.2f; // filter cut-off frequency float f0 = 0.0f; // filter center frequency (band-pass, band-stop) float Ap = 0.1f; // filter pass-band ripple float As = 60.0f; // filter stop-band attenuation iirfilt_crcf q = iirfilt_crcf_create_prototype(LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_LOWPASS, _format, _order, fc, f0, Ap, As); // initialize input/output float complex x[4]; float complex y[4]; for (i=0; i<4; i++) x[i] = randnf() + _Complex_I*randnf(); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { iirfilt_crcf_execute(q, x[0], &y[0]); iirfilt_crcf_execute(q, x[1], &y[1]); iirfilt_crcf_execute(q, x[2], &y[2]); iirfilt_crcf_execute(q, x[3], &y[3]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy filter object iirfilt_crcf_destroy(q); } #define IIRFILT_CRCF_BENCHMARK_API(N,T) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { iirfilt_crcf_bench(_start, _finish, _num_iterations, N, T); } // benchmark regular transfer function form void benchmark_iirfilt_crcf_4 IIRFILT_CRCF_BENCHMARK_API(4, LIQUID_IIRDES_TF) void benchmark_iirfilt_crcf_8 IIRFILT_CRCF_BENCHMARK_API(8, LIQUID_IIRDES_TF) void benchmark_iirfilt_crcf_16 IIRFILT_CRCF_BENCHMARK_API(16, LIQUID_IIRDES_TF) void benchmark_iirfilt_crcf_32 IIRFILT_CRCF_BENCHMARK_API(32, LIQUID_IIRDES_TF) void benchmark_iirfilt_crcf_64 IIRFILT_CRCF_BENCHMARK_API(64, LIQUID_IIRDES_TF) // benchmark second-order sections form void benchmark_iirfilt_crcf_sos_4 IIRFILT_CRCF_BENCHMARK_API(4, LIQUID_IIRDES_SOS) void benchmark_iirfilt_crcf_sos_8 IIRFILT_CRCF_BENCHMARK_API(8, LIQUID_IIRDES_SOS) void benchmark_iirfilt_crcf_sos_16 IIRFILT_CRCF_BENCHMARK_API(16, LIQUID_IIRDES_SOS) void benchmark_iirfilt_crcf_sos_32 IIRFILT_CRCF_BENCHMARK_API(32, LIQUID_IIRDES_SOS) void benchmark_iirfilt_crcf_sos_64 IIRFILT_CRCF_BENCHMARK_API(64, LIQUID_IIRDES_SOS) // benchmark DC-blocking filter void benchmark_irfilt_crcf_dcblock(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { unsigned long int i; // create filter object iirfilt_crcf q = iirfilt_crcf_create_dc_blocker(0.1f); // initialize input/output float complex x[4]; for (i=0; i<4; i++) x[i] = randnf() + _Complex_I*randnf(); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { iirfilt_crcf_execute(q, x[0], &x[0]); iirfilt_crcf_execute(q, x[1], &x[1]); iirfilt_crcf_execute(q, x[2], &x[2]); iirfilt_crcf_execute(q, x[3], &x[3]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy filter object iirfilt_crcf_destroy(q); } liquid-dsp-1.7.0/src/filter/bench/iirinterp_crcf_benchmark.c000066400000000000000000000060661474751757600241440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void iirinterp_crcf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _M, unsigned int _order) { // normalize number of iterations *_num_iterations *= 80; *_num_iterations /= _M*_order; if (*_num_iterations < 1) *_num_iterations = 1; // create interpolator from prototype liquid_iirdes_filtertype ftype = LIQUID_IIRDES_BUTTER; liquid_iirdes_bandtype btype = LIQUID_IIRDES_LOWPASS; liquid_iirdes_format format = LIQUID_IIRDES_SOS; float fc = 0.5f / (float)_M; // filter cut-off frequency float f0 = 0.0f; float Ap = 0.1f; float As = 60.0f; iirinterp_crcf q = iirinterp_crcf_create_prototype(_M,ftype,btype,format,_order,fc,f0,Ap,As); float complex y[_M]; // start trials getrusage(RUSAGE_SELF, _start); unsigned int i; for (i=0; i<(*_num_iterations); i++) { iirinterp_crcf_execute(q, 1.0f, y); iirinterp_crcf_execute(q, 1.0f, y); iirinterp_crcf_execute(q, 1.0f, y); iirinterp_crcf_execute(q, 1.0f, y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; iirinterp_crcf_destroy(q); } #define IIRINTERP_CRCF_BENCHMARK_API(M,ORDER) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { iirinterp_crcf_bench(_start, _finish, _num_iterations, M, ORDER); } void benchmark_iirinterp_crcf_M2 IIRINTERP_CRCF_BENCHMARK_API(2, 5) void benchmark_iirinterp_crcf_M4 IIRINTERP_CRCF_BENCHMARK_API(4, 5) void benchmark_iirinterp_crcf_M8 IIRINTERP_CRCF_BENCHMARK_API(8, 5) void benchmark_iirinterp_crcf_M16 IIRINTERP_CRCF_BENCHMARK_API(16,5) void benchmark_iirinterp_crcf_M32 IIRINTERP_CRCF_BENCHMARK_API(32,5) liquid-dsp-1.7.0/src/filter/bench/resamp2_crcf_benchmark.c000066400000000000000000000103211474751757600234750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2018 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" typedef enum { RESAMP2_DECIM, RESAMP2_INTERP } resamp2_type; // Helper function to keep code base small void resamp2_crcf_bench(struct rusage *_start, struct rusage *_finish, unsigned long int * _num_iterations, unsigned int _m, resamp2_type _type) { // scale number of iterations by filter length // NOTE: n = 4*m+1 // cycles/trial ~ 70.5 + 7.74*_m *_num_iterations *= 200; *_num_iterations /= 70.5 + 7.74*_m; unsigned long int i; resamp2_crcf q = resamp2_crcf_create(_m,0.0f,60.0f); float complex x[] = {1.0f, -1.0f}; float complex y[] = {1.0f, -1.0f}; // start trials getrusage(RUSAGE_SELF, _start); if (_type == RESAMP2_DECIM) { // run decimator for (i=0; i<(*_num_iterations); i++) { resamp2_crcf_decim_execute(q,x,y); resamp2_crcf_decim_execute(q,x,y); resamp2_crcf_decim_execute(q,x,y); resamp2_crcf_decim_execute(q,x,y); } } else { // run interpolator for (i=0; i<(*_num_iterations); i++) { resamp2_crcf_interp_execute(q,x[0],y); resamp2_crcf_interp_execute(q,x[0],y); resamp2_crcf_interp_execute(q,x[0],y); resamp2_crcf_interp_execute(q,x[0],y); } } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; resamp2_crcf_destroy(q); } #define RESAMP2_CRCF_BENCHMARK_API(M,T) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { resamp2_crcf_bench(_start, _finish, _num_iterations, M, T); } // // Decimators // void benchmark_resamp2_crcf_decim_m2 RESAMP2_CRCF_BENCHMARK_API( 2,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m4 RESAMP2_CRCF_BENCHMARK_API( 4,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m8 RESAMP2_CRCF_BENCHMARK_API( 8,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m16 RESAMP2_CRCF_BENCHMARK_API( 16,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m32 RESAMP2_CRCF_BENCHMARK_API( 32,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m64 RESAMP2_CRCF_BENCHMARK_API( 64,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m128 RESAMP2_CRCF_BENCHMARK_API(128,RESAMP2_DECIM) void benchmark_resamp2_crcf_decim_m256 RESAMP2_CRCF_BENCHMARK_API(256,RESAMP2_DECIM) // // Interpolators // void benchmark_resamp2_crcf_interp_m2 RESAMP2_CRCF_BENCHMARK_API( 2,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m4 RESAMP2_CRCF_BENCHMARK_API( 4,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m8 RESAMP2_CRCF_BENCHMARK_API( 8,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m16 RESAMP2_CRCF_BENCHMARK_API( 16,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m32 RESAMP2_CRCF_BENCHMARK_API( 32,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m64 RESAMP2_CRCF_BENCHMARK_API( 64,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m128 RESAMP2_CRCF_BENCHMARK_API(128,RESAMP2_INTERP) void benchmark_resamp2_crcf_interp_m256 RESAMP2_CRCF_BENCHMARK_API(256,RESAMP2_INTERP) liquid-dsp-1.7.0/src/filter/bench/resamp_crcf_benchmark.c000066400000000000000000000071351474751757600234240ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2018 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" // Helper function to keep code base small void resamp_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _P, unsigned int _Q) { // adjust number of iterations: cycles/trial ~ 500 + 100 Q *_num_iterations /= (500 + 100*_Q); // create resampling object; irrational rate is just less than Q/P float rate = (float)_Q/(float)_P*sqrt(3301.0f/3302.0f); unsigned int m = 12; // filter semi-length float bw = 0.45f; // filter bandwidth float As = 60.0f; // stop-band attenuation [dB] unsigned int npfb = 64; // number of polyphase filters resamp_crcf q = resamp_crcf_create(rate,m,bw,As,npfb); // buffering float complex buf_0[_P]; float complex buf_1[_Q*4]; unsigned int num_written; unsigned long int i; for (i=0; i<_P; i++) buf_0[i] = i % 7 ? 1 : -1; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); resamp_crcf_execute_block(q, buf_0, _P, buf_1, &num_written); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy object resamp_crcf_destroy(q); } #define RESAMP_CRCF_BENCHMARK_API(P,Q) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { resamp_crcf_bench(_start, _finish, _num_iterations, P, Q); } // // Resampler benchmark prototypes; compare to rational rate resampler // void benchmark_resamp_crcf_P17_Q1 RESAMP_CRCF_BENCHMARK_API(17, 1) void benchmark_resamp_crcf_P17_Q2 RESAMP_CRCF_BENCHMARK_API(17, 2) void benchmark_resamp_crcf_P17_Q4 RESAMP_CRCF_BENCHMARK_API(17, 4) void benchmark_resamp_crcf_P17_Q8 RESAMP_CRCF_BENCHMARK_API(17, 8) void benchmark_resamp_crcf_P17_Q16 RESAMP_CRCF_BENCHMARK_API(17, 16) void benchmark_resamp_crcf_P17_Q32 RESAMP_CRCF_BENCHMARK_API(17, 32) void benchmark_resamp_crcf_P17_Q64 RESAMP_CRCF_BENCHMARK_API(17, 64) void benchmark_resamp_crcf_P17_Q128 RESAMP_CRCF_BENCHMARK_API(17, 128) void benchmark_resamp_crcf_P17_Q256 RESAMP_CRCF_BENCHMARK_API(17, 256) liquid-dsp-1.7.0/src/filter/bench/rresamp_crcf_benchmark.c000066400000000000000000000066221474751757600236060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" // Helper function to keep code base small void rresamp_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _P, unsigned int _Q) { // adjust number of iterations *_num_iterations = *_num_iterations * liquid_nextpow2(_Q+1) / (4*_Q); // create resampling object unsigned int m = 12; float bw = 0.45f; float As = 60.0f; rresamp_crcf q = rresamp_crcf_create_kaiser(_P,_Q,m,bw,As); // input/output buffers unsigned int buf_len = _P > _Q ? _P : _Q; // max(_P,_Q) float complex * buf = (float complex*) malloc(buf_len*sizeof(float complex)); // initialize buffer unsigned long int i; for (i=0; i #include "liquid.h" // Helper function to keep code base small void symsync_crcf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _k, unsigned int _m) { unsigned long int i; unsigned int npfb = 16; // number of filters in bank unsigned int k = _k; // samples/symbol unsigned int m = _m; // filter delay [symbols] float beta = 0.3f; // filter excess bandwidth factor // create symbol synchronizer symsync_crcf q = symsync_crcf_create_rnyquist(LIQUID_FIRFILT_RRC, k, m, beta, npfb); // unsigned int num_samples = 64; *_num_iterations /= num_samples; unsigned int num_written; float complex x[num_samples]; float complex y[num_samples]; // generate pseudo-random data msequence ms = msequence_create_default(6); for (i=0; i #include #include #include // defined: // AUTOCORR() name-mangling macro // TI type (input) // TC type (coefficients) // TO type (output) // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro struct AUTOCORR(_s) { unsigned int window_size; unsigned int delay; WINDOW() w; // input buffer WINDOW() wdelay; // input buffer with delay float * we2; // energy buffer float e2_sum; // running sum of energy unsigned int ie2; // read index }; // create auto-correlator object // _window_size : size of the correlator window // _delay : correlator delay [samples] AUTOCORR() AUTOCORR(_create)(unsigned int _window_size, unsigned int _delay) { // create main object AUTOCORR() q = (AUTOCORR()) malloc(sizeof(struct AUTOCORR(_s))); // set user-based parameters q->window_size = _window_size; q->delay = _delay; // create window objects q->w = WINDOW(_create)(q->window_size); q->wdelay = WINDOW(_create)(q->window_size + q->delay); // allocate array for squared energy buffer q->we2 = (float*) malloc( (q->window_size)*sizeof(float) ); // clear object AUTOCORR(_reset)(q); // return main object return q; } // destroy auto-correlator object, freeing internal memory int AUTOCORR(_destroy)(AUTOCORR() _q) { // destroy internal window objects WINDOW(_destroy)(_q->w); WINDOW(_destroy)(_q->wdelay); // free array for squared energy buffer free(_q->we2); // free main object memory free(_q); return LIQUID_OK; } // reset auto-correlator object's internals int AUTOCORR(_reset)(AUTOCORR() _q) { // clear/reset internal window buffers WINDOW(_reset)(_q->w); WINDOW(_reset)(_q->wdelay); // reset internal squared energy buffer _q->e2_sum = 0.0; unsigned int i; for (i=0; i<_q->window_size; i++) _q->we2[i] = 0.0; _q->ie2 = 0; // reset read index to zero return LIQUID_OK; } // print auto-correlator parameters to stdout int AUTOCORR(_print)(AUTOCORR() _q) { printf("\n", _q->window_size, _q->delay); return LIQUID_OK; } // push sample into auto-correlator object int AUTOCORR(_push)(AUTOCORR() _q, TI _x) { // push input sample into buffers WINDOW(_push)(_q->w, _x); // non-delayed buffer WINDOW(_push)(_q->wdelay, conj(_x)); // delayed buffer // push |_x|^2 into buffer at appropriate location float e2 = creal( _x*conj(_x) ); _q->e2_sum -= _q->we2[ _q->ie2 ]; _q->e2_sum += e2; _q->we2[ _q->ie2 ] = e2; _q->ie2 = (_q->ie2+1) % _q->window_size; return LIQUID_OK; } // Write block of samples into auto-correlator object // _q : auto-correlation object // _x : input array [size: _n x 1] // _n : number of input samples int AUTOCORR(_write)(AUTOCORR() _q, TI * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) AUTOCORR(_push)(_q, _x[i]); return LIQUID_OK; } // compute auto-correlation output int AUTOCORR(_execute)(AUTOCORR() _q, TO *_rxx) { // provide pointers for reading buffer TI * rw; // input buffer read pointer TC * rwdelay; // input buffer read pointer (with delay) // read buffers; set internal pointers appropriately WINDOW(_read)(_q->w, &rw ); WINDOW(_read)(_q->wdelay, &rwdelay); // execute vector dot product on arrays, saving result to // user-supplied output pointer return DOTPROD(_run4)(rw, rwdelay, _q->window_size, _rxx); } // compute auto-correlation on block of samples; the input // and output arrays may have the same pointer // _q : auto-correlation object // _x : input array [size: _n x 1] // _n : number of input, output samples // _rxx : input array [size: _n x 1] int AUTOCORR(_execute_block)(AUTOCORR() _q, TI * _x, unsigned int _n, TO * _rxx) { unsigned int i; for (i=0; i<_n; i++) { // push input sample into auto-correlator AUTOCORR(_push)(_q, _x[i]); // compute output AUTOCORR(_execute)(_q, &_rxx[i]); } return LIQUID_OK; } // return sum of squares of buffered samples float AUTOCORR(_get_energy)(AUTOCORR() _q) { // value is already computed; simply return value return _q->e2_sum; } liquid-dsp-1.7.0/src/filter/src/bessel.c000066400000000000000000000215411474751757600201100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Bessel filter design // // References: // [Bianchi:2007] G. Bianchi and R. Sorrentino, "Electronic Filter Simulation // and Design." New York: McGraw-Hill, 2007. // [Orchard:1965] H. J. Orchard, "The Roots of the Maximally Flat-Delay // Polynomials." IEEE Transactions on Circuit Theory, September, 1965. // #include #include #include #include #include "liquid.internal.h" #define LIQUID_DEBUG_BESSEL_PRINT 0 // forward declarations int fpoly_bessel(unsigned int _n, float * _p); int fpoly_bessel_roots(unsigned int _n, float complex * _roots); int fpoly_bessel_roots_orchard(unsigned int _n, float complex * _roots); int fpoly_bessel_roots_orchard_recursion(unsigned int _n, float _x, float _y, float * _x_hat, float * _y_hat); // **************************************** // Compute analog zeros, poles, gain of low-pass Bessel // filter, grouping complex conjugates together. If // the filter order is odd, the single real pole is at // the end of the array. There are no zeros for the // analog Bessel filter. The gain is unity. // _n : filter order // _z : output analog zeros [length: 0] // _p : output analog poles [length: _n] // _k : output analog gain int bessel_azpkf(unsigned int _n, float complex * _za, float complex * _pa, float complex * _ka) { // roots are computed with order _n+1 so we must use a longer array to // prevent out-of-bounds write on the provided _pa array float complex _tmp_pa[_n+1]; // compute poles (roots to Bessel polynomial) if (fpoly_bessel_roots(_n+1,_tmp_pa) != LIQUID_OK) return liquid_error(LIQUID_EICONFIG,"bessel_azpkf(), invalid configuration"); for (int i = 0; i < _n; i++) _pa[i] = _tmp_pa[i]; // analog Bessel filter prototype has no zeros // The analog Bessel filter's 3-dB cut-off frequency is a // non-linear function of its order. This frequency can // be approximated from [Bianchi:2007] (1.67), pp. 33. // Re-normalize poles by (approximated) 3-dB frequency. float w3dB = sqrtf((2*_n-1)*logf(2.0f)); unsigned int i; for (i=0; i<_n; i++) _pa[i] /= w3dB; // set gain *_ka = 1.0f; for (i=0; i<_n; i++) *_ka *= _pa[i]; return LIQUID_OK; } int fpoly_bessel(unsigned int _n, float * _p) { unsigned int k; unsigned int N = _n-1; for (k=0; k<_n; k++) { #if 0 // use internal log(gamma(z)) float t0 = liquid_lngammaf((float)(2*N-k)+1); float t1 = liquid_lngammaf((float)(N-k) +1); float t2 = liquid_lngammaf((float)(k) +1); #else // use standard math log(gamma(z)) float t0 = lgammaf((float)(2*N-k)+1); float t1 = lgammaf((float)(N-k) +1); float t2 = lgammaf((float)(k) +1); #endif // M_LN2 = log(2) = 0.693147180559945 float t3 = M_LN2 * (float)(N-k); // log(2^(N-k)) = log(2)*log(N-k) _p[k] = roundf(expf(t0 - t1 - t2 - t3)); #if 0 printf(" p[%3u,%3u] = %12.4e\n", k, _n, _p[k]); printf(" t0 : %12.4e\n", t0); printf(" t1 : %12.4e\n", t1); printf(" t2 : %12.4e\n", t2); printf(" t3 : %12.4e\n", t3); #endif } return LIQUID_OK; } int fpoly_bessel_roots(unsigned int _n, float complex * _roots) { return fpoly_bessel_roots_orchard(_n, _roots); } // Estimate the roots of the _n^th-order Bessel polynomial using // Orchard's recursion. The initial estimates for the roots of // L_{k} are extrapolated from those in L_{k-2} and L_{k-1}. // The resulting root is near enough the true root such that // Orchard's recursion will find it. int fpoly_bessel_roots_orchard(unsigned int _n, float complex * _roots) { // initialize arrays float complex r0[_n]; // roots of L_{k-2} float complex r1[_n]; // roots of L_{k-1} float complex r_hat[_n]; // roots of L_{k} unsigned int i, j; unsigned int p, L; for (i=1; i<_n; i++) { p = i % 2; // order is odd? L = (i+p)/2; //printf("\n***** order %3u, p=%3u, L=%3u\n", i, p, L); if (i == 1) { r1[0] = -1; r_hat[0] = -1; } else if (i == 2) { r1[0] = -1; r_hat[0] = -1.5f + _Complex_I*0.5f*sqrtf(3.0f); } else { // use previous 2 sets of roots to estimate this set if (p) { // odd order : one real root on negative imaginary axis r_hat[0] = 2*crealf(r1[0]) - crealf(r0[0]); } else { // even order r_hat[0] = 2*r1[0] - conjf(r0[0]); } // linear extrapolation of roots of L_{k-2} and L_{k-1} for // new root estimate in L_{k} for (j=1; j roots(L_{k+2)) // roots(L_{k}) -> roots(L_{k+1)) memmove(r0, r1, (L-p)*sizeof(float complex)); memmove(r1, r_hat, L*sizeof(float complex)); } // copy results to output p = _n % 2; L = (_n-p)/2; for (i=0; i #include #include #include #include "liquid.internal.h" #define LIQUID_DEBUG_BUTTER_PRINT 0 // Compute analog zeros, poles, gain of low-pass Butterworth // filter, grouping complex conjugates together. If filter // order is odd, the single real pole (-1) is at the end of // the array. There are no zeros for the analog Butterworth // filter. The gain is unity. // _n : filter order // _za : output analog zeros [length: 0] // _pa : output analog poles [length: _n] // _ka : output analog gain int butter_azpkf(unsigned int _n, liquid_float_complex * _za, liquid_float_complex * _pa, liquid_float_complex * _ka) { unsigned int r = _n%2; unsigned int L = (_n - r)/2; unsigned int i; unsigned int k=0; for (i=0; i #include #include #include #include #include "liquid.internal.h" #define LIQUID_DEBUG_CHEBY1_PRINT 0 // Compute analog zeros, poles, gain of low-pass Chebyshev // Type I filter, grouping complex conjugates together. If // the filter order is odd, the single real pole is at the // end of the array. There are no zeros for the analog // Chebyshev Type I filter. // _n : filter order // _ep : epsilon, related to pass-band ripple // _za : output analog zeros [length: 0] // _pa : output analog poles [length: _n] // _ka : output analog gain int cheby1_azpkf(unsigned int _n, float _ep, liquid_float_complex * _za, liquid_float_complex * _pa, liquid_float_complex * _ka) { // temporary values float t0 = sqrt(1.0 + 1.0/(_ep*_ep)); float tp = powf( t0 + 1.0/_ep, 1.0/(float)(_n) ); float tm = powf( t0 - 1.0/_ep, 1.0/(float)(_n) ); float b = 0.5*(tp + tm); // ellipse major axis float a = 0.5*(tp - tm); // ellipse minor axis #if LIQUID_DEBUG_CHEBY1_PRINT printf(" ep : %12.8f\n", _ep); printf(" b : %12.8f\n", b); printf(" a : %12.8f\n", a); #endif // filter order variables unsigned int r = _n%2; // odd order? unsigned int L = (_n - r)/2; // half order // compute poles unsigned int i; unsigned int k=0; for (i=0; i #include #include #include #include #include "liquid.internal.h" #define LIQUID_DEBUG_CHEBY2_PRINT 0 // Compute analog zeros, poles, gain of low-pass Chebyshev // Type II filter, grouping complex conjugates together. If // the filter order is odd, the single real pole is at the // end of the array. // _n : filter order // _ep : epsilon, related to stop-band ripple // _za : output analog zeros [length: 2*floor(_n/2)] // _pa : output analog poles [length: _n] // _ka : output analog gain int cheby2_azpkf(unsigned int _n, float _es, liquid_float_complex * _za, liquid_float_complex * _pa, liquid_float_complex * _ka) { // temporary values float t0 = sqrt(1.0 + 1.0/(_es*_es)); float tp = powf( t0 + 1.0/_es, 1.0/(float)(_n) ); float tm = powf( t0 - 1.0/_es, 1.0/(float)(_n) ); float b = 0.5*(tp + tm); // ellipse major axis float a = 0.5*(tp - tm); // ellipse minor axis #if LIQUID_DEBUG_CHEBY2_PRINT printf("ep : %12.8f\n", _es); printf("b : %12.8f\n", b); printf("a : %12.8f\n", a); #endif // filter order variables unsigned int r = _n % 2; // odd order? unsigned int L = (_n - r)/2; // half order // compute poles unsigned int i; unsigned int k=0; for (i=0; i #include #include #include #include "liquid.internal.h" struct DDS(_s) { // user-defined parameters unsigned int num_stages; // number of halfband stages float fc0; // high-rate center frequency (-0.5,0.5) float bw0; // low-rate bandwidth (range?) float as0; // filter stop-band attenuation [dB] // derived values unsigned int rate; // re-sampling rate (2^num_stages) // halfband decimation/interpolation stages RESAMP2() * halfband_resamp; // array of half-band resamplers float * fc; // filter center frequency float * ft; // filter transition bandwidth float * as; // filter stop-band attenuation [dB] array unsigned int * m; // filter semi-length // internal buffers unsigned int buffer_len; T * buffer0; T * buffer1; // low-rate mixing stage NCO() ncox; // down-converter scaling factor float zeta; TC scale; }; // create dds object // _num_stages : number of halfband stages // _fc : input carrier // _bw : input signal bandwidth // _as : stop-band attenuation DDS() DDS(_create)(unsigned int _num_stages, float _fc, float _bw, float _as) { // error checking if (_num_stages > 20) return liquid_error_config("dds_%s_create(), number of stages %u exceeds reasonable maximum (20)", EXTENSION_FULL, _num_stages); if (_fc > 0.5f || _fc < -0.5f) return liquid_error_config("dds_%s_create(), frequency %12.4e is out of range [-0.5,0.5]", EXTENSION_FULL, _fc); if (_bw <= 0.0f || _bw >= 1.0f) return liquid_error_config("dds_%s_create(), bandwidth %12.4e is out of range (0,1)", EXTENSION_FULL, _bw); if (_as < 0.0f) return liquid_error_config("dds_%s_create(), stop-band suppression %12.4e must be greater than zero", EXTENSION_FULL, _as); // create object DDS() q = (DDS()) malloc(sizeof(struct DDS(_s))); q->num_stages = _num_stages; q->rate = 1<<(q->num_stages); q->fc0 = _fc; q->bw0 = _bw; q->as0 = _as; // allocate memory for filter properties q->fc = (float*) malloc((q->num_stages)*sizeof(float)); q->ft = (float*) malloc((q->num_stages)*sizeof(float)); q->as = (float*) malloc((q->num_stages)*sizeof(float)); q->m = (unsigned int*) malloc((q->num_stages)*sizeof(unsigned int)); unsigned int i; float fc, bw; fc = 0.5*(1<num_stages)*q->fc0; // filter center frequency bw = q->bw0; // signal bandwidth // TODO : compute/set filter bandwidths, lengths appropriately for (i=0; inum_stages; i++) { q->fc[i] = fc; while (q->fc[i] > 0.5f) q->fc[i] -= 1.0f; while (q->fc[i] < -0.5f) q->fc[i] += 1.0f; // compute transition bandwidth q->ft[i] = 0.5f*(1.0f - bw); if (q->ft[i] > 0.45) q->ft[i] = 0.45f; // set maximum bandwidth q->as[i] = q->as0; // compute (estimate) required filter length //q->m[i] = i==0 ? 37 : q->h_m[i-1]*0.7; q->m[i] = estimate_req_filter_len(q->ft[i], q->as[i]); // update carrier, bandwidth parameters fc *= 0.5f; bw *= 0.5f; } // allocate memory for buffering q->buffer_len = q->rate; q->buffer0 = (T*) malloc((q->buffer_len)*sizeof(T)); q->buffer1 = (T*) malloc((q->buffer_len)*sizeof(T)); // allocate memory for resampler pointers and create objects q->halfband_resamp = (RESAMP2()*) malloc((q->num_stages)*sizeof(RESAMP()*)); for (i=0; inum_stages; i++) { q->halfband_resamp[i] = RESAMP2(_create)(q->m[i], q->fc[i], q->as[i]); } // set down-converter scaling factor q->zeta = 1.0f / ((float)(q->rate)); q->scale = 1.0f; // create NCO and set frequency q->ncox = NCO(_create)(LIQUID_VCO); // TODO : ensure range is in [-pi,pi] NCO(_set_frequency)(q->ncox, 2*M_PI*(q->rate)*(q->fc0)); return q; } // copy object DDS() DDS(_copy)(DDS() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dds_%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy internal memory DDS() q_copy = (DDS()) malloc(sizeof(struct DDS(_s))); memmove(q_copy, q_orig, sizeof(struct DDS(_s))); // copy array of half-band resamplers q_copy->halfband_resamp = (RESAMP2()*) malloc((q_copy->num_stages)*sizeof(RESAMP()*)); unsigned int i; for (i=0; inum_stages; i++) q_copy->halfband_resamp[i] = RESAMP2(_copy)(q_orig->halfband_resamp[i]); // copy arrays of parameters q_copy->fc = (float * ) liquid_malloc_copy(q_orig->fc, q_copy->num_stages, sizeof(float )); q_copy->ft = (float * ) liquid_malloc_copy(q_orig->ft, q_copy->num_stages, sizeof(float )); q_copy->as = (float * ) liquid_malloc_copy(q_orig->as, q_copy->num_stages, sizeof(float )); q_copy->m = (unsigned int*) liquid_malloc_copy(q_orig->m, q_copy->num_stages, sizeof(unsigned int)); // copy buffers q_copy->buffer0 = (T*) liquid_malloc_copy(q_orig->buffer0, q_orig->buffer_len, sizeof(T)); q_copy->buffer1 = (T*) liquid_malloc_copy(q_orig->buffer1, q_orig->buffer_len, sizeof(T)); // copy mixer q_copy->ncox = NCO(_copy)(q_orig->ncox); // return new object return q_copy; } // destroy dds object, freeing all internally-allocated memory int DDS(_destroy)(DDS() _q) { // free filter parameter arrays free(_q->m); free(_q->as); free(_q->fc); free(_q->ft); // destroy buffers free(_q->buffer0); free(_q->buffer1); // destroy halfband resampler objects unsigned int i; for (i=0; i<_q->num_stages; i++) RESAMP2(_destroy)(_q->halfband_resamp[i]); free(_q->halfband_resamp); // destroy NCO object NCO(_destroy)(_q->ncox); // destroy DDS object free(_q); return LIQUID_OK; } // print dds object internals int DDS(_print)(DDS() _q) { printf("rate, _q->fc0, _q->bw0, nco_crcf_get_frequency(_q->ncox) / (2.0f*M_PI), _q->as0, _q->num_stages); unsigned int i; for (i=0; i<_q->num_stages; i++) printf("{fc=%.5f, ft=%.5f, m=%u},",_q->fc[i],_q->ft[i],_q->m[i]); printf("]>\n"); return LIQUID_OK; } // reset dds object internals, reset filters and nco phase int DDS(_reset)(DDS() _q) { // reset internal filter state variables unsigned int i; for (i=0; i<_q->num_stages; i++) { RESAMP2(_reset)(_q->halfband_resamp[i]); } NCO(_set_phase)(_q->ncox,0.0f); return LIQUID_OK; } // Set output scaling for filter // _q : synthesizer object // _scale : scaling factor to apply to each output sample int DDS(_set_scale)(DDS() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // Get output scaling for filter // _q : synthesizer object // _scale : scaling factor to apply to each output sample int DDS(_get_scale)(DDS() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // Get number of half-band states in DDS object unsigned int DDS(_get_num_stages)(DDS() _q) { return _q->num_stages; } // Get delay (samples) when running as interpolator unsigned int DDS(_get_delay_interp)(DDS() _q) { unsigned int i, delay=0; for (i=0; i<_q->num_stages; i++) { delay *= 2; delay += 2*_q->m[i]; } return delay; } // Get delay (samples) when running as decimator float DDS(_get_delay_decim)(DDS() _q) { float delay = 0.0f; unsigned int i; for (i=0; i<_q->num_stages; i++) { delay *= 0.5f; delay += _q->m[_q->num_stages-i-1] - 0.5f; } return delay; } // execute decimator // _q : dds object // _x : input sample array [size: 2^num_stages x 1] // _y : output sample int DDS(_decim_execute)(DDS() _q, T * _x, T * _y) { // copy input data memmove(_q->buffer0, _x, (_q->rate)*sizeof(T)); unsigned int k=_q->rate;// number of inputs for this stage unsigned int s; // stage counter unsigned int i; // input counter unsigned int g; // halfband resampler stage index (reversed) T * b0 = NULL; // input buffer pointer T * b1 = _q->buffer0; // output buffer pointer // iterate through each stage for (s=0; s<_q->num_stages; s++) { // length halves with each iteration k >>= 1; // set buffer pointers b0 = s%2 == 0 ? _q->buffer0 : _q->buffer1; b1 = s%2 == 1 ? _q->buffer0 : _q->buffer1; // execute halfband decimator g = _q->num_stages - s - 1; for (i=0; ihalfband_resamp[g], &b0[2*i], &b1[i]); } // output value T y = b1[0]; // increment NCO NCO(_mix_down)(_q->ncox, y, &y); NCO(_step)(_q->ncox); // set output, normalizing by scaling factor *_y = y * _q->zeta * _q->scale; return LIQUID_OK; } // execute interpolator // _q : dds object // _x : input sample // _y : output sample array [size: 2^num_stages x 1] int DDS(_interp_execute)(DDS() _q, T _x, T * _y) { // increment NCO _x *= _q->scale; NCO(_mix_up)(_q->ncox, _x, &_x); NCO(_step)(_q->ncox); unsigned int s; // stage counter unsigned int i; // input counter unsigned int k=1; // number of inputs for this stage T * b0 = NULL; // input buffer pointer T * b1 = _q->buffer0; // output buffer pointer // set initial buffer value _q->buffer0[0] = _x; // iterate through each stage for (s=0; s<_q->num_stages; s++) { // set buffer pointers b0 = s%2 == 0 ? _q->buffer0 : _q->buffer1; b1 = s%2 == 1 ? _q->buffer0 : _q->buffer1; // execute halfband interpolator for (i=0; ihalfband_resamp[s], b0[i], &b1[2*i]); // length doubles with each iteration k <<= 1; } // copy output data memmove(_y, b1, (_q->rate)*sizeof(T)); return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/ellip.c000066400000000000000000000265161474751757600177470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Elliptic filter design // // [Orfanidis:2006] Sophocles J. Orfanidis, "Lecture Notes on // Elliptic Filter Design." 2006 // [Orfanidis:2005] Sophocles J. Orfanidis, source code available // on www.ece.rutgers.edu/~orfanidi/hpeq #include #include #include #include "liquid.internal.h" #define LIQUID_DEBUG_ELLIP_PRINT 0 // landenf() // // Compute the Landen transformation of _k over _n iterations, // k[n] = (k[n-1] / (1+k'[n-1]))^2 // where // k'[n-1] = sqrt(1-k[n-1]^2) // // _k : elliptic modulus // _n : number of iterations // _v : sequence of decreasing moduli [size: _n] int landenf(float _k, unsigned int _n, float * _v) { unsigned int i; float k = _k; // k[n] float kp; // k'[n] for (i=0; i<_n; i++) { kp = sqrtf(1 - k*k); k = (1 - kp)/(1 + kp); _v[i] = k; } return LIQUID_OK; } // ellipkf() // // compute elliptic integral K(k) for _n recursions // // _k : elliptic modulus // _n : number of iterations // _K : complete elliptic integral (modulus k) // _Kp : complete elliptic integral (modulus k') int ellipkf(float _k, unsigned int _n, float * _K, float * _Kp) { // define range for k due to machine precision float kmin = 4e-4f; float kmax = sqrtf(1-kmin*kmin); float K; float Kp; float kp = sqrtf(1-_k*_k); //printf("ellipkf: k = %16.8e, kp = %16.8e\n", _k, kp); // Floating point resolution limits the range of the // computation of K on input _k [Orfanidis:2005] if (_k > kmax) { // input exceeds maximum extreme for this precision; use // approximation float L = -logf(0.25f*kp); K = L + 0.25f*(L-1)*kp*kp; } else { float v[_n]; landenf(_k,_n,v); K = M_PI * 0.5f; unsigned int i; for (i=0; i<_n; i++) K *= (1 + v[i]); } if (_k < kmin) { // input exceeds minimum extreme for this precision; use // approximation float L = -logf(_k*0.25f); Kp = L + 0.25f*(L-1)*_k*_k; } else { float vp[_n]; landenf(kp,_n,vp); Kp = M_PI * 0.5f; unsigned int i; for (i=0; i<_n; i++) Kp *= (1 + vp[i]); } // set return values *_K = K; *_Kp = Kp; return LIQUID_OK; } // ellipdegf() // // Compute elliptic degree using _n iterations // // _N : analog filter order // _k1 : elliptic modulus for stop-band, ep/ep1 // _n : number of Landen iterations float ellipdegf(float _N, float _k1, unsigned int _n) { // compute K1, K1p from _k1 float K1, K1p; ellipkf(_k1,_n,&K1,&K1p); // compute q1 from K1, K1p float q1 = expf(-M_PI*K1p/K1); // compute q from q1 float q = powf(q1,1.0f/_N); // expand numerator, denominator unsigned int m; float b = 0.0f; for (m=0; m<_n; m++) b += powf(q,(float)(m*(m+1))); float a = 0.0f; for (m=1; m<_n; m++) a += powf(q,(float)(m*m)); float g = b / (1.0f + 2.0f*a); float k = 4.0f*sqrtf(q)*g*g; #if LIQUID_DEBUG_ELLIP_PRINT printf("ellipdegf(N=%f, k1=%f, n=%u):\n", _N, _k1, _n); printf(" K1 : %12.4e;\n", K1); printf(" K1p : %12.4e;\n", K1p); printf(" q1 : %12.4e;\n", q1); printf(" q : %12.4e;\n", q); #endif return k; } // ellip_cdf() // // complex elliptic cd() function (Jacobian elliptic cosine) // // _u : vector in the complex u-plane // _k : elliptic modulus (0 <= _k < 1) // _n : number of Landen iterations (typically 5-6) float complex ellip_cdf(float complex _u, float _k, unsigned int _n) { float complex wn = ccosf(_u*M_PI*0.5f); float v[_n]; landenf(_k,_n,v); unsigned int i; for (i=_n; i>0; i--) { wn = (1 + v[i-1])*wn / (1 + v[i-1]*wn*wn); } return wn; } // ellip_snf() // // complex elliptic sn() function (Jacobian elliptic sine) // // _u : vector in the complex u-plane // _k : elliptic modulus (0 <= _k < 1) // _n : number of Landen iterations (typically 5-6) float complex ellip_snf(float complex _u, float _k, unsigned int _n) { float complex wn = csinf(_u*M_PI*0.5f); float v[_n]; landenf(_k,_n,v); unsigned int i; for (i=_n; i>0; i--) { wn = (1 + v[i-1])*wn / (1 + v[i-1]*wn*wn); } return wn; } // ellip_acdf() // // complex elliptic inverse cd() function (Jacobian elliptic // arc cosine) // // _w : vector in the complex u-plane // _k : elliptic modulus (0 <= _k < 1) // _n : number of Landen iterations (typically 5-6) float complex ellip_acdf(float complex _w, float _k, unsigned int _n) { float v[_n]; landenf(_k,_n,v); float v1; float complex w = _w; unsigned int i; for (i=0; i<_n; i++) { v1 = (i==0) ? _k : v[i-1]; w = w / (1 + liquid_csqrtf(1 - w*w*v1*v1)) * 2.0 / (1+v[i]); //printf(" w[%3u] = %12.8f + j*%12.8f\n", i, crealf(w), cimagf(w)); } float complex u = liquid_cacosf(w) * 2.0 / M_PI; //printf(" u = %12.8f + j*%12.8f\n", crealf(u), cimagf(u)); #if 0 float K, Kp; ellipkf(_k, _n, &K, &Kp); float R = Kp / K; #endif return u; } // ellip_asnf() // // complex elliptic inverse sn() function (Jacobian elliptic // arc sine) // // _w : vector in the complex u-plane // _k : elliptic modulus (0 <= _k < 1) // _n : number of Landen iterations (typically 5-6) float complex ellip_asnf(float complex _w, float _k, unsigned int _n) { return 1.0 - ellip_acdf(_w,_k,_n); } // ellip_azpkf() // // Compute analog zeros, poles, gain of low-pass elliptic // filter, grouping complex conjugates together. If // the filter order is odd, the single real pole is at the // end of the array. // _n : filter order // _ep : epsilon_p, related to pass-band ripple // _es : epsilon_s, related to stop-band ripple // _za : output analog zeros [length: floor(_n/2)] // _pa : output analog poles [length: _n] // _ka : output analog gain int ellip_azpkf(unsigned int _n, float _ep, float _es, float complex * _za, float complex * _pa, float complex * _ka) { // filter specifications float fp = 1.0f / (2.0f * M_PI); // pass-band cutoff float fs = 1.1*fp; // stop-band cutoff //float Gp = 1/sqrtf(1 + _ep*_ep); // pass-band gain //float Gs = 1/sqrtf(1 + _es*_es); // stop-band gain // number of iterations for elliptic integral // approximations unsigned int n=7; float Wp = 2*M_PI*fp; float Ws = 2*M_PI*fs; // ripples passband, stopband float ep = _ep; float es = _es; #if LIQUID_DEBUG_ELLIP_PRINT printf("ep, es : %12.8f, %12.8f\n", _ep, _es); #endif float k = Wp/Ws; // 0.8889f; float k1 = ep/es; // 0.0165f; #if LIQUID_DEBUG_ELLIP_PRINT printf("k : %12.4e\n", k); printf("k1 : %12.4e\n", k1); #endif float K, Kp; float K1, K1p; ellipkf(k, n, &K, &Kp); // K = 2.23533416, Kp = 1.66463780 ellipkf(k1,n, &K1, &K1p); // K1 = 1.57090271, K1p = 5.49361753 #if LIQUID_DEBUG_ELLIP_PRINT printf("K, Kp : %12.8f, %12.8f\n", K, Kp); printf("K1, K1p : %12.8f, %12.8f\n", K1, K1p); #endif float N = (float)_n; // ceilf(Nexact) = 5 #if LIQUID_DEBUG_ELLIP_PRINT float Nexact = (K1p/K1)/(Kp/K); // 4.69604063 printf("N (exact) : %12.8f\n", Nexact); printf("N : %12.8f\n", N); #endif k = ellipdegf(N,k1,n); // 0.91427171 #if LIQUID_DEBUG_ELLIP_PRINT printf("k : %12.4e\n", k); #endif #if LIQUID_DEBUG_ELLIP_PRINT float fs_new = fp/k; // 4.37506723 printf("fs_new : %12.8f\n", fs_new); #endif unsigned int L = (unsigned int)(floorf(N/2.0f)); // 2 unsigned int r = ((unsigned int)N) % 2; float u[L]; unsigned int i; for (i=0; i #include #include #include struct FDELAY(_s) { unsigned int nmax; // maximum delay allowed unsigned int m; // filter semi-length unsigned int npfb; // number of filters in polyphase filter-bank float delay; // current delay WINDOW() w; // window for bulk delay FIRPFB() pfb; // polyphase filter-bank for fractional delay unsigned int w_index; // index: window (bulk delay) unsigned int f_index; // index: polyphase filter-bank (fractional delay) }; // Create a delay object with a maximum offset and filter specification // _nmax : maximum integer sample offset // _m : polyphase filter-bank semi-length, _m > 0 // _npfb : number of filters in polyphase filter-bank, _npfb > 0 FDELAY() FDELAY(_create)(unsigned int _nmax, unsigned int _m, unsigned int _npfb) { // validate input if (_nmax == 0) return liquid_error_config("fdelay_%s_create(), max delay must be greater than 0", EXTENSION_FULL); if (_m == 0) return liquid_error_config("fdelay_%s_create(), filter semi-length must be greater than 0", EXTENSION_FULL); if (_npfb == 0) return liquid_error_config("fdelay_%s_create(), number of filters must be greater than 0", EXTENSION_FULL); // create filter object and initialize FDELAY() q = (FDELAY()) malloc(sizeof(struct FDELAY(_s))); q->nmax = _nmax; q->m = _m; q->npfb = _npfb; // create window (internal buffer); provision 1 extra sample to account // for additional delay q->w = WINDOW(_create)(q->nmax + 1); // create polyphase filter-bank q->pfb = FIRPFB(_create_default)(q->npfb, q->m); // reset filter state (clear buffer) FDELAY(_reset)(q); return q; } // Create a delay object with a maximum offset and default filter // parameters (_m = 8, _npfb = 64) // _nmax : maximum integer sample offset FDELAY() FDELAY(_create_default)(unsigned int _nmax) { return FDELAY(_create)(_nmax, 8, 64); } // Destroy delay object and free all internal memory int FDELAY(_destroy)(FDELAY() _q) { WINDOW(_destroy)(_q->w); FIRPFB(_destroy)(_q->pfb); free(_q); return LIQUID_OK; } // Reset delay object internals int FDELAY(_reset)(FDELAY() _q) { _q->delay = 0.0f; _q->w_index = _q->nmax-1; _q->f_index = 0; WINDOW(_reset)(_q->w); FIRPFB(_reset)(_q->pfb); return LIQUID_OK; } // Print delay object internals int FDELAY(_print)(FDELAY() _q) { printf("\n", _q->nmax, _q->m, _q->npfb, _q->delay); return LIQUID_OK; } // Get current delay (accounting for _m?) float FDELAY(_get_delay)(FDELAY() _q) { return _q->delay; } int FDELAY(_set_delay)(FDELAY() _q, float _delay) { if (_delay < 0) { return liquid_error(LIQUID_EIVAL,"fdelay_%s_set_delay(), delay (%g) cannot be negative", EXTENSION_FULL, _delay); } else if (_delay > _q->nmax) { return liquid_error(LIQUID_EIVAL,"fdelay_%s_set_delay(), delay (%g) cannot exceed maximum (%u)", EXTENSION_FULL, _delay, _q->nmax); } // compute offset from delay and integer/fractional components float offset = (float)(_q->nmax) - _delay; int intpart = (int) floorf(offset); float fracpart = offset - (float)intpart; // set indices appropriately _q->w_index = intpart; _q->f_index = (unsigned int)roundf(_q->npfb * fracpart); while (_q->f_index >= _q->npfb) { _q->w_index++; _q->f_index -= _q->npfb; } // ensure valid range; clip if needed. Note that w_index can be equal // to nmax because the window was provisioned for nmax+1 if (_q->w_index > _q->nmax) return liquid_error(LIQUID_EINT,"fdelay_%s_set_delay(), window index exceeds maximum", EXTENSION_FULL); #if 0 // debug printf("delay:%f -> offset:%f -> %d + %f -> %d + (%u/%u)\n", _delay, offset, intpart, fracpart, _q->w_index, _q->f_index, _q->npfb); #endif _q->delay = _delay; return LIQUID_OK; } int FDELAY(_adjust_delay)(FDELAY() _q, float _delta) { return FDELAY(_set_delay)(_q, _q->delay + _delta); } unsigned int FDELAY(_get_nmax)(FDELAY() _q) { return _q->nmax; } unsigned int FDELAY(_get_m)(FDELAY() _q) { return _q->m; } unsigned int FDELAY(_get_npfb)(FDELAY() _q) { return _q->npfb; } // Push sample into filter object's internal buffer // _q : filter object // _x : single input sample int FDELAY(_push)(FDELAY() _q, TI _x) { // apply bulk delay WINDOW(_push)(_q->w, _x); TO v; WINDOW(_index)(_q->w, _q->w_index, &v); // apply fractional delay FIRPFB(_push)(_q->pfb, v); return LIQUID_OK; } // Write block of samplex into filter object's internal buffer // _q : filter object // _x : buffer of input samples, [size: _n x 1] // _n : number of input samples int FDELAY(_write)(FDELAY() _q, TI * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { if ( FDELAY(_push)(_q, _x[i]) != LIQUID_OK) { return liquid_error(LIQUID_EINT,"fdelay_%s_write(), could not write sample", EXTENSION_FULL); } } return LIQUID_OK; } // Execute vector dot product on the filter's internal buffer and // coefficients // _q : filter object // _y : pointer to single output sample int FDELAY(_execute)(FDELAY() _q, TO * _y) { FIRPFB(_execute)(_q->pfb, _q->f_index, _y); return LIQUID_OK; } // Execute the filter on a block of input samples; in-place operation // is permitted (_x and _y may point to the same place in memory) // _q : filter object // _x : pointer to input array, [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array, [size: _n x 1] int FDELAY(_execute_block)(FDELAY() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { FDELAY(_push)(_q, _x[i]); FDELAY(_execute)(_q, _y+i); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/fftfilt.proto.c000066400000000000000000000214621474751757600214350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // finite impulse response (FIR) filter using fast Fourier transforms (FFTs) #include #include #include // fftfilt object structure struct FFTFILT(_s) { TC * h; // filter coefficients array [size; h_len x 1] unsigned int h_len; // filter length unsigned int n; // input/output block size // internal memory arrays // TODO: make TI/TO type, but ensuring complex // TODO: use special format for fftfilt_rrrf type float complex * time_buf; // time buffer [size: 2*n x 1] float complex * freq_buf; // freq buffer [size: 2*n x 1] float complex * H; // FFT of filter coefficients [size: 2*n x 1] float complex * w; // overlap array [size: n x 1] // FFT objects FFT_PLAN fft; // FFT object (forward) FFT_PLAN ifft; // FFT object (inverse) TC scale; // output scaling factor }; // create FFT-based FIR filter using external coefficients // _h : filter coefficients [size: _h_len x 1] // _h_len : filter length, _h_len > 0 // _n : block size = nfft/2, at least _h_len-1 FFTFILT() FFTFILT(_create)(TC * _h, unsigned int _h_len, unsigned int _n) { // validate input if (_h_len == 0) return liquid_error_config("fftfilt_%s_create(), filter length must be greater than zero",EXTENSION_FULL); if (_n < _h_len-1) return liquid_error_config("fftfilt_%s_create(), block length must be greater than _h_len-1 (%u)",EXTENSION_FULL,_h_len-1); // create filter object and initialize FFTFILT() q = (FFTFILT()) malloc(sizeof(struct FFTFILT(_s))); q->h_len = _h_len; q->n = _n; // copy filter coefficients q->h = (TC *) malloc((q->h_len)*sizeof(TC)); memmove(q->h, _h, _h_len*sizeof(TC)); // allocate internal memory arrays q->time_buf = (float complex *) FFT_MALLOC((2*q->n)* sizeof(float complex)); // time buffer q->freq_buf = (float complex *) FFT_MALLOC((2*q->n)* sizeof(float complex)); // frequency buffer q->H = (float complex *) malloc((2*q->n)* sizeof(float complex)); // FFT{ h } q->w = (float complex *) malloc(( q->n)* sizeof(float complex)); // delay buffer // create internal FFT objects q->fft = FFT_CREATE_PLAN(2*q->n, q->time_buf, q->freq_buf, FFT_DIR_FORWARD, FFT_METHOD); q->ifft = FFT_CREATE_PLAN(2*q->n, q->freq_buf, q->time_buf, FFT_DIR_BACKWARD, FFT_METHOD); // compute FFT of filter coefficients and copy to internal H array unsigned int i; for (i=0; i<2*q->n; i++) q->time_buf[i] = (i < q->h_len) ? q->h[i] : 0; // time_buf > {FFT} > freq_buf FFT_EXECUTE(q->fft); memmove(q->H, q->freq_buf, 2*q->n*sizeof(float complex)); // set default scaling FFTFILT(_set_scale)(q, 1); // reset filter state (clear buffer) FFTFILT(_reset)(q); // return object return q; } // copy object FFTFILT() FFTFILT(_copy)(FFTFILT() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters FFTFILT() q_copy = (FFTFILT()) malloc(sizeof(struct FFTFILT(_s))); memmove(q_copy, q_orig, sizeof(struct FFTFILT(_s))); // copy filter coefficients q_copy->h = (TC *) liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(TC)); // allocate FFT buffers q_copy->time_buf = (float complex*) FFT_MALLOC((2*q_orig->n) * sizeof(float complex)); q_copy->freq_buf = (float complex*) FFT_MALLOC((2*q_orig->n) * sizeof(float complex)); // copy buffers memmove(q_copy->time_buf, q_orig->time_buf, (2*q_orig->n) * sizeof(float complex)); memmove(q_copy->freq_buf, q_orig->freq_buf, (2*q_orig->n) * sizeof(float complex)); q_copy->H = (float complex*) liquid_malloc_copy(q_orig->H, 2*q_orig->n, sizeof(float complex)); q_copy->w = (float complex*) liquid_malloc_copy(q_orig->w, q_orig->n, sizeof(float complex)); // create internal FFT objects and return q_copy->fft = FFT_CREATE_PLAN(2*q_copy->n, q_copy->time_buf, q_copy->freq_buf, FFT_DIR_FORWARD, FFT_METHOD); q_copy->ifft = FFT_CREATE_PLAN(2*q_copy->n, q_copy->freq_buf, q_copy->time_buf, FFT_DIR_BACKWARD, FFT_METHOD); return q_copy; } // destroy object, freeing all internally-allocated memory int FFTFILT(_destroy)(FFTFILT() _q) { // free internal arrays free(_q->h); // filter coefficients FFT_FREE(_q->time_buf); // buffer (time domain) FFT_FREE(_q->freq_buf); // buffer (frequency domain) free(_q->H); // frequency response of filter coefficients free(_q->w); // output window buffer // destroy FFT objects FFT_DESTROY_PLAN(_q->fft); // forward transform FFT_DESTROY_PLAN(_q->ifft); // reverse transform // free main object free(_q); return LIQUID_OK; } // reset internal state of filter object int FFTFILT(_reset)(FFTFILT() _q) { // reset overlap window unsigned int i; for (i=0; i<_q->n; i++) { _q->w[i] = 0; } return LIQUID_OK; } // print filter object internals (taps, buffer) int FFTFILT(_print)(FFTFILT() _q) { printf("h_len, _q->n); printf(", scale="); PRINTVAL_TC(_q->scale,%g); printf(">\n"); return LIQUID_OK; } // set output scaling for filter int FFTFILT(_set_scale)(FFTFILT() _q, TC _scale) { // set scale, normalized by fft size _q->scale = _scale / (float)(2*_q->n); return LIQUID_OK; } // get output scaling for filter int FFTFILT(_get_scale)(FFTFILT() _q, TC * _scale) { // get scale, normalized by fft size *_scale = _q->scale * (float)(2*_q->n); return LIQUID_OK; } // execute the filter on internal buffer and coefficients // _q : filter object // _x : pointer to input data array [size: _n x 1] // _y : pointer to output data array [size: _n x 1] int FFTFILT(_execute)(FFTFILT() _q, TI * _x, TO * _y) { unsigned int i; // copy input #if 0 //TI_COMPLEX memmove(_q->time_buf, _x, _q->n*sizeof(TI)); #else // manual copy for type conversion // TODO: use DCT or equivalent for (i=0; i<_q->n; i++) _q->time_buf[i] = _x[i]; #endif // pad end of time-domain buffer with zeros // TODO: not necessary to do this every time #if 0 memset(&_q->time_buf[_q->n], 0, _q->n*sizeof(TI)); #else for (i=0; i<_q->n; i++) _q->time_buf[_q->n + i] = 0; #endif // run forward transform FFT_EXECUTE(_q->fft); // compute inner product between FFT{ _x } and FFT{ H } #if 1 for (i=0; i<2*_q->n; i++) _q->freq_buf[i] *= _q->H[i]; #else // use SIMD vector extensions # if TI_COMPLEX // complex floating-point inner product liquid_vectorcf_mul(_q->freq_buf, _q->H, 2*_q->n, _q->freq_buf); # else // real floating-point inner product liquid_vectorf_mul(_q->freq_buf, _q->H, 2*_q->n, _q->freq_buf); # endif #endif // compute inverse transform FFT_EXECUTE(_q->ifft); // copy output summed with buffer and scaled #if TI_COMPLEX for (i=0; i<_q->n; i++) _y[i] = (_q->time_buf[i] + _q->w[i]) * _q->scale; #else // manual copy for type conversion // TODO: use DCT or equivalent for (i=0; i<_q->n; i++) _y[i] = (T) crealf(_q->time_buf[i] + _q->w[i]) * _q->scale; #endif // copy buffer memmove(_q->w, &_q->time_buf[_q->n], _q->n*sizeof(float complex)); return LIQUID_OK; } // return length of filter object's internal coefficients unsigned int FFTFILT(_get_length)(FFTFILT() _q) { return _q->h_len; } liquid-dsp-1.7.0/src/filter/src/filter_cccf.c000066400000000000000000000071661474751757600211050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Filter API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "cccf" // #define AUTOCORR(name) LIQUID_CONCAT(autocorr_cccf,name) #define DDS(name) LIQUID_CONCAT(dds_cccf,name) #define FFTFILT(name) LIQUID_CONCAT(fftfilt_cccf,name) #define FIRDECIM(name) LIQUID_CONCAT(firdecim_cccf,name) #define FIRFILT(name) LIQUID_CONCAT(firfilt_cccf,name) #define FIRINTERP(name) LIQUID_CONCAT(firinterp_cccf,name) #define FIRPFB(name) LIQUID_CONCAT(firpfb_cccf,name) #define IIRDECIM(name) LIQUID_CONCAT(iirdecim_cccf,name) #define IIRFILT(name) LIQUID_CONCAT(iirfilt_cccf,name) #define IIRFILTSOS(name) LIQUID_CONCAT(iirfiltsos_cccf,name) #define IIRINTERP(name) LIQUID_CONCAT(iirinterp_cccf,name) #define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define MSRESAMP(name) LIQUID_CONCAT(msresamp_cccf,name) #define MSRESAMP2(name) LIQUID_CONCAT(msresamp2_cccf,name) // ordfilt #define RRESAMP(name) LIQUID_CONCAT(rresamp_cccf,name) #define RESAMP(name) LIQUID_CONCAT(resamp_cccf,name) #define RESAMP2(name) LIQUID_CONCAT(resamp2_cccf,name) //#define SYMSYNC(name) LIQUID_CONCAT(symsync_cccf,name) #define T float complex // general #define TO float complex // output #define TC float complex // coefficients #define TI float complex // input #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define POLY(name) LIQUID_CONCAT(polyf,name) #define TO_COMPLEX 1 #define TC_COMPLEX 1 #define TI_COMPLEX 1 #define PRINTVAL_TO(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_CFLOAT(X,F) // prototype files #include "autocorr.proto.c" #include "dds.proto.c" #include "fftfilt.proto.c" #include "firdecim.proto.c" #include "firfilt.proto.c" #include "firinterp.proto.c" #include "firpfb.proto.c" #include "iirdecim.proto.c" #include "iirfilt.proto.c" #include "iirfiltsos.proto.c" #include "iirinterp.proto.c" //#include "qmfb.proto.c" // ordfilt #include "msresamp.proto.c" #include "msresamp2.proto.c" #include "rresamp.proto.c" //#include "resamp.proto.c" // floating-point phase version #include "resamp.fixed.proto.c" // fixed-point phase version #include "resamp2.proto.c" //#include "symsync.proto.c" liquid-dsp-1.7.0/src/filter/src/filter_crcf.c000066400000000000000000000072021474751757600211130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Filter API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "crcf" // #define AUTOCORR(name) LIQUID_CONCAT(autocorr_crcf,name) #define FDELAY(name) LIQUID_CONCAT(fdelay_crcf,name) #define FFTFILT(name) LIQUID_CONCAT(fftfilt_crcf,name) #define FIRDECIM(name) LIQUID_CONCAT(firdecim_crcf,name) #define FIRFARROW(name) LIQUID_CONCAT(firfarrow_crcf,name) #define FIRFILT(name) LIQUID_CONCAT(firfilt_crcf,name) #define FIRINTERP(name) LIQUID_CONCAT(firinterp_crcf,name) #define FIRPFB(name) LIQUID_CONCAT(firpfb_crcf,name) #define IIRDECIM(name) LIQUID_CONCAT(iirdecim_crcf,name) #define IIRFILT(name) LIQUID_CONCAT(iirfilt_crcf,name) #define IIRFILTSOS(name) LIQUID_CONCAT(iirfiltsos_crcf,name) #define IIRINTERP(name) LIQUID_CONCAT(iirinterp_crcf,name) #define MSRESAMP(name) LIQUID_CONCAT(msresamp_crcf,name) #define MSRESAMP2(name) LIQUID_CONCAT(msresamp2_crcf,name) // ordfilt #define RRESAMP(name) LIQUID_CONCAT(rresamp_crcf,name) #define RESAMP(name) LIQUID_CONCAT(resamp_crcf,name) #define RESAMP2(name) LIQUID_CONCAT(resamp2_crcf,name) #define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) #define T float complex // general #define TO float complex // output #define TC float // coefficients #define TI float complex // input #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_crcf,name) #define POLY(name) LIQUID_CONCAT(polyf,name) #define TO_COMPLEX 1 #define TC_COMPLEX 0 #define TI_COMPLEX 1 #define PRINTVAL_TO(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_CFLOAT(X,F) // prototype files //#include "autocorr.proto.c" #include "fdelay.proto.c" #include "fftfilt.proto.c" #include "firdecim.proto.c" #include "firfarrow.proto.c" #include "firfilt.proto.c" #include "firinterp.proto.c" #include "firpfb.proto.c" #include "iirdecim.proto.c" #include "iirfilt.proto.c" #include "iirfiltsos.proto.c" #include "iirinterp.proto.c" #include "msresamp.proto.c" #include "msresamp2.proto.c" // ordfilt #include "rresamp.proto.c" //#include "resamp.proto.c" // floating-point phase version #include "resamp.fixed.proto.c" // fixed-point phase version #include "resamp2.proto.c" #include "symsync.proto.c" liquid-dsp-1.7.0/src/filter/src/filter_rrrf.c000066400000000000000000000074771474751757600211670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Filter API: floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "rrrf" // #define AUTOCORR(name) LIQUID_CONCAT(autocorr_rrrf,name) #define FDELAY(name) LIQUID_CONCAT(fdelay_rrrf,name) #define FFTFILT(name) LIQUID_CONCAT(fftfilt_rrrf,name) #define FIRDECIM(name) LIQUID_CONCAT(firdecim_rrrf,name) #define FIRFARROW(name) LIQUID_CONCAT(firfarrow_rrrf,name) #define FIRFILT(name) LIQUID_CONCAT(firfilt_rrrf,name) #define FIRINTERP(name) LIQUID_CONCAT(firinterp_rrrf,name) #define FIRHILB(name) LIQUID_CONCAT(firhilbf,name) #define FIRPFB(name) LIQUID_CONCAT(firpfb_rrrf,name) #define IIRDECIM(name) LIQUID_CONCAT(iirdecim_rrrf,name) #define IIRFILT(name) LIQUID_CONCAT(iirfilt_rrrf,name) #define IIRFILTSOS(name) LIQUID_CONCAT(iirfiltsos_rrrf,name) #define IIRHILB(name) LIQUID_CONCAT(iirhilbf,name) #define IIRINTERP(name) LIQUID_CONCAT(iirinterp_rrrf,name) #define MSRESAMP(name) LIQUID_CONCAT(msresamp_rrrf,name) #define MSRESAMP2(name) LIQUID_CONCAT(msresamp2_rrrf,name) #define ORDFILT(name) LIQUID_CONCAT(ordfilt_rrrf,name) #define RRESAMP(name) LIQUID_CONCAT(rresamp_rrrf,name) #define RESAMP(name) LIQUID_CONCAT(resamp_rrrf,name) #define RESAMP2(name) LIQUID_CONCAT(resamp2_rrrf,name) #define SYMSYNC(name) LIQUID_CONCAT(symsync_rrrf,name) #define T float // general #define TO float // output #define TC float // coefficients #define TI float // input #define WINDOW(name) LIQUID_CONCAT(windowf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define POLY(name) LIQUID_CONCAT(polyf,name) #define TO_COMPLEX 0 #define TC_COMPLEX 0 #define TI_COMPLEX 0 #define PRINTVAL_TO(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_FLOAT(X,F) // prototype files #include "autocorr.proto.c" #include "fdelay.proto.c" #include "fftfilt.proto.c" #include "firdecim.proto.c" #include "firfarrow.proto.c" #include "firfilt.proto.c" #include "firinterp.proto.c" #include "firhilb.proto.c" #include "firpfb.proto.c" #include "iirdecim.proto.c" #include "iirfilt.proto.c" #include "iirfiltsos.proto.c" #include "iirhilb.proto.c" #include "iirinterp.proto.c" #include "msresamp.proto.c" #include "msresamp2.proto.c" #include "ordfilt.proto.c" #include "rresamp.proto.c" //#include "resamp.proto.c" // floating-point phase version #include "resamp.fixed.proto.c" // fixed-point phase version #include "resamp2.proto.c" #include "symsync.proto.c" liquid-dsp-1.7.0/src/filter/src/firdecim.proto.c000066400000000000000000000226021474751757600215560ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // finite impulse response decimator object definitions #include #include #include // decimator structure struct FIRDECIM(_s) { TC * h; // coefficients array unsigned int h_len; // number of coefficients unsigned int M; // decimation factor WINDOW() w; // buffer DOTPROD() dp; // vector dot product TC scale; // output scaling factor }; // create decimator object // _M : decimation factor // _h : filter coefficients [size: _h_len x 1] // _h_len : filter coefficients length FIRDECIM() FIRDECIM(_create)(unsigned int _M, TC * _h, unsigned int _h_len) { // validate input if (_h_len == 0) return liquid_error_config("decim_%s_create(), filter length must be greater than zero", EXTENSION_FULL); if (_M == 0) return liquid_error_config("decim_%s_create(), decimation factor must be greater than zero", EXTENSION_FULL); FIRDECIM() q = (FIRDECIM()) malloc(sizeof(struct FIRDECIM(_s))); q->h_len = _h_len; q->M = _M; // allocate memory for coefficients q->h = (TC*) malloc((q->h_len)*sizeof(TC)); // load filter in reverse order unsigned int i; for (i=0; ih_len; i++) q->h[i] = _h[_h_len-i-1]; // create window (internal buffer) q->w = WINDOW(_create)(q->h_len); // create dot product object q->dp = DOTPROD(_create)(q->h, q->h_len); // set default scaling q->scale = 1; // reset filter state (clear buffer) FIRDECIM(_reset)(q); return q; } // create decimator from Kaiser prototype // _M : decimolation factor // _m : symbol delay // _as : stop-band attenuation [dB] FIRDECIM() FIRDECIM(_create_kaiser)(unsigned int _M, unsigned int _m, float _as) { // validate input if (_M < 2) return liquid_error_config("decim_%s_create_kaiser(), decim factor must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("decim_%s_create_kaiser(), filter delay must be greater than 0", EXTENSION_FULL); if (_as < 0.0f) return liquid_error_config("decim_%s_create_kaiser(), stop-band attenuation must be positive", EXTENSION_FULL); // compute filter coefficients (floating point precision) unsigned int h_len = 2*_M*_m + 1; float hf[h_len]; float fc = 0.5f / (float) (_M); liquid_firdes_kaiser(h_len, fc, _as, 0.0f, hf); // copy coefficients to type-specific array (e.g. float complex) TC hc[h_len]; unsigned int i; for (i=0; i 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 // _dt : fractional sample delay, 0 <= _dt < 1 FIRDECIM() FIRDECIM(_create_prototype)(int _type, unsigned int _M, unsigned int _m, float _beta, float _dt) { // validate input if (_M < 2) return liquid_error_config("decim_%s_create_prototype(), decimation factor must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("decim_%s_create_prototype(), filter delay must be greater than 0", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("decim_%s_create_prototype(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); if (_dt < -1.0f || _dt > 1.0f) return liquid_error_config("decim_%s_create_prototype(), filter fractional sample delay must be in [-1,1]", EXTENSION_FULL); // generate square-root Nyquist filter unsigned int h_len = 2*_M*_m + 1; float h[h_len]; if (liquid_firdes_prototype(_type,_M,_m,_beta,_dt,h) != LIQUID_OK) return liquid_error_config("decim_%s_create_prototype(), could not design internal filter", EXTENSION_FULL); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC hc[h_len]; for (i=0; ih_len = q_orig->h_len; q_copy->M = q_orig->M; q_copy->h = (TC *) malloc((q_orig->h_len)*sizeof(TC)); memmove(q_copy->h, q_orig->h, (q_orig->h_len)*sizeof(TC)); // copy window, dotprod,m and scale q_copy->w = WINDOW(_copy)(q_orig->w); q_copy->dp = DOTPROD(_copy)(q_orig->dp); q_copy->scale = q_orig->scale; return q_copy; } // destroy decimator object int FIRDECIM(_destroy)(FIRDECIM() _q) { WINDOW(_destroy)(_q->w); DOTPROD(_destroy)(_q->dp); free(_q->h); free(_q); return LIQUID_OK; } // print decimator object internals int FIRDECIM(_print)(FIRDECIM() _q) { printf("M); // print scaling printf(", scale="); PRINTVAL_TC(_q->scale,%g); printf(">\n"); return LIQUID_OK; } // reset decimator object int FIRDECIM(_reset)(FIRDECIM() _q) { return WINDOW(_reset)(_q->w); } // Get decimation rate unsigned int FIRDECIM(_get_decim_rate)(FIRDECIM() _q) { return _q->M; } // Set output scaling for decimator // _q : decimator object // _scale : scaling factor to apply to each output sample int FIRDECIM(_set_scale)(FIRDECIM() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // Get output scaling for decimator // _q : decimator object // _scale : scaling factor to apply to each output sample int FIRDECIM(_get_scale)(FIRDECIM() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // Compute complex frequency response \(H\) of decimator on prototype // filter coefficients at a specific frequency \(f_c\) // _q : decimator object // _fc : normalized frequency for evaluation // _H : pointer to output complex frequency response int FIRDECIM(_freqresp)(FIRDECIM() _q, float _fc, liquid_float_complex * _H) { #if TC_COMPLEX==0 int rc = liquid_freqrespf(_q->h, _q->h_len, _fc, _H); #elif TC_COMPLEX==1 int rc = liquid_freqrespcf(_q->h, _q->h_len, _fc, _H); #else # error("invalid complex type for coefficients") #endif // apply scaling *_H *= _q->scale; return rc; } // execute decimator // _q : decimator object // _x : input sample array [size: _M x 1] // _y : output sample pointer int FIRDECIM(_execute)(FIRDECIM() _q, TI * _x, TO * _y) { TI * r; // read pointer unsigned int i; for (i=0; i<_q->M; i++) { WINDOW(_push)(_q->w, _x[i]); if (i==0) { // read buffer (retrieve pointer to aligned memory array) WINDOW(_read)(_q->w, &r); // execute dot product DOTPROD(_execute)(_q->dp, r, _y); // apply scaling factor *_y *= _q->scale; } } return LIQUID_OK; } // execute decimator on block of _n*_M input samples // _q : decimator object // _x : input array [size: _n*_M x 1] // _n : number of _output_ samples // _y : output array [_size: _n x 1] int FIRDECIM(_execute_block)(FIRDECIM() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute _M input samples computing just one output each time FIRDECIM(_execute)(_q, &_x[i*_q->M], &_y[i]); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/firdes.c000066400000000000000000000603231474751757600201100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Finite impulse response filter design // // References: // [Herrmann:1973] O. Herrmann, L. R. Rabiner, and D. S. K. Chan, // "Practical design rules for optimum finite impulse response // lowpass digital filters," Bell Syst. Tech. Journal, vol. 52, // pp. 769--99, July-Aug. 1973 // [Vaidyanathan:1993] Vaidyanathan, P. P., "Multirate Systems and // Filter Banks," 1993, Prentice Hall, Section 3.2.1 #include #include #include #include #include "liquid.internal.h" // method to estimate required filter length #define ESTIMATE_REQ_FILTER_LEN_METHOD_KAISER (0) #define ESTIMATE_REQ_FILTER_LEN_METHOD_HERRMANN (1) // select filter estimate method #define ESTIMATE_REQ_FILTER_LEN_METHOD (0) const char * liquid_firfilt_type_str[LIQUID_FIRFILT_NUM_TYPES][2] = { // short, long name {"unknown", "unknown"}, // Nyquist filter prototypes {"kaiser", "Nyquist Kaiser filter"}, {"pm", "Parks-McClellan filter"}, {"rcos", "raised-cosine filter"}, {"fexp", "flipped exponential"}, {"fsech", "flipped hyperbolic secant"}, {"farcsech", "flipped arc-hyperbolic secant"}, // root-Nyquist filter prototypes {"arkaiser", "root-Nyquist Kaiser (approximate optimum)"}, {"rkaiser", "root-Nyquist Kaiser (true optimum)"}, {"rrcos", "root raised-cosine"}, {"hm3", "harris-Moerder-3 filter"}, {"gmsktx", "GMSK transmit filter"}, {"gmskrx", "GMSK receive filter"}, {"rfexp", "root flipped exponential"}, {"rfsech", "root flipped hyperbolic secant"}, {"rfarcsech","root flipped arc-hyperbolic secant"}, }; // estimate required filter length given transition bandwidth and // stop-band attenuation // _df : transition bandwidth (0 < _df < 0.5) // _as : stopband suppression level [dB] (_as > 0) unsigned int estimate_req_filter_len(float _df, float _as) { if (_df > 0.5f || _df <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len(), invalid bandwidth : %f", _df); return 0; } else if (_as <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len(), invalid stopband level : %f", _as); return 0; } // compute filter length estimate #if ESTIMATE_REQ_FILTER_LEN_METHOD == ESTIMATE_REQ_FILTER_LEN_METHOD_KAISER // use Kaiser's estimate unsigned int h_len = (unsigned int) estimate_req_filter_len_Kaiser(_df,_as); #elif ESTIMATE_REQ_FILTER_LEN_METHOD == ESTIMATE_REQ_FILTER_LEN_METHOD_HERRMANN // use Herrmann's estimate unsigned int h_len = (unsigned int) estimate_req_filter_len_Herrmann(_df,_as); #else # error "invalid required filter length estimation method" #endif return h_len; } // estimate filter stop-band attenuation given // _df : transition bandwidth (0 < _b < 0.5) // _n : filter length float estimate_req_filter_As(float _df, unsigned int _n) { // run search for stop-band attenuation which gives these results float as0 = 0.01f; // lower bound float as1 = 200.0f; // upper bound float as_hat = 0.0f; // stop-band attenuation estimate float N_hat = 0.0f; // filter length estimate // perform simple bisection search unsigned int num_iterations = 20; unsigned int i; for (i=0; i 0 // _n : filter length float estimate_req_filter_df(float _as, unsigned int _n) { // run search for stop-band attenuation which gives these results float df0 = 1e-3f; // lower bound float df1 = 0.499f; // upper bound float df_hat = 0.0f; // stop-band attenuation estimate float N_hat = 0.0f; // filter length estimate // perform simple bisection search unsigned int num_iterations = 20; unsigned int i; for (i=0; i 0) float estimate_req_filter_len_Kaiser(float _df, float _as) { if (_df > 0.5f || _df <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len_Kaiser(), invalid bandwidth : %f", _df); return 0.0f; } else if (_as <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len(), invalid stopband level : %f", _as); return 0.0f; } // compute filter length estimate return (_as - 7.95f)/(14.26f*_df); } // estimate required filter length given transition bandwidth and // stop-band attenuation (algorithm from [Herrmann:1973]) // _df : transition bandwidth (0 < _df < 0.5) // _as : stop-band attenuation [dB] (as > 0) float estimate_req_filter_len_Herrmann(float _df, float _as) { if (_df > 0.5f || _df <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len_Herrmann(), invalid bandwidth : %f", _df); return 0.0f; } else if (_as <= 0.0f) { liquid_error(LIQUID_EICONFIG,"estimate_req_filter_len(), invalid stopband level : %f", _as); return 0.0f; } // Gaeddert's revisions: if (_as > 105.0f) return estimate_req_filter_len_Kaiser(_df,_as); _as += 7.4f; // compute delta_1, delta_2 float d1, d2; d1 = d2 = powf(10.0, -_as/20.0); // compute log of delta_1, delta_2 float t1 = log10f(d1); float t2 = log10f(d2); // compute D_infinity(delta_1, delta_2) float Dinf = (0.005309f*t1*t1 + 0.07114f*t1 - 0.4761f)*t2 - (0.002660f*t1*t1 + 0.59410f*t1 + 0.4278f); // compute f(delta_1, delta_2) float f = 11.012f + 0.51244f*(t1-t2); // compute filter length estimate float h_len = (Dinf - f*_df*_df) / _df + 1.0f; return h_len; } // returns the Kaiser window beta factor give the filter's target // stop-band attenuation (as) [Vaidyanathan:1993] // _as : target filter's stop-band attenuation [dB], _as > 0 float kaiser_beta_As(float _as) { _as = fabsf(_as); float beta; if (_as > 50.0f) beta = 0.1102f*(_as - 8.7f); else if (_as > 21.0f) beta = 0.5842*powf(_as - 21, 0.4f) + 0.07886f*(_as - 21); else beta = 0.0f; return beta; } // Design FIR filter using generic window/taper method // _wtype : window type, e.g. LIQUID_WINDOW_HAMMING // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _arg : window-specific argument, if required // _h : output coefficient buffer, [size: _n x 1] int liquid_firdes_windowf(int _wtype, unsigned int _n, float _fc, float _arg, float * _h) { // validate inputs if (_fc <= 0.0f || _fc > 0.5f) { return liquid_error(LIQUID_EICONFIG,"liquid_firdes_window(), cutoff frequency (%12.4e) out of range (0, 0.5)", _fc); } else if (_n == 0) { return liquid_error(LIQUID_EICONFIG,"liquid_firdes_window(), filter length must be greater than zero"); } float t, h1, h2; unsigned int i; for (i=0; i<_n; i++) { // time vector t = (float)i - (float)(_n-1)/2.0f; // sinc prototype h1 = sincf(2.0f*_fc*t); // window h2 = liquid_windowf(_wtype,i,_n,_arg); // composite _h[i] = h1*h2; } return LIQUID_OK; } // Design FIR using kaiser window // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 // _h : output coefficient buffer, [size: _n x 1] int liquid_firdes_kaiser(unsigned int _n, float _fc, float _as, float _mu, float *_h) { // validate inputs if (_mu < -0.5f || _mu > 0.5f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_kaiser(), _mu (%12.4e) out of range [-0.5,0.5]", _mu); if (_fc <= 0.0f || _fc > 0.5f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_kaiser(), cutoff frequency (%12.4e) out of range (0, 0.5)", _fc); if (_n == 0) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_kaiser(), filter length must be greater than zero"); // choose kaiser beta parameter (approximate) float beta = kaiser_beta_As(_as); // TODO: invoke liquid_firdes_windowf() float t, h1, h2; unsigned int i; for (i=0; i<_n; i++) { t = (float)i - (float)(_n-1)/2 + _mu; // sinc prototype h1 = sincf(2.0f*_fc*t); // kaiser window h2 = liquid_kaiser(i,_n,beta); //printf("t = %f, h1 = %f, h2 = %f\n", t, h1, h2); // composite _h[i] = h1*h2; } return LIQUID_OK; } // Design finite impulse response notch filter // _m : filter semi-length, m in [1,1000] // _f0 : filter notch frequency (normalized), -0.5 <= _fc <= 0.5 // _as : stop-band attenuation [dB], _as > 0 // _h : output coefficient buffer, [size: 2*_m+1 x 1] int liquid_firdes_notch(unsigned int _m, float _f0, float _as, float * _h) { // validate inputs if (_m < 1 || _m > 1000) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_notch(), _m (%12u) out of range [1,1000]", _m); if (_f0 < -0.5f || _f0 > 0.5f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_notch(), notch frequency (%12.4e) must be in [-0.5,0.5]", _f0); if (_as <= 0.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_notch(), stop-band suppression (%12.4e) must be greater than zero", _as); // choose kaiser beta parameter (approximate) float beta = kaiser_beta_As(_as); // design filter unsigned int h_len = 2*_m+1; unsigned int i; float scale = 0.0f; for (i=0; i= 0) // _theta : LoS component angle of arrival // _h : output coefficient buffer int liquid_firdes_doppler(unsigned int _n, float _fd, float _K, float _theta, float * _h) { // TODO: add error checking float t, J, r, w; float beta = 4; // kaiser window parameter unsigned int i; for (i=0; i<_n; i++) { // time sample t = (float)i - (float)(_n-1)/2; // Bessel J = 1.5*liquid_besselj0f(fabsf((float)(2*M_PI*_fd*t))); // Rice-K component r = 1.5*_K/(_K+1)*cosf(2*M_PI*_fd*t*cosf(_theta)); // Window w = liquid_kaiser(i, _n, beta); // composite _h[i] = (J+r)*w; //printf("t=%f, J=%f, r=%f, w=%f\n", t, J, r, w); } return LIQUID_OK; } // // filter analysis // // liquid_filter_autocorr() // // Compute auto-correlation of filter at a specific lag. // // _h : filter coefficients [size: _h_len x 1] // _h_len : filter length // _lag : auto-correlation lag (samples) float liquid_filter_autocorr(float * _h, unsigned int _h_len, int _lag) { // auto-correlation is even symmetric _lag = abs(_lag); // lag outside of filter length is zero if (_lag >= _h_len) return 0.0f; // compute auto-correlation float rxx=0.0f; // initialize auto-correlation to zero unsigned int i; for (i=_lag; i<_h_len; i++) rxx += _h[i] * _h[i-_lag]; return rxx; } // liquid_filter_crosscorr() // // Compute cross-correlation of two filters at a specific lag. // // _h : filter coefficients [size: _h_len] // _h_len : filter length // _g : filter coefficients [size: _g_len] // _g_len : filter length // _lag : cross-correlation lag (samples) float liquid_filter_crosscorr(float * _h, unsigned int _h_len, float * _g, unsigned int _g_len, int _lag) { // cross-correlation is odd symmetric if (_h_len < _g_len) { return liquid_filter_crosscorr(_g, _g_len, _h, _h_len, -_lag); } // at this point _h_len > _g_len // assert(_h_len > _g_len); if (_lag <= -(int)_g_len) return 0.0f; if (_lag >= (int)_h_len) return 0.0f; int ig = _lag < 0 ? -_lag : 0; // starting index for _g int ih = _lag > 0 ? _lag : 0; // starting index for _h // compute length of overlap // condition 1: condition 2: condition 3: // [------ h ------] [------ h ------] [------ h ------] // [-- g --] [-- g --] [-- g --] // >| n |< >| n |< >| n |< // int n; if (_lag < 0) n = (int)_g_len + _lag; else if (_lag < (_h_len-_g_len)) n = _g_len; else n = _h_len - _lag; // compute cross-correlation float rxy=0.0f; // initialize auto-correlation to zero int i; for (i=0; i< n; i++) rxy += _h[ih+i] * _g[ig+i]; return rxy; } // liquid_filter_isi() // // Compute inter-symbol interference (ISI)--both RMS and // maximum--for the filter _h. // // _h : filter coefficients [size: 2*_k*_m+1 x 1] // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _rms : output root mean-squared ISI // _max : maximum ISI void liquid_filter_isi(float * _h, unsigned int _k, unsigned int _m, float * _rms, float * _max) { unsigned int h_len = 2*_k*_m+1; // compute zero-lag auto-correlation float rxx0 = liquid_filter_autocorr(_h,h_len,0); //printf("rxx0 = %12.8f\n", rxx0); unsigned int i; float isi_rms = 0.0f; float isi_max = 0.0f; float e; for (i=1; i<=2*_m; i++) { e = liquid_filter_autocorr(_h,h_len,i*_k) / rxx0; e = fabsf(e); isi_rms += e*e; if (i==1 || e > isi_max) isi_max = e; } *_rms = sqrtf( isi_rms / (float)(2*_m) ); *_max = isi_max; } // Compute relative out-of-band energy // // _h : filter coefficients [size: _h_len x 1] // _h_len : filter length // _fc : analysis cut-off frequency // _nfft : fft size float liquid_filter_energy(float * _h, unsigned int _h_len, float _fc, unsigned int _nfft) { // validate input if (_fc < 0.0f || _fc > 0.5f) { liquid_error(LIQUID_EICONFIG,"liquid_filter_energy(), cut-off frequency must be in [0,0.5]"); return 0.0f; } else if (_h_len == 0) { liquid_error(LIQUID_EICONFIG,"liquid_filter_energy(), filter length must be greater than zero"); return 0.0f; } else if (_nfft == 0) { liquid_error(LIQUID_EICONFIG,"liquid_filter_energy(), fft size must be greater than zero"); return 0.0f; } // allocate memory for complex phasor float complex expjwt[_h_len]; // initialize accumulators float e_total = 0.0f; // total energy float e_stopband = 0.0f; // stop-band energy // create dotprod object dotprod_crcf dp = dotprod_crcf_create(_h,_h_len); unsigned int i; unsigned int k; for (i=0; i<_nfft; i++) { float f = 0.5f * (float)i / (float)(_nfft); // initialize complex phasor for (k=0; k<_h_len; k++) expjwt[k] = cexpf(_Complex_I*2*M_PI*f*k); // compute vector dot product float complex v; dotprod_crcf_execute(dp, expjwt, &v); // accumulate output float e2 = crealf( v*conjf(v) ); e_total += e2; e_stopband += (f >= _fc) ? e2 : 0.0f; } // destroy dotprod object dotprod_crcf_destroy(dp); // return energy ratio return e_stopband / e_total; } // Get static frequency response from filter coefficients at particular // frequency with real-valued coefficients // _h : coefficients, [size: _h_len x 1] // _h_len : length of coefficients array // _fc : center frequency for analysis, -0.5 <= _fc <= 0.5 // _H : pointer to output value int liquid_freqrespf(float * _h, unsigned int _h_len, float _fc, float complex * _H) { // compute dot product between coefficients and exp{ 2 pi fc {0..n-1} } float complex H = 0.0f; unsigned int i; for (i=0; i<_h_len; i++) H += _h[i] * cexpf(-_Complex_I*2*M_PI*_fc*i); // set return value *_H = H; return LIQUID_OK; } // Get static frequency response from filter coefficients at particular // frequency with complex coefficients // _h : coefficients, [size: _h_len x 1] // _h_len : length of coefficients array // _fc : center frequency for analysis, -0.5 <= _fc <= 0.5 // _H : pointer to output value int liquid_freqrespcf(float complex * _h, unsigned int _h_len, float _fc, float complex * _H) { // compute dot product between coefficients and exp{ 2 pi fc {0..n-1} } float complex H = 0.0f; unsigned int i; for (i=0; i<_h_len; i++) H += _h[i] * cexpf(-_Complex_I*2*M_PI*_fc*i); // set return value *_H = H; return LIQUID_OK; } // returns filter type based on input string int liquid_getopt_str2firfilt(const char * _str) { // compare each string to short name unsigned int i; for (i=0; i #include #include #include #include #include "liquid.internal.h" #define LIQUID_FIRDESPM_DEBUG 0 #define LIQUID_FIRDESPM_DEBUG_PRINT 0 #define LIQUID_FIRDESPM_DEBUG_FILENAME "firdespm_internal_debug.m" #if LIQUID_FIRDESPM_DEBUG int firdespm_output_debug_file(firdespm _q); #endif #if 0 // initialize internal memory and arrays int firdespm_init_memory(firdespm _q, unsigned int _h_len, unsigned int _num_bands); #endif // initialize the frequency grid on the disjoint bounded set int firdespm_init_grid(firdespm _q); // compute interpolating polynomial int firdespm_compute_interp(firdespm _q); // compute error signal from actual response (interpolator // output), desired response, and weights int firdespm_compute_error(firdespm _q); // search error curve for _r+1 extremal indices int firdespm_iext_search(firdespm _q); // evaluates result to determine if Remez exchange algorithm // has converged int firdespm_is_search_complete(firdespm _q); // compute filter taps (coefficients) from result int firdespm_compute_taps(firdespm _q, float * _h); // structured data type struct firdespm_s { // constants unsigned int h_len; // filter length unsigned int s; // odd/even filter length unsigned int n; // filter semi-length unsigned int r; // number of approximating functions unsigned int num_bands; // number of discrete bands unsigned int grid_size; // number of points on the grid unsigned int grid_density; // density of the grid // band type (e.g. LIQUID_FIRDESPM_BANDPASS) liquid_firdespm_btype btype; // filter description parameters double * bands; // bands array [size: 2*num_bands] double * des; // desired response [size: num_bands] double * weights; // weights [size: num_bands] liquid_firdespm_wtype * wtype; // dense grid elements double * F; // frequencies, [0, 0.5] double * D; // desired response double * W; // weight double * E; // error double * x; // Chebyshev points : cos(2*pi*f) double * alpha; // Lagrange interpolating polynomial double * c; // interpolants double rho; // extremal weighted error unsigned int * iext; // indices of extrema unsigned int num_exchanges; // number of changes in extrema firdespm_callback callback; // user-defined callback function void * userdata; // user-defined structure for callback function #if LIQUID_FIRDESPM_DEBUG FILE * fid; #endif }; // run filter design (full life cycle of object) // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _des : desired response [size: _num_bands x 1] // _weights : response weighting [size: _num_bands x 1] // _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) // _h : output coefficients array [size: _h_len x 1] int firdespm_run(unsigned int _h_len, unsigned int _num_bands, float * _bands, float * _des, float * _weights, liquid_firdespm_wtype * _wtype, liquid_firdespm_btype _btype, float * _h) { // create object firdespm q = firdespm_create(_h_len,_num_bands,_bands,_des,_weights,_wtype,_btype); // execute firdespm_execute(q,_h); // destroy firdespm_destroy(q); return LIQUID_OK; } // run filter design for basic low-pass filter // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 [ignored] // _h : output coefficient buffer, [size: _n x 1] int firdespm_lowpass(unsigned int _n, float _fc, float _as, float _mu, float * _h) { // validate inputs if (_mu < -0.5f || _mu > 0.5f) return liquid_error(LIQUID_EICONFIG,"firdespm_lowpass(), _mu (%12.4e) out of range [-0.5,0.5]", _mu); if (_fc < 0.0f || _fc > 0.5f) return liquid_error(LIQUID_EICONFIG,"firdespm_lowpass(), cutoff frequency (%12.4e) out of range (0, 0.5)", _fc); if (_n == 0) return liquid_error(LIQUID_EICONFIG,"firdespm_lowpass(), filter length must be greater than zero"); // estimate transition band float ft = estimate_req_filter_df(_as, _n); // derived values float fp = _fc - 0.5*ft; // pass-band cutoff frequency float fs = _fc + 0.5*ft; // stop-band cutoff frequency liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; // derived values unsigned int num_bands = 2; float bands[4] = {0.0f, fp, fs, 0.5f}; float des[2] = {1.0f, 0.0f}; float weights[2] = {1.0f, 1.0f}; liquid_firdespm_wtype wtype[2] = {LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_EXPWEIGHT}; // design filter return firdespm_run(_n,num_bands,bands,des,weights,wtype,btype,_h); } // create firdespm object // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _des : desired response [size: _num_bands x 1] // _weights : response weighting [size: _num_bands x 1] // _wtype : weight types (e.g. LIQUID_FIRDESPM_FLATWEIGHT) [size: _num_bands x 1] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) firdespm firdespm_create(unsigned int _h_len, unsigned int _num_bands, float * _bands, float * _des, float * _weights, liquid_firdespm_wtype * _wtype, liquid_firdespm_btype _btype) { // basic validation if (_h_len==0) return liquid_error_config("firdespm_create(), filter length cannot be 0"); if (_num_bands==0) return liquid_error_config("firdespm_create(), number of bands cannot be 0"); // validate filter specification unsigned int i; int bands_valid = 1; int weights_valid = 1; // ensure bands are within [0,0.5] for (i=0; i<2*_num_bands; i++) bands_valid &= _bands[i] >= 0.0 && _bands[i] <= 0.5; // ensure bands are non-decreasing for (i=1; i<2*_num_bands; i++) bands_valid &= _bands[i] >= _bands[i-1]; // ensure weights are greater than 0 // TODO: ignore weights if pointer is NULL for (i=0; i<_num_bands; i++) weights_valid &= _weights[i] > 0; if (!bands_valid) return liquid_error_config("firdespm_create(), invalid bands"); if (!weights_valid) return liquid_error_config("firdespm_create(), invalid weights (must be positive)"); // create object firdespm q = (firdespm) malloc(sizeof(struct firdespm_s)); // compute number of extremal frequencies q->h_len = _h_len; // filter length q->s = q->h_len % 2; // odd/even length q->n = (q->h_len - q->s)/2; // filter semi-length q->r = q->n + q->s; // number of approximating functions q->btype = _btype; // set band type // allocate memory for extremal frequency set, interpolating polynomial q->iext = (unsigned int*) malloc((q->r+1)*sizeof(unsigned int)); q->x = (double*) malloc((q->r+1)*sizeof(double)); q->alpha = (double*) malloc((q->r+1)*sizeof(double)); q->c = (double*) malloc((q->r+1)*sizeof(double)); // allocate memory for arrays q->num_bands = _num_bands; q->bands = (double*) malloc(2*q->num_bands*sizeof(double)); q->des = (double*) malloc( q->num_bands*sizeof(double)); q->weights = (double*) malloc( q->num_bands*sizeof(double)); // allocate memory for weighting types q->wtype = (liquid_firdespm_wtype*) malloc(q->num_bands*sizeof(liquid_firdespm_wtype)); if (_wtype == NULL) { // set to default (LIQUID_FIRDESPM_FLATWEIGHT) for (i=0; inum_bands; i++) q->wtype[i] = LIQUID_FIRDESPM_FLATWEIGHT; } else { // copy from input for (i=0; inum_bands; i++) q->wtype[i] = _wtype[i]; } // copy input arrays for (i=0; inum_bands; i++) { q->bands[2*i+0] = _bands[2*i+0]; q->bands[2*i+1] = _bands[2*i+1]; q->des[i] = _des[i]; q->weights[i] = _weights == NULL ? 1.0f : _weights[i]; } // estimate grid size // TODO : adjust grid density based on expected value for rho q->grid_density = 20; q->grid_size = 0; double df = 0.5/(q->grid_density*q->r); // frequency step for (i=0; inum_bands; i++) { double f0 = q->bands[2*i+0]; // lower band edge double f1 = q->bands[2*i+1]; // upper band edge q->grid_size += (unsigned int)( (f1-f0)/df + 1.0 ); } // create the grid q->F = (double*) malloc(q->grid_size*sizeof(double)); q->D = (double*) malloc(q->grid_size*sizeof(double)); q->W = (double*) malloc(q->grid_size*sizeof(double)); q->E = (double*) malloc(q->grid_size*sizeof(double)); q->callback = NULL; q->userdata = NULL; firdespm_init_grid(q); // TODO : fix grid, weights according to filter type // return object return q; } // create firdespm object with user-defined callback // _h_len : length of filter (number of taps) // _num_bands : number of frequency bands // _bands : band edges, f in [0,0.5], [size: _num_bands x 2] // _btype : band type (e.g. LIQUID_FIRDESPM_BANDPASS) // _callback : user-defined callback for specifying desired response & weights // _userdata : user-defined data structure for callback function firdespm firdespm_create_callback(unsigned int _h_len, unsigned int _num_bands, float * _bands, liquid_firdespm_btype _btype, firdespm_callback _callback, void * _userdata) { // basic validation if (_h_len==0) return liquid_error_config("firdespm_create_callback(), filter length cannot be 0"); if (_num_bands==0) return liquid_error_config("firdespm_create_callback(), number of bands cannot be 0"); // validate input unsigned int i; int bands_valid = 1; // ensure bands are within [0,0.5] for (i=0; i<2*_num_bands; i++) bands_valid &= _bands[i] >= 0.0 && _bands[i] <= 0.5; // ensure bands are non-decreasing for (i=1; i<2*_num_bands; i++) bands_valid &= _bands[i] >= _bands[i-1]; if (!bands_valid) return liquid_error_config("firdespm_create(), invalid bands"); // create object firdespm q = (firdespm) malloc(sizeof(struct firdespm_s)); // compute number of extremal frequencies q->h_len = _h_len; // filter length q->s = q->h_len % 2; // odd/even length q->n = (q->h_len - q->s)/2; // filter semi-length q->r = q->n + q->s; // number of approximating functions q->btype = _btype; // set band type q->callback = _callback; q->userdata = _userdata; // allocate memory for extremal frequency set, interpolating polynomial q->iext = (unsigned int*) malloc((q->r+1)*sizeof(unsigned int)); q->x = (double*) malloc((q->r+1)*sizeof(double)); q->alpha = (double*) malloc((q->r+1)*sizeof(double)); q->c = (double*) malloc((q->r+1)*sizeof(double)); // allocate memory for arrays q->num_bands = _num_bands; q->bands = (double*) malloc(2*q->num_bands*sizeof(double)); q->des = (double*) malloc( q->num_bands*sizeof(double)); q->weights = (double*) malloc( q->num_bands*sizeof(double)); q->wtype = (liquid_firdespm_wtype*) malloc(q->num_bands*sizeof(liquid_firdespm_wtype)); // copy input arrays for (i=0; inum_bands; i++) { q->bands[2*i+0] = _bands[2*i+0]; q->bands[2*i+1] = _bands[2*i+1]; q->des[i] = 0.0f; q->weights[i] = 0.0f; } // estimate grid size // TODO : adjust grid density based on expected value for rho q->grid_density = 20; q->grid_size = 0; double df = 0.5/(q->grid_density*q->r); // frequency step for (i=0; inum_bands; i++) { double f0 = q->bands[2*i+0]; // lower band edge double f1 = q->bands[2*i+1]; // upper band edge q->grid_size += (unsigned int)( (f1-f0)/df + 1.0 ); } // create the grid q->F = (double*) malloc(q->grid_size*sizeof(double)); q->D = (double*) malloc(q->grid_size*sizeof(double)); q->W = (double*) malloc(q->grid_size*sizeof(double)); q->E = (double*) malloc(q->grid_size*sizeof(double)); firdespm_init_grid(q); // TODO : fix grid, weights according to filter type // return object return q; } // copy object firdespm firdespm_copy(firdespm q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firdespm_copy(), object cannot be NULL"); // create filter object and copy base parameters firdespm q_copy = (firdespm) malloc(sizeof(struct firdespm_s)); memmove(q_copy, q_orig, sizeof(struct firdespm_s)); // copy memory for filter description parameters q_copy->bands = (double*)liquid_malloc_copy(q_orig->bands, 2*q_orig->num_bands, sizeof(double)); q_copy->des = (double*)liquid_malloc_copy(q_orig->des, q_orig->num_bands, sizeof(double)); q_copy->weights = (double*)liquid_malloc_copy(q_orig->weights, q_orig->num_bands, sizeof(double)); q_copy->wtype = (liquid_firdespm_wtype*) liquid_malloc_copy(q_orig->wtype, q_orig->num_bands, sizeof(liquid_firdespm_wtype)); // copy the grid q_copy->F = (double*) liquid_malloc_copy(q_copy->F, q_orig->grid_size, sizeof(double)); q_copy->D = (double*) liquid_malloc_copy(q_copy->D, q_orig->grid_size, sizeof(double)); q_copy->W = (double*) liquid_malloc_copy(q_copy->W, q_orig->grid_size, sizeof(double)); q_copy->E = (double*) liquid_malloc_copy(q_copy->E, q_orig->grid_size, sizeof(double)); // copy memory for extremal frequency set, interpolating polynomial q_copy->iext = (unsigned int*) liquid_malloc_copy(q_copy->iext, q_orig->r+1,sizeof(unsigned int)); q_copy->x = (double*) liquid_malloc_copy(q_copy->x, q_orig->r+1,sizeof(double)); q_copy->alpha = (double*) liquid_malloc_copy(q_copy->alpha,q_orig->r+1,sizeof(double)); q_copy->c = (double*) liquid_malloc_copy(q_copy->c, q_orig->r+1,sizeof(double)); return q_copy; } // destroy firdespm object int firdespm_destroy(firdespm _q) { #if LIQUID_FIRDESPM_DEBUG firdespm_output_debug_file(_q); #endif // free memory for extremal frequency set, interpolating polynomial free(_q->iext); free(_q->x); free(_q->alpha); free(_q->c); // free dense grid elements free(_q->F); free(_q->D); free(_q->W); free(_q->E); // free band description elements free(_q->bands); free(_q->des); free(_q->weights); free(_q->wtype); // free object free(_q); return LIQUID_OK; } // print firdespm object internals int firdespm_print(firdespm _q) { unsigned int i; printf("num_bands; i++) printf("%g,", _q->bands[2*i+0]); printf("]"); printf(", hi=["); for (i=0; i<_q->num_bands; i++) printf("%g,", _q->bands[2*i+1]); printf("]"); printf(", des=["); for (i=0; i<_q->num_bands; i++) printf("%g,", _q->des[i]); printf("]"); printf(", w=["); for (i=0; i<_q->num_bands; i++) printf("%g,", _q->weights[i]); printf("]"); printf(">\n"); return LIQUID_OK; } // execute filter design, storing result in _h int firdespm_execute(firdespm _q, float * _h) { unsigned int i; // initial guess of extremal frequencies evenly spaced on F // TODO : guarantee at least one extremal frequency lies in each band for (i=0; i<_q->r+1; i++) { _q->iext[i] = (i * (_q->grid_size-1)) / _q->r; #if LIQUID_FIRDESPM_DEBUG_PRINT printf("iext_guess[%3u] = %u\n", i, _q->iext[i]); #endif } // iterate over the Remez exchange algorithm unsigned int p; unsigned int max_iterations = 40; for (p=0; pgrid_density*_q->r); #if LIQUID_FIRDESPM_DEBUG_PRINT printf("df : %12.8f\n", df); #endif #if 0 firdespm_print(_q); // compute total bandwidth double b=0.0; for (i=0; i<_q->num_bands; i++) b += _q->bands[2*i+1] - _q->bands[2*i+0]; printf("b : %12.8f\n", b); // adjust frequency step size if it is too large double g = b / (df * _q->r); // approximate oversampling rate (points/extrema) double gmin = 4.0; if (g < gmin) df *= g / gmin; printf("df : %12.8f\n", df); #endif // number of grid points counter unsigned int n = 0; double f0, f1; double fw = 1.0f; // weighting function for (i=0; i<_q->num_bands; i++) { // extract band edges f0 = _q->bands[2*i+0]; f1 = _q->bands[2*i+1]; // ensure first point is not zero for differentiator // and Hilbert transforms due to transformation (below) if (i==0 && _q->btype != LIQUID_FIRDESPM_BANDPASS) f0 = f0 < df ? df : f0; // compute the number of gridpoints in this band unsigned int num_points = (unsigned int)( (f1-f0)/df + 0.5 ); // ensure at least one point per band if (num_points < 1) num_points = 1; //printf("band : [%12.8f %12.8f] %3u points\n",f0,f1,num_points); // add points to grid for (j=0; jF[n] = f0 + j*df; // compute desired response using function pointer if provided if (_q->callback != NULL) { _q->callback(_q->F[n], _q->userdata, &_q->D[n], &_q->W[n]); } else { _q->D[n] = _q->des[i]; // compute weight, applying weighting function switch (_q->wtype[i]) { case LIQUID_FIRDESPM_FLATWEIGHT: fw = 1.0f; break; case LIQUID_FIRDESPM_EXPWEIGHT: fw = expf(2.0f*j*df); break; case LIQUID_FIRDESPM_LINWEIGHT: fw = 1.0f + 2.7f*j*df; break; default: return liquid_error(LIQUID_EICONFIG,"firdespm_init_grid(), invalid weighting specifier: %d", _q->wtype[i]); } _q->W[n] = _q->weights[i] * fw; } n++; } // force endpoint to be upper edge of frequency band _q->F[n-1] = f1; // according to Janovetz } _q->grid_size = n; // take care of special symmetry conditions here if (_q->btype == LIQUID_FIRDESPM_BANDPASS) { if (_q->s == 0) { // even length filter for (i=0; i<_q->grid_size; i++) { _q->D[i] /= cos(M_PI*_q->F[i]); _q->W[i] *= cos(M_PI*_q->F[i]); } // force weight at endpoint to be (nearly) zero //_q->W[_q->grid_size-1] = 6.12303177e-17f; } } else { // differentiator, Hilbert transform if (_q->s == 0) { // even length filter for (i=0; i<_q->grid_size; i++) { _q->D[i] /= sin(M_PI*_q->F[i]); _q->W[i] *= sin(M_PI*_q->F[i]); } } else { // odd length filter for (i=0; i<_q->grid_size; i++) { _q->D[i] /= sin(2*M_PI*_q->F[i]); _q->W[i] *= sin(2*M_PI*_q->F[i]); } } } return LIQUID_OK; } // compute interpolating polynomial int firdespm_compute_interp(firdespm _q) { unsigned int i; // compute Chebyshev points on F[iext[]] : cos(2*pi*f) for (i=0; i<_q->r+1; i++) { _q->x[i] = cos(2*M_PI*_q->F[_q->iext[i]]); #if LIQUID_FIRDESPM_DEBUG_PRINT printf("x[%3u] = %12.8f\n", i, _q->x[i]); #endif } //printf("\n"); // compute Lagrange interpolating polynomial poly_fit_lagrange_barycentric(_q->x,_q->r+1,_q->alpha); #if LIQUID_FIRDESPM_DEBUG_PRINT for (i=0; i<_q->r+1; i++) printf("a[%3u] = %12.8f\n", i, _q->alpha[i]); #endif // compute rho double t0 = 0.0; // numerator double t1 = 0.0; // denominator for (i=0; i<_q->r+1; i++) { //printf("D[%3u] = %16.8e, W[%3u] = %16.8e\n", i, _q->D[_q->iext[i]], i, _q->W[_q->iext[i]]); t0 += _q->alpha[i] * _q->D[_q->iext[i]]; t1 += _q->alpha[i] / _q->W[_q->iext[i]] * (i % 2 ? -1.0 : 1.0); } _q->rho = t0/t1; #if LIQUID_FIRDESPM_DEBUG_PRINT printf(" rho : %12.4e\n", _q->rho); printf("\n"); #endif // compute polynomial values (interpolants) for (i=0; i<_q->r+1; i++) { _q->c[i] = _q->D[_q->iext[i]] - (i % 2 ? -1 : 1) * _q->rho / _q->W[_q->iext[i]]; #if LIQUID_FIRDESPM_DEBUG_PRINT printf("c[%3u] = %16.8e\n", i, _q->c[i]); #endif } return LIQUID_OK; } int firdespm_compute_error(firdespm _q) { unsigned int i; double xf; double H; for (i=0; i<_q->grid_size; i++) { // compute actual response xf = cos(2*M_PI*_q->F[i]); H = poly_val_lagrange_barycentric(_q->x,_q->c,_q->alpha,xf,_q->r+1); // compute error _q->E[i] = _q->W[i] * (_q->D[i] - H); } return LIQUID_OK; } // search error curve for r+1 extremal indices // TODO : return number of values which have changed (stopping criteria) int firdespm_iext_search(firdespm _q) { unsigned int i; // found extremal frequency indices unsigned int nmax = 2*_q->r + 2*_q->num_bands; // max number of extremals unsigned int found_iext[nmax]; unsigned int num_found=0; #if 0 // check for extremum at f=0 if ( fabs(_q->E[0]) > fabs(_q->E[1]) ) found_iext[num_found++] = 0; #else // force f=0 into candidate set found_iext[num_found++] = 0; #if LIQUID_FIRDESPM_DEBUG_PRINT printf("num_found : %4u [%4u / %4u]\n", num_found, 0, _q->grid_size); #endif #endif // search inside grid for (i=1; i<_q->grid_size-1; i++) { if ( ((_q->E[i]>=0.0) && (_q->E[i-1]<=_q->E[i]) && (_q->E[i+1]<=_q->E[i]) ) || ((_q->E[i]< 0.0) && (_q->E[i-1]>=_q->E[i]) && (_q->E[i+1]>=_q->E[i]) ) ) { //assert(num_found < nmax); if (num_found < nmax) found_iext[num_found++] = i; #if LIQUID_FIRDESPM_DEBUG_PRINT printf("num_found : %4u [%4u / %4u]\n", num_found, i, _q->grid_size); #endif } } #if 0 // check for extremum at f=0.5 if ( fabs(_q->E[_q->grid_size-1]) > fabs(_q->E[_q->grid_size-2]) ) found_iext[num_found++] = _q->grid_size-1; #else // force f=0.5 into candidate set //assert(num_found < nmax); if (num_found < nmax) found_iext[num_found++] = _q->grid_size-1; //printf("num_found : %4u [%4u / %4u]\n", num_found, _q->grid_size-1, _q->grid_size); #endif //printf("r+1 = %4u, num_found = %4u\n", _q->r+1, num_found); if (num_found < _q->r+1) { // too few extremal frequencies found. Theoretically, this // should never happen as the Chebyshev alternation theorem // guarantees at least r+1 extrema, however due to finite // machine precision, interpolation can be imprecise _q->num_exchanges = 0; return 0; //return liquid_error(LIQUID_EINT,"firdespm_iext_search(), too few extrema found (expected %u, found %u); returning prematurely", //_q->r+1, num_found); } assert(num_found <= nmax); // search extrema and eliminate smallest unsigned int imin=0; // index of found_iext where _E is a minimum extreme unsigned int sign=0; // sign of error unsigned int num_extra = num_found - _q->r - 1; // number of extra extremal frequencies unsigned int alternating_sign; #if LIQUID_FIRDESPM_DEBUG_PRINT for (i=0; i<_q->r+1; i++) printf("iext[%4u] = %4u : %16.8e\n", i, found_iext[i], _q->E[found_iext[i]]); #endif while (num_extra) { // evaluate sign of first extrema sign = _q->E[found_iext[0]] > 0.0; // imin = 0; alternating_sign = 1; for (i=1; iE[found_iext[i]]) < fabs(_q->E[found_iext[imin]]) ) imin = i; if ( sign && _q->E[found_iext[i]] < 0.0 ) { sign = 0; } else if ( !sign && _q->E[found_iext[i]] >= 0.0 ) { sign = 1; } else { // found two extrema with non-alternating sign; delete // the smaller of the two if ( fabs(_q->E[found_iext[i]]) < fabs(_q->E[found_iext[i-1]]) ) imin = i; else imin = i-1; alternating_sign = 0; break; } } //printf(" imin : %3u : %12.4e;\n", imin, _q->E[found_iext[imin]]); // if ( alternating_sign && num_extra==1) { //imin = (fabs(_q->E[found_iext[0]]) > fabs(_q->E[found_iext[num_extra-1]])) ? 0 : num_extra-1; if (fabs(_q->E[found_iext[0]]) < fabs(_q->E[found_iext[num_found-1]])) imin = 0; else imin = num_found-1; } // Delete value in 'found_iext' at 'index imin'. This // is equivalent to shifing all values left one position // starting at index imin+1 //printf("deleting found_iext[%3u] = %3u\n", imin, found_iext[imin]); #if 0 memmove( &found_iext[imin], &found_iext[imin+1], (num_found-imin)*sizeof(unsigned int)); #else // equivalent code: for (i=imin; inum_exchanges=0; for (i=0; i<_q->r+1; i++) _q->num_exchanges += _q->iext[i] == found_iext[i] ? 0 : 1; // copy new values memmove(_q->iext, found_iext, (_q->r+1)*sizeof(unsigned int)); #if LIQUID_FIRDESPM_DEBUG_PRINT for (i=0; i<_q->r+1; i++) printf("iext_new[%4u] = %4u : %16.8e\n", i, found_iext[i], _q->E[found_iext[i]]); #endif return LIQUID_OK; } // evaluates result to determine if Remez exchange algorithm // has converged int firdespm_is_search_complete(firdespm _q) { // if no extremal frequencies have been exchanged, Remez // algorithm has converged if (_q->num_exchanges == 0) return 1; unsigned int i; double tol = 1e-3f; double e=0.0; double emin=0.0; double emax=0.0; for (i=0; i<_q->r+1; i++) { e = fabs(_q->E[_q->iext[i]]); if (i==0 || e < emin) emin = e; if (i==0 || e > emax) emax = e; } #if LIQUID_FIRDESPM_DEBUG_PRINT printf("emin : %16.8e, emax : %16.8e, metric : %16.8e\n", emin, emax, (emax-emin)/emax); #endif return (emax-emin) / emax < tol ? 1 : 0; } // compute filter taps (coefficients) from result int firdespm_compute_taps(firdespm _q, float * _h) { unsigned int i; // re-generate interpolator and compute coefficients // for best cosine approximation firdespm_compute_interp(_q); // evaluate Lagrange polynomial on evenly spaced points unsigned int p = _q->r - _q->s + 1; double G[p]; for (i=0; ih_len); double xf = cos(2*M_PI*f); double cf = poly_val_lagrange_barycentric(_q->x,_q->c,_q->alpha,xf,_q->r+1); double g=1.0; if (_q->btype == LIQUID_FIRDESPM_BANDPASS && _q->s==1) { // odd filter length, even symmetry g = 1.0; } else if (_q->btype == LIQUID_FIRDESPM_BANDPASS && _q->s==0) { // even filter length, even symmetry g = cos(M_PI * i / _q->h_len); } else if (_q->btype != LIQUID_FIRDESPM_BANDPASS && _q->s==1) { // odd filter length, odd symmetry } else if (_q->btype != LIQUID_FIRDESPM_BANDPASS && _q->s==0) { // even filter length, odd symmetry } G[i] = cf * g; //printf("G(%3u) = %12.4e (cf = %12.8f, f=%12.8f, c = %12.8f);\n", i+1, G[i], cf, f, g); } // compute inverse DFT (slow method), performing // transformation here for different filter types // TODO : flesh out computation for other filter types unsigned int j; if (_q->btype == LIQUID_FIRDESPM_BANDPASS) { // odd filter length, even symmetry for (i=0; i<_q->h_len; i++) { double v = G[0]; double f = ((double)i - (double)(p-1) + 0.5*(1-_q->s)) / (double)(_q->h_len); for (j=1; j<_q->r; j++) v += 2.0 * G[j] * cos(2*M_PI*f*j); _h[i] = v / (double)(_q->h_len); } } else if (_q->btype != LIQUID_FIRDESPM_BANDPASS && _q->s==1) { // odd filter length, odd symmetry return liquid_error(LIQUID_EINT,"firdespm_compute_taps(), filter configuration not yet supported"); } else if (_q->btype != LIQUID_FIRDESPM_BANDPASS && _q->s==0) { // even filter length, odd symmetry return liquid_error(LIQUID_EINT,"firdespm_compute_taps(), filter configuration not yet supported"); } #if LIQUID_FIRDESPM_DEBUG_PRINT printf("\n"); for (i=0; i<_q->h_len; i++) printf("h(%3u) = %12.8f;\n", i+1, _h[i]); #endif return LIQUID_OK; } #if LIQUID_FIRDESPM_DEBUG int firdespm_output_debug_file(firdespm _q) { FILE * fid = fopen(LIQUID_FIRDESPM_DEBUG_FILENAME,"w"); fprintf(fid,"%% %s : auto-generated file\n", LIQUID_FIRDESPM_DEBUG_FILENAME); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); unsigned int i; for (i=0; i<_q->grid_size; i++) { fprintf(fid,"F(%4u) = %16.8e;\n", i+1, _q->F[i]); fprintf(fid,"D(%4u) = %16.8e;\n", i+1, _q->D[i]); fprintf(fid,"W(%4u) = %16.8e;\n", i+1, _q->W[i]); fprintf(fid,"E(%4u) = %16.8e;\n", i+1, _q->E[i]); } for (i=0; i<_q->r+1; i++) { fprintf(fid,"iext(%4u) = %u;\n", i+1, _q->iext[i]+1); } fprintf(fid,"figure;\n"); fprintf(fid,"plot(F,E,'-', F(iext),E(iext),'x');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('frequency');\n"); fprintf(fid,"ylabel('error');\n"); // evaluate poly unsigned int n=1024; for (i=0; ix,_q->c,_q->alpha,x,_q->r+1); fprintf(fid,"f(%4u) = %20.12e; H(%4u) = %20.12e;\n", i+1, f, i+1, c); } fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,H,'-', F(iext),D(iext)-E(iext),'x');\n"); //fprintf(fid,"plot(f,20*log10(abs(H)),'-', F(iext),20*log10(abs(D(iext)-E(iext))),'x');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"xlabel('frequency');\n"); fprintf(fid,"ylabel('filter response');\n"); fprintf(fid,"rho = %20.12e;\n", _q->rho); fclose(fid); printf("internal debugging results written to %s.\n", LIQUID_FIRDESPM_DEBUG_FILENAME); return LIQUID_OK; } #endif #if 0 // design halfband filter using Parks-McClellan algorithm given the // filter length and desired transition band int liquid_firdespm_halfband_ft(unsigned int _m, float _ft, float * _h) { liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; unsigned int h_len = 4*_m + 1; unsigned int num_bands = 2; float f0 = 0.25f - 0.5f*_ft; float f1 = 0.25f + 0.5f*_ft; float bands[4] = {0.0f, f0, f1, 0.5f}; float des[2] = {1.0f, 0.0f}; float weights[2] = {1.0f, 1.0f}; // best with {1, 1} liquid_firdespm_wtype wtype[2] = { // best with {flat, flat} LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT,}; // design filter firdespm_run(h_len,num_bands,bands,des,weights,wtype,btype,_h); #if 0 // ensure values at odd indices are 0 (excepting center value) unsigned int i; for (i=0; i<_m; i++) { _h[ 2*i] = 0; _h[h_len-2*i-1] = 0; } #endif return LIQUID_OK; } #endif liquid-dsp-1.7.0/src/filter/src/firdespm_halfband.c000066400000000000000000000120531474751757600222610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "liquid.h" // structured data type struct firdespm_halfband_s { // top-level filter design parameters unsigned int m; // filter semi-length unsigned int h_len; // filter length, 4*m+1 float ft; // desired transition band float * h; // resulting filter coefficients // utility calculation unsigned int nfft; // transform size for analysis float complex * buf_time; // time buffer float complex * buf_freq; // frequency buffer fftplan fft; // transform object unsigned int n; // number of points to evaluate }; float firdespm_halfband_utility(float _gamma, void * _userdata) { // type-cast input structure as pointer struct firdespm_halfband_s * q = (struct firdespm_halfband_s*)_userdata; // design filter float f0 = 0.25f - 0.5f*q->ft*_gamma; float f1 = 0.25f + 0.5f*q->ft; float bands[4] = {0.00f, f0, f1, 0.50f}; float des[2] = {1.0f, 0.0f}; float weights[2] = {1.0f, 1.0f}; // best with {1, 1} liquid_firdespm_wtype wtype[2] = { // best with {flat, flat} LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT,}; firdespm_run(q->h_len, 2, bands, des, weights, wtype, LIQUID_FIRDESPM_BANDPASS, q->h); // compute utility; copy ideal non-zero coefficients and compute transform unsigned int i; // force zeros for even coefficients for (i=0; im; i++) { q->h[ 2*i] = 0; q->h[q->h_len-2*i-1] = 0; } // copy coefficients to input buffer for (i=0; infft; i++) { q->buf_time[i] = i < q->h_len ? q->h[i] : 0.0f; } // compute transform fft_execute(q->fft); // compute metric: power in stop-band float u = 0.0f; for (i=0; in; i++) { unsigned int idx = q->nfft/2 - i; float u_test = cabsf(q->buf_freq[idx]); //printf(" %3u : %12.8f : %12.3f\n", i, (float)(idx) / (float)(q->nfft), 20*log10f(u_test)); u += u_test * u_test; } // return utility in dB return 10*log10f(u / (float)(q->n)); } // perform search to find optimal coefficients given transition band int liquid_firdespm_halfband_ft(unsigned int _m, float _ft, float * _h) { // create and initialize object struct firdespm_halfband_s q; q.m = _m; q.h_len = 4*_m+1; q.ft = _ft; q.h = (float*)malloc(q.h_len*sizeof(float)); // initialize values for utility calculation q.nfft = 1200; while (q.nfft < 20*q.m) q.nfft <<= 1; q.buf_time = (float complex*) fft_malloc(q.nfft*sizeof(float complex)); q.buf_freq = (float complex*) fft_malloc(q.nfft*sizeof(float complex)); q.fft = fft_create_plan(q.nfft, q.buf_time, q.buf_freq, LIQUID_FFT_FORWARD, 0); // compute indices of stop-band analysis q.n = (unsigned int)(q.nfft * (0.25f - 0.5f*_ft)); //printf("firdespm.halfband, m=%u, ft=%.3f, n=%u, nfft=%u, n=%u\n", // q.m, q.ft, q.h_len, q.nfft, q.n); // create and run search qs1dsearch optim = qs1dsearch_create(firdespm_halfband_utility, &q, LIQUID_OPTIM_MINIMIZE); qs1dsearch_init_bounds(optim, 1.0f, 0.9f); unsigned int i; for (i=0; i<32; i++) { qs1dsearch_step (optim); //qs1dsearch_print(optim); } qs1dsearch_destroy(optim); // copy optimal coefficients memmove(_h, q.h, q.h_len*sizeof(float)); // destroy objects free(q.h); fft_destroy_plan(q.fft); fft_free(q.buf_time); fft_free(q.buf_freq); // return LIQUID_OK; } // perform search to find optimal coefficients given stop-band suppression int liquid_firdespm_halfband_as(unsigned int _m, float _as, float * _h) { // estimate transition band given other parameters float ft = estimate_req_filter_df(_as, 4*_m+1); // return filter design return liquid_firdespm_halfband_ft(_m, ft, _h); } liquid-dsp-1.7.0/src/filter/src/firfarrow.proto.c000066400000000000000000000247401474751757600220020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfarrow.c // // Finite impulse response Farrow filter // #include #include #include #include #define FIRFARROW_USE_DOTPROD 1 #define FIRFARROW_DEBUG 0 // defined: // FIRFARROW() name-mangling macro // T coefficients type // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro int FIRFARROW(_genpoly)(FIRFARROW() _q); struct FIRFARROW(_s) { TC * h; // filter coefficients unsigned int h_len; // filter length float fc; // filter cutoff float as; // stop-band attenuation [dB] unsigned int Q; // polynomial order float mu; // fractional sample delay float * P; // polynomail coefficients matrix [ h_len x Q+1 ] float gamma; // inverse of DC response (normalization factor) #if FIRFARROW_USE_DOTPROD WINDOW() w; #else TI * v; unsigned int v_index; #endif }; // create firfarrow object // _h_len : filter length // _p : polynomial order // _fc : filter cutoff frequency // _as : stopband attenuation [dB] FIRFARROW() FIRFARROW(_create)(unsigned int _h_len, unsigned int _p, float _fc, float _as) { // validate input if (_h_len < 2) return liquid_error_config("firfarrow_%s_create(), filter length must be > 2", EXTENSION_FULL); if (_p < 1) return liquid_error_config("firfarrow_%s_create(), polynomial order must be at least 1", EXTENSION_FULL); if (_fc < 0.0f || _fc > 0.5f) return liquid_error_config("firfarrow_%s_create(), filter cutoff must be in [0,0.5]", EXTENSION_FULL); if (_as < 0.0f) return liquid_error_config("firfarrow_%s_create(), filter stop-band attenuation must be greater than zero", EXTENSION_FULL); // create main object FIRFARROW() q = (FIRFARROW()) malloc(sizeof(struct FIRFARROW(_s))); // set internal properties q->h_len = _h_len; // filter length q->Q = _p; // polynomial order q->as = _as; // filter stop-band attenuation q->fc = _fc; // filter cutoff frequency // allocate memory for filter coefficients q->h = (TC *) malloc((q->h_len)*sizeof(TC)); #if FIRFARROW_USE_DOTPROD q->w = WINDOW(_create)(q->h_len); #else q->v = malloc((q->h_len)*sizeof(TI)); #endif // allocate memory for polynomial matrix [ h_len x Q+1 ] q->P = (float*) malloc((q->h_len)*(q->Q+1)*sizeof(float)); // reset the filter object FIRFARROW(_reset)(q); // generate polynomials FIRFARROW(_genpoly)(q); // set nominal delay of 0 FIRFARROW(_set_delay)(q,0.0f); // return main object return q; } // destroy firfarrow object, freeing all internal memory int FIRFARROW(_destroy)(FIRFARROW() _q) { #if FIRFARROW_USE_DOTPROD WINDOW(_destroy)(_q->w); #else free(_q->v); #endif free(_q->h); // free the filter coefficients array free(_q->P); // free the polynomial matrix // free main object free(_q); return LIQUID_OK; } // print firfarrow object's internal properties int FIRFARROW(_print)(FIRFARROW() _q) { printf("\n", _q->h_len, _q->Q); #if 0 printf("polynomial coefficients:\n"); // print coefficients unsigned int i, j, n=0; for (i=0; i<_q->h_len; i++) { printf(" %3u : ", i); for (j=0; j<_q->Q+1; j++) printf("%12.4e ", _q->P[n++]); printf("\n"); } printf("filter coefficients (mu=%8.4f):\n", _q->mu); n = _q->h_len; for (i=0; iw); #else unsigned int i; for (i=0; i<_q->h_len; i++) _q->v[i] = 0; _q->v_index = 0; return LIQUID_OK; #endif } // push sample into firfarrow object // _q : firfarrow object // _x : input sample int FIRFARROW(_push)(FIRFARROW() _q, TI _x) { #if FIRFARROW_USE_DOTPROD return WINDOW(_push)(_q->w, _x); #else _q->v[ _q->v_index ] = _x; (_q->v_index)++; _q->v_index = (_q->v_index) % (_q->h_len); return LIQUID_OK; #endif } // set fractional delay of firfarrow object // _q : firfarrow object // _mu : fractional sample delay int FIRFARROW(_set_delay)(FIRFARROW() _q, float _mu) { // validate input if (_mu < -1.0f || _mu > 1.0f) { return liquid_error(LIQUID_EIVAL,"firfarrow_%s_create(), delay must be in [-1,1]\n", EXTENSION_FULL); } unsigned int i, n=0; for (i=0; i<_q->h_len; i++) { // compute filter tap from polynomial using negative // value for _mu _q->h[i] = POLY(_val)(_q->P+n, _q->Q, -_mu); // normalize filter by inverse of DC response _q->h[i] *= _q->gamma; n += _q->Q+1; //printf(" h[%3u] = %12.8f\n", i, _q->h[i]); } return LIQUID_OK; } // execute firfarrow internal dot product // _q : firfarrow object // _y : output sample pointer int FIRFARROW(_execute)(FIRFARROW() _q, TO * _y) { #if FIRFARROW_USE_DOTPROD TI *r; WINDOW(_read)(_q->w, &r); DOTPROD(_run4)(_q->h, r, _q->h_len, _y); #else TO y = 0; unsigned int i; for (i=0; i<_q->h_len; i++) y += _q->v[ (i+_q->v_index)%(_q->h_len) ] * _q->h[i]; *_y = y; #endif return LIQUID_OK; } // compute firfarrow filter on block of samples; the input // and output arrays may have the same pointer // _q : firfarrow object // _x : input array [size: _n x 1] // _n : input, output array size // _y : output array [size: _n x 1] int FIRFARROW(_execute_block)(FIRFARROW() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // push input sample FIRFARROW(_push)(_q, _x[i]); // compute output FIRFARROW(_execute)(_q, &_y[i]); } return LIQUID_OK; } // get length of firfarrow object (number of filter taps) unsigned int FIRFARROW(_get_length)(FIRFARROW() _q) { return _q->h_len; } // get coefficients of firfarrow object // _q : firfarrow object // _h : output coefficients pointer int FIRFARROW(_get_coefficients)(FIRFARROW() _q, TC * _h) { memmove(_h, _q->h, (_q->h_len)*sizeof(TC)); return LIQUID_OK; } // compute complex frequency response // _q : filter object // _fc : frequency // _H : output frequency response int FIRFARROW(_freqresponse)(FIRFARROW() _q, float _fc, float complex * _H) { unsigned int i; float complex H = 0.0f; for (i=0; i<_q->h_len; i++) H += _q->h[i] * cexpf(_Complex_I*2*M_PI*_fc*i); // set return value *_H = H; return LIQUID_OK; } // compute group delay [samples] // _q : filter object // _fc : frequency float FIRFARROW(_groupdelay)(FIRFARROW() _q, float _fc) { // copy coefficients to be in correct order float h[_q->h_len]; unsigned int i; unsigned int n = _q->h_len; for (i=0; ih[i]); return fir_group_delay(h, n, _fc); } // // internal // // generate polynomials to represent filter coefficients int FIRFARROW(_genpoly)(FIRFARROW() _q) { // TODO : shy away from 'float' and use 'TC' types unsigned int i, j, n=0; float x, mu, h0, h1; float mu_vect[_q->Q+1]; float hp_vect[_q->Q+1]; float p[_q->Q+1]; float beta = kaiser_beta_As(_q->as); for (i=0; i<_q->h_len; i++) { #if FIRFARROW_DEBUG printf("i : %3u / %3u\n", i, _q->h_len); #endif x = (float)(i) - (float)(_q->h_len-1)/2.0f; for (j=0; j<=_q->Q; j++) { mu = ((float)j - (float)_q->Q)/((float)_q->Q) + 0.5f; h0 = sincf(2.0f*(_q->fc)*(x + mu)); h1 = liquid_kaiser(i,_q->h_len,beta); #if FIRFARROW_DEBUG printf(" %3u : x=%12.8f, mu=%12.8f, h0=%12.8f, h1=%12.8f, hp=%12.8f\n", j, x, mu, h0, h1, h0*h1); #endif mu_vect[j] = mu; hp_vect[j] = h0*h1; } POLY(_fit)(mu_vect,hp_vect,_q->Q+1,p,_q->Q+1); #if FIRFARROW_DEBUG printf(" polynomial : "); for (j=0; j<=_q->Q; j++) printf("%8.4f,", p[j]); printf("\n"); #endif // copy coefficients to internal matrix memmove(_q->P+n, p, (_q->Q+1)*sizeof(float)); n += _q->Q+1; } #if FIRFARROW_DEBUG // print coefficients n=0; for (i=0; i<_q->h_len; i++) { printf("%3u : ", i); for (j=0; j<_q->Q+1; j++) printf("%12.4e ", _q->P[n++]); printf("\n"); } #endif // normalize DC gain _q->gamma = 1.0f; // initialize gamma to 1 FIRFARROW(_set_delay)(_q,0.0f); // compute filter taps with zero delay _q->gamma = 0.0f; // clear gamma for (i=0; i<_q->h_len; i++) // compute DC response _q->gamma += _q->h[i]; _q->gamma = 1.0f / (_q->gamma); // invert result return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/firfilt.proto.c000066400000000000000000000372501474751757600214400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt : finite impulse response (FIR) filter // #include #include #include // defined: // FIRFILT() name-mangling macro // T coefficients type // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro // NOTE: using the window is about 27% slower, but fixes a valgrind issue #define LIQUID_FIRFILT_USE_WINDOW (1) // firfilt object structure struct FIRFILT(_s) { TC * h; // filter coefficients array [size; h_len x 1] unsigned int h_len; // filter length #if LIQUID_FIRFILT_USE_WINDOW // use window object for internal buffer WINDOW() w; #else // use array as internal buffer (faster) TI * w; // internal buffer object unsigned int w_len; // window length unsigned int w_mask; // window index mask unsigned int w_index; // window read index #endif DOTPROD() dp; // dot product object TC scale; // output scaling factor }; // create firfilt object // _h : coefficients (filter taps) [size: _n x 1] // _n : filter length FIRFILT() FIRFILT(_create)(TC * _h, unsigned int _n) { // validate input if (_n == 0) return liquid_error_config("firfilt_%s_create(), filter length must be greater than zero", EXTENSION_FULL); // create filter object and initialize FIRFILT() q = (FIRFILT()) malloc(sizeof(struct FIRFILT(_s))); q->h_len = _n; q->h = (TC *) malloc((q->h_len)*sizeof(TC)); #if LIQUID_FIRFILT_USE_WINDOW // create window (internal buffer) q->w = WINDOW(_create)(q->h_len); #else // initialize array for buffering q->w_len = 1<h_len); // effectively 2^{floor(log2(len))+1} q->w_mask = q->w_len - 1; q->w = (TI *) malloc((q->w_len + q->h_len + 1)*sizeof(TI)); q->w_index = 0; #endif // move coefficients memmove(q->h, _h, (q->h_len)*sizeof(TC)); // create dot product object with coefficients in reverse order q->dp = DOTPROD(_create_rev)(q->h, q->h_len); // set default scaling q->scale = 1; // reset filter state (clear buffer) FIRFILT(_reset)(q); return q; } // create filter using Kaiser-Bessel windowed sinc method // _n : filter length, _n > 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 // _mu : fractional sample offset, -0.5 < _mu < 0.5 FIRFILT() FIRFILT(_create_kaiser)(unsigned int _n, float _fc, float _as, float _mu) { // compute temporary array for holding coefficients float hf[_n]; if (liquid_firdes_kaiser(_n, _fc, _as, _mu, hf) != LIQUID_OK) return liquid_error_config("firfilt_%s_create_kaiser(), invalid config", EXTENSION_FULL); // copy coefficients to type-specific array TC h[_n]; unsigned int i; for (i=0; i<_n; i++) h[i] = (TC) hf[i]; // return FIRFILT(_create)(h, _n); } // create from square-root Nyquist prototype // _type : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : nominal samples/symbol, _k > 1 // _m : filter delay [symbols], _m > 0 // _beta : rolloff factor, 0 < beta <= 1 // _mu : fractional sample offset,-0.5 < _mu < 0.5 FIRFILT() FIRFILT(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, float _mu) { // generate square-root Nyquist filter unsigned int h_len = 2*_k*_m + 1; float hf[h_len]; if (liquid_firdes_prototype(_type,_k,_m,_beta,_mu,hf) != LIQUID_OK) return liquid_error_config("firfilt_%s_create_rnyquist(), invalid configuration", EXTENSION_FULL); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC hc[h_len]; for (i=0; i 0 // _fc : cutoff frequency, 0 < _fc < 0.5 // _as : stop-band attenuation [dB], _as > 0 FIRFILT() FIRFILT(_create_firdespm)(unsigned int _h_len, float _fc, float _as) { // generate square-root Nyquist filter float hf[_h_len]; if (firdespm_lowpass(_h_len,_fc,_as,0,hf) != LIQUID_OK) return liquid_error_config("firfilt_%s_create_firdespm(), invalid config", EXTENSION_FULL); // copy coefficients to type-specific array (e.g. float complex) // and scale by filter bandwidth to be consistent with other lowpass prototypes unsigned int i; TC hc[_h_len]; for (i=0; i<_h_len; i++) hc[i] = hf[i] * 0.5f / _fc; // return filter object and return return FIRFILT(_create)(hc, _h_len); } // create rectangular filter prototype FIRFILT() FIRFILT(_create_rect)(unsigned int _n) { // validate input if (_n == 0 || _n > 1024) return liquid_error_config("firfilt_%s_create_rect(), filter length must be in [1,1024]", EXTENSION_FULL); // create float array coefficients float hf[_n]; unsigned int i; for (i=0; i<_n; i++) hf[i] = 1.0f; // copy coefficients to type-specific array TC h[_n]; for (i=0; i<_n; i++) h[i] = (TC) hf[i]; // return filter object and return return FIRFILT(_create)(h, _n); } // create DC blocking filter FIRFILT() FIRFILT(_create_dc_blocker)(unsigned int _m, float _as) { // create float array coefficients and design filter unsigned int h_len = 2*_m+1; float hf[h_len]; if (liquid_firdes_notch(_m, 0, _as, hf) != LIQUID_OK) return liquid_error_config("firfilt_%s_create_dc_blocker(), invalid config",EXTENSION_FULL); // copy coefficients to type-specific array TC h[h_len]; unsigned int i; for (i=0; ih_len) { // reallocate memory _q->h_len = _n; _q->h = (TC*) realloc(_q->h, (_q->h_len)*sizeof(TC)); #if LIQUID_FIRFILT_USE_WINDOW // recreate window object, preserving internal state _q->w = WINDOW(_recreate)(_q->w, _q->h_len); #else // free old array free(_q->w); // initialize array for buffering _q->w_len = 1<h_len); // effectively 2^{floor(log2(len))+1} _q->w_mask = _q->w_len - 1; // FIXME: valgrind is complaining about an uninitialized variable in the following malloc line _q->w = (TI *) malloc((_q->w_len + _q->h_len + 1)*sizeof(TI)); _q->w_index = 0; #endif } // load filter in reverse order for (i=_n; i>0; i--) _q->h[i-1] = _h[_n-i]; // re-create internal dot product object _q->dp = DOTPROD(_recreate)(_q->dp, _q->h, _q->h_len); return _q; } // copy object FIRFILT() FIRFILT(_copy)(FIRFILT() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters FIRFILT() q_copy = (FIRFILT()) malloc(sizeof(struct FIRFILT(_s))); memmove(q_copy, q_orig, sizeof(struct FIRFILT(_s))); // copy filter coefficients q_copy->h = (TC *) liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(TC)); #if LIQUID_FIRFILT_USE_WINDOW // copy window q_copy->w = WINDOW(_copy)(q_orig->w); #else // initialize array for buffering q_copy->w = (TI *) liquid_malloc_copy(q_orig->w, q_orig->w_len, sizeof(TI)); #endif // copy dot product object and return q_copy->dp = DOTPROD(_copy)(q_orig->dp); return q_copy; } // destroy firfilt object int FIRFILT(_destroy)(FIRFILT() _q) { #if LIQUID_FIRFILT_USE_WINDOW WINDOW(_destroy)(_q->w); #else free(_q->w); #endif DOTPROD(_destroy)(_q->dp); free(_q->h); free(_q); return LIQUID_OK; } // reset internal state of filter object int FIRFILT(_reset)(FIRFILT() _q) { #if LIQUID_FIRFILT_USE_WINDOW return WINDOW(_reset)(_q->w); #else unsigned int i; for (i=0; i<_q->w_len; i++) _q->w[i] = 0.0; _q->w_index = 0; return LIQUID_OK; #endif } // print filter object internals (taps, buffer) int FIRFILT(_print)(FIRFILT() _q) { printf("h_len); printf(", scale="); PRINTVAL_TC(_q->scale,%12.8f); printf(">\n"); return LIQUID_OK; } // set output scaling for filter int FIRFILT(_set_scale)(FIRFILT() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // get output scaling for filter int FIRFILT(_get_scale)(FIRFILT() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // push sample into filter object's internal buffer // _q : filter object // _x : input sample int FIRFILT(_push)(FIRFILT() _q, TI _x) { #if LIQUID_FIRFILT_USE_WINDOW return WINDOW(_push)(_q->w, _x); #else // increment index _q->w_index++; // wrap around pointer _q->w_index &= _q->w_mask; // if pointer wraps around, copy excess memory if (_q->w_index == 0) memmove(_q->w, _q->w + _q->w_len, (_q->h_len)*sizeof(TI)); // append value to end of buffer _q->w[_q->w_index + _q->h_len - 1] = _x; return LIQUID_OK; #endif } // Write block of samples into filter object's internal buffer // _q : filter object // _x : buffer of input samples, [size: _n x 1] // _n : number of input samples int FIRFILT(_write)(FIRFILT() _q, TI * _x, unsigned int _n) { #if LIQUID_FIRFILT_USE_WINDOW return WINDOW(_write)(_q->w, _x, _n); #else // TODO: be smarter about this unsigned int i; for (i=0; i<_n; i++) { int rc = FIRFILT(_push)(_q, _x[i]); if (rc != LIQUID_OK) return rc; } return LIQUID_OK; #endif } // compute output sample (dot product between internal // filter coefficients and internal buffer) // _q : filter object // _y : output sample pointer int FIRFILT(_execute)(FIRFILT() _q, TO * _y) { // read buffer (retrieve pointer to aligned memory array) #if LIQUID_FIRFILT_USE_WINDOW TI *r; WINDOW(_read)(_q->w, &r); #else TI *r = _q->w + _q->w_index; #endif // execute dot product DOTPROD(_execute)(_q->dp, r, _y); // apply scaling factor *_y *= _q->scale; return LIQUID_OK; } // run on single sample int FIRFILT(_execute_one)(FIRFILT() _q, TI _x, TO * _y) { FIRFILT(_push)(_q, _x); return FIRFILT(_execute)(_q, _y); } // execute the filter on a block of input samples; the // input and output buffers may be the same // _q : filter object // _x : pointer to input array [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array [size: _n x 1] int FIRFILT(_execute_block)(FIRFILT() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // push sample into filter FIRFILT(_push)(_q, _x[i]); // compute output sample FIRFILT(_execute)(_q, &_y[i]); } return LIQUID_OK; } // get filter length unsigned int FIRFILT(_get_length)(FIRFILT() _q) { return _q->h_len; } // Get pointer to coefficients array const TC * FIRFILT(_get_coefficients)(FIRFILT() _q) { return (const TC *) _q->h; } // Copy internal coefficients to external buffer int FIRFILT(_copy_coefficients)(FIRFILT() _q, TC * _h) { // internal coefficients are stored in normal order memmove(_h, _q->h, (_q->h_len)*sizeof(TC)); return LIQUID_OK; } // compute complex frequency response // _q : filter object // _fc : frequency // _H : output frequency response int FIRFILT(_freqresponse)(FIRFILT() _q, float _fc, float complex * _H) { #if TC_COMPLEX==0 int rc = liquid_freqrespf(_q->h, _q->h_len, _fc, _H); #elif TC_COMPLEX==1 int rc = liquid_freqrespcf(_q->h, _q->h_len, _fc, _H); #else # error("invalid complex type for coefficients") #endif // apply scaling *_H *= _q->scale; return rc; } // compute group delay in samples // _q : filter object // _fc : frequency float FIRFILT(_groupdelay)(FIRFILT() _q, float _fc) { // copy coefficients float h[_q->h_len]; unsigned int i; for (i=0; i<_q->h_len; i++) h[i] = crealf(_q->h[i]); return fir_group_delay(h, _q->h_len, _fc); } liquid-dsp-1.7.0/src/filter/src/firhilb.proto.c000066400000000000000000000260321474751757600214140ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // finite impulse response (FIR) Hilbert transform #include #include #include #include struct FIRHILB(_s) { T * h; // filter coefficients T complex * hc; // filter coefficients (complex) unsigned int h_len; // length of filter float as; // filter stop-band attenuation [dB] unsigned int m; // filter semi-length, h_len = 4*m+1 // quadrature filter component T * hq; // quadrature filter coefficients unsigned int hq_len; // quadrature filter length (2*m) // input buffers WINDOW() w0; // input buffer (even samples) WINDOW() w1; // input buffer (odd samples) // additional buffers needed exclusively for real-to-complex filter operations WINDOW() w2; WINDOW() w3; // vector dot product DOTPROD() dpq; // regular real-to-complex/complex-to-real operation unsigned int toggle; }; // create firhilb object // _m : filter semi-length (delay: 2*m+1) // _as : stop-band attenuation [dB] FIRHILB() FIRHILB(_create)(unsigned int _m, float _as) { // validate firhilb inputs if (_m < 2) return liquid_error_config("firhilb_create(), filter semi-length (m) must be at least 2"); // allocate memory for main object FIRHILB() q = (FIRHILB()) malloc(sizeof(struct FIRHILB(_s))); q->m = _m; // filter semi-length q->as = fabsf(_as); // stop-band attenuation // set filter length and allocate memory for coefficients q->h_len = 4*(q->m) + 1; q->h = (T *) malloc((q->h_len)*sizeof(T)); q->hc = (T complex *) malloc((q->h_len)*sizeof(T complex)); // allocate memory for quadrature filter component q->hq_len = 2*(q->m); q->hq = (T *) malloc((q->hq_len)*sizeof(T)); // compute filter coefficients for half-band filter liquid_firdes_kaiser(q->h_len, 0.25f, q->as, 0.0f, q->h); // alternate sign of non-zero elements unsigned int i; for (i=0; ih_len; i++) { float t = (float)i - (float)(q->h_len-1)/2.0f; q->hc[i] = q->h[i] * cexpf(_Complex_I*0.5f*M_PI*t); q->h[i] = cimagf(q->hc[i]); } // resample, reverse direction unsigned int j=0; for (i=1; ih_len; i+=2) q->hq[j++] = q->h[q->h_len - i - 1]; // create windows for upper and lower polyphase filter branches q->w0 = WINDOW(_create)(2*(q->m)); q->w1 = WINDOW(_create)(2*(q->m)); q->w2 = WINDOW(_create)(2*(q->m)); q->w3 = WINDOW(_create)(2*(q->m)); // create internal dot product object q->dpq = DOTPROD(_create)(q->hq, q->hq_len); // reset internal state and return object FIRHILB(_reset)(q); return q; } FIRHILB() FIRHILB(_copy)(FIRHILB() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firhilb%s_copy(), object cannot be NULL", EXTENSION_SHORT); // create filter object and copy base parameters FIRHILB() q_copy = (FIRHILB()) malloc(sizeof(struct FIRHILB(_s))); memmove(q_copy, q_orig, sizeof(struct FIRHILB(_s))); // copy filter coefficients q_copy->h = (T *) liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(T)); q_copy->hc = (T complex*) liquid_malloc_copy(q_orig->hc, q_orig->h_len, sizeof(T complex)); q_copy->hq = (T *) liquid_malloc_copy(q_orig->hq, q_orig->hq_len, sizeof(T)); // copy objects and return q_copy->w0 = WINDOW (_copy)(q_orig->w0 ); q_copy->w1 = WINDOW (_copy)(q_orig->w1 ); q_copy->w2 = WINDOW (_copy)(q_orig->w2 ); q_copy->w3 = WINDOW (_copy)(q_orig->w3 ); q_copy->dpq = DOTPROD(_copy)(q_orig->dpq); return q_copy; } // destroy firhilb object int FIRHILB(_destroy)(FIRHILB() _q) { // destroy window buffers WINDOW(_destroy)(_q->w0); WINDOW(_destroy)(_q->w1); WINDOW(_destroy)(_q->w2); WINDOW(_destroy)(_q->w3); // destroy internal dot product object DOTPROD(_destroy)(_q->dpq); // free coefficients arrays free(_q->h); free(_q->hc); free(_q->hq); // free main object memory free(_q); return LIQUID_OK; } // print firhilb object internals int FIRHILB(_print)(FIRHILB() _q) { printf("\n", EXTENSION_SHORT, _q->h_len); return LIQUID_OK; } // reset firhilb object internal state int FIRHILB(_reset)(FIRHILB() _q) { // clear window buffers WINDOW(_reset)(_q->w0); WINDOW(_reset)(_q->w1); WINDOW(_reset)(_q->w2); WINDOW(_reset)(_q->w3); // reset toggle flag _q->toggle = 0; return LIQUID_OK; } // execute Hilbert transform (real to complex) // _q : firhilb object // _x : real-valued input sample // _y : complex-valued output sample int FIRHILB(_r2c_execute)(FIRHILB() _q, T _x, T complex * _y) { T * r; // buffer read pointer T yi; // in-phase component T yq; // quadrature component if ( _q->toggle == 0 ) { // push sample into upper branch WINDOW(_push)(_q->w0, _x); // upper branch (delay) WINDOW(_index)(_q->w0, _q->m-1, &yi); // lower branch (filter) WINDOW(_read)(_q->w1, &r); // execute dotprod DOTPROD(_execute)(_q->dpq, r, &yq); } else { // push sample into lower branch WINDOW(_push)(_q->w1, _x); // upper branch (delay) WINDOW(_index)(_q->w1, _q->m-1, &yi); // lower branch (filter) WINDOW(_read)(_q->w0, &r); // execute dotprod DOTPROD(_execute)(_q->dpq, r, &yq); } // toggle flag _q->toggle = 1 - _q->toggle; // set return value *_y = yi + _Complex_I * yq; return LIQUID_OK; } // execute Hilbert transform (complex to real) // _q : firhilb object // _x : complex-valued input sample // _y0 : real-valued output sample, lower side-band retained // _y1 : real-valued output sample, upper side-band retained int FIRHILB(_c2r_execute)(FIRHILB() _q, T complex _x, T * _y0, T * _y1) { T * r; // buffer read pointer T yi; // T yq; // if (_q->toggle == 0) { // push samples into appropriate buffers WINDOW(_push)(_q->w0, crealf(_x)); WINDOW(_push)(_q->w1, cimagf(_x)); // compute delay branch WINDOW(_index)(_q->w0, _q->m-1, &yi); // compute filter branch WINDOW(_read)(_q->w3, &r); DOTPROD(_execute)(_q->dpq, r, &yq); } else { // push samples into appropriate buffers WINDOW(_push)(_q->w2, crealf(_x)); WINDOW(_push)(_q->w3, cimagf(_x)); // compute delay branch WINDOW(_index)(_q->w2, _q->m-1, &yi); // compute filter branch WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dpq, r, &yq); } // adjust state _q->toggle = 1 - _q->toggle; // set return value *_y0 = yi + yq; // lower side-band *_y1 = yi - yq; // upper side-band return LIQUID_OK; } // execute Hilbert transform decimator (real to complex) // _q : firhilb object // _x : real-valued input array [size: 2 x 1] // _y : complex-valued output sample int FIRHILB(_decim_execute)(FIRHILB() _q, T * _x, T complex * _y) { T * r; // buffer read pointer T yi; // in-phase component T yq; // quadrature component // compute quadrature component (filter branch) WINDOW(_push)(_q->w1, _x[0]); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dpq, r, &yq); // delay branch WINDOW(_push)(_q->w0, _x[1]); WINDOW(_index)(_q->w0, _q->m-1, &yi); // set return value T complex v = yi + _Complex_I * yq; *_y = _q->toggle ? -v : v; // toggle flag _q->toggle = 1 - _q->toggle; return LIQUID_OK; } // execute Hilbert transform decimator (real to complex) on // a block of samples // _q : Hilbert transform object // _x : real-valued input array [size: 2*_n x 1] // _n : number of *output* samples // _y : complex-valued output array [size: _n x 1] int FIRHILB(_decim_execute_block)(FIRHILB() _q, T * _x, unsigned int _n, T complex * _y) { unsigned int i; for (i=0; i<_n; i++) { FIRHILB(_decim_execute)(_q, &_x[2*i], &_y[i]); } return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) // _q : firhilb object // _y : complex-valued input sample // _x : real-valued output array [size: 2 x 1] int FIRHILB(_interp_execute)(FIRHILB() _q, T complex _x, T * _y) { T * r; // buffer read pointer // TODO macro for crealf, cimagf? T vi = _q->toggle ? -crealf(_x) : crealf(_x); T vq = _q->toggle ? -cimagf(_x) : cimagf(_x); // compute delay branch WINDOW(_push)(_q->w0, vq); WINDOW(_index)(_q->w0, _q->m-1, &_y[0]); // compute second branch (filter) WINDOW(_push)(_q->w1, vi); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dpq, r, &_y[1]); // toggle flag _q->toggle = 1 - _q->toggle; return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) // on a block of samples // _q : Hilbert transform object // _x : complex-valued input array [size: _n x 1] // _n : number of *input* samples // _y : real-valued output array [size: 2*_n x 1] int FIRHILB(_interp_execute_block)(FIRHILB() _q, T complex * _x, unsigned int _n, T * _y) { unsigned int i; for (i=0; i<_n; i++) { FIRHILB(_interp_execute)(_q, _x[i], &_y[2*i]); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/firinterp.proto.c000066400000000000000000000246301474751757600220010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // finite impulse response (FIR) interpolator #include #include #include struct FIRINTERP(_s) { TC * h; // prototype filter coefficients unsigned int h_len; // prototype filter length unsigned int h_sub_len; // sub-filter length unsigned int M; // interpolation factor FIRPFB() filterbank; // polyphase filterbank object }; // create interpolator // _interp : interpolation factor // _h : filter coefficients array [size: _h_len x 1] // _h_len : filter length FIRINTERP() FIRINTERP(_create)(unsigned int _interp, TC * _h, unsigned int _h_len) { // validate input if (_interp < 2) return liquid_error_config("firinterp_%s_create(), interp factor must be greater than 1", EXTENSION_FULL); if (_h_len < _interp) return liquid_error_config("firinterp_%s_create(), filter length cannot be less than interp factor", EXTENSION_FULL); // allocate main object memory and set internal parameters FIRINTERP() q = (FIRINTERP()) malloc(sizeof(struct FIRINTERP(_s))); q->M = _interp; q->h_len = _h_len; // compute sub-filter length q->h_sub_len=0; while (q->M * q->h_sub_len < _h_len) q->h_sub_len++; // compute effective filter length (pad end of prototype with zeros) q->h_len = q->M * q->h_sub_len; q->h = (TC*) malloc((q->h_len)*sizeof(TC)); // load filter coefficients in regular order, padding end with zeros unsigned int i; for (i=0; ih_len; i++) q->h[i] = i < _h_len ? _h[i] : 0.0f; // create polyphase filterbank q->filterbank = FIRPFB(_create)(q->M, q->h, q->h_len); // return interpolator object return q; } // create interpolator from Kaiser prototype // _interp : interpolation factor // _m : symbol delay // _as : stop-band attenuation [dB] FIRINTERP() FIRINTERP(_create_kaiser)(unsigned int _interp, unsigned int _m, float _as) { // validate input if (_interp < 2) return liquid_error_config("firinterp_%s_create_kaiser(), interp factor must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firinterp_%s_create_kaiser(), filter delay must be greater than 0", EXTENSION_FULL); if (_as < 0.0f) return liquid_error_config("firinterp_%s_create_kaiser(), stop-band attenuation must be positive", EXTENSION_FULL); // compute filter coefficients (floating point precision) unsigned int h_len = 2*_interp*_m + 1; float hf[h_len]; float fc = 0.5f / (float) (_interp); liquid_firdes_kaiser(h_len, fc, _as, 0.0f, hf); // copy coefficients to type-specific array (e.g. float complex) TC hc[h_len]; unsigned int i; for (i=0; i 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, _beta < 1 // _dt : fractional sample delay, _dt in (-1, 1) FIRINTERP() FIRINTERP(_create_prototype)(int _type, unsigned int _interp, unsigned int _m, float _beta, float _dt) { // validate input if (_interp < 2) return liquid_error_config("firinterp_%s_create_prototype(), interp factor must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firinterp_%s_create_prototype(), filter delay must be greater than 0", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("firinterp_%s_create_prototype(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); if (_dt < -1.0f || _dt > 1.0f) return liquid_error_config("firinterp_%s_create_prototype(), filter fractional sample delay must be in [-1,1]", EXTENSION_FULL); // generate Nyquist filter unsigned int h_len = 2*_interp*_m + 1; float h[h_len]; liquid_firdes_prototype(_type,_interp,_m,_beta,_dt,h); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC hc[h_len]; for (i=0; i 1 FIRINTERP() FIRINTERP(_create_linear)(unsigned int _interp) { // validate input if (_interp < 1) return liquid_error_config("firinterp_%s_create_linear(), interp factor must be greater than 1", EXTENSION_FULL); // generate coefficients unsigned int i; TC hc[2*_interp]; for (i=0; i<_interp; i++) hc[ i] = (float)i / (float)_interp; for (i=0; i<_interp; i++) hc[_interp+i] = 1.0f - (float)i / (float)_interp; // return interpolator object return FIRINTERP(_create)(_interp, hc, 2*_interp); } // create window interpolator object // _interp : interpolation factor, _interp > 1 // _m : filter semi-length, _m > 0 FIRINTERP() FIRINTERP(_create_window)(unsigned int _interp, unsigned int _m) { // validate input if (_interp < 1) return liquid_error_config("firinterp_%s_create_spline(), interp factor must be greater than 1", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firinterp_%s_create_spline(), interp factor must be greater than 1", EXTENSION_FULL); // generate coefficients unsigned int i; TC hc[2*_m*_interp]; for (i=0; i<2*_m*_interp; i++) hc[i] = powf(sinf(M_PI*(float)i/(float)(2*_m*_interp)), 2.0f); // return interpolator object return FIRINTERP(_create)(_interp, hc, 2*_m*_interp); } // copy object FIRINTERP() FIRINTERP(_copy)(FIRINTERP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firinterp_%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy internal memory FIRINTERP() q_copy = (FIRINTERP()) malloc(sizeof(struct FIRINTERP(_s))); memmove(q_copy, q_orig, sizeof(struct FIRINTERP(_s))); // copy objects and allocated memory q_copy->h = (TC *)liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(TC)); q_copy->filterbank= FIRPFB(_copy)(q_orig->filterbank); return q_copy; } // destroy interpolator object int FIRINTERP(_destroy)(FIRINTERP() _q) { FIRPFB(_destroy)(_q->filterbank); free(_q->h); free(_q); return LIQUID_OK; } // print interpolator state int FIRINTERP(_print)(FIRINTERP() _q) { printf("M); printf(", h_len=%u", _q->h_len); printf(">\n"); return FIRPFB(_print)(_q->filterbank); } // clear internal state int FIRINTERP(_reset)(FIRINTERP() _q) { return FIRPFB(_reset)(_q->filterbank); } // Get interpolation rate unsigned int FIRINTERP(_get_interp_rate)(FIRINTERP() _q) { return _q->M; } // Get sub-filter length (length of each poly-phase filter) unsigned int FIRINTERP(_get_sub_len)(FIRINTERP() _q) { return _q->h_sub_len; } // Set output scaling for interpolator // _q : interpolator object // _scale : scaling factor to apply to each output sample int FIRINTERP(_set_scale)(FIRINTERP() _q, TC _scale) { return FIRPFB(_set_scale)(_q->filterbank, _scale); } // Get output scaling for interpolator // _q : interpolator object // _scale : scaling factor to apply to each output sample int FIRINTERP(_get_scale)(FIRINTERP() _q, TC * _scale) { return FIRPFB(_get_scale)(_q->filterbank, _scale); } // execute interpolator // _q : interpolator object // _x : input sample // _y : output array [size: 1 x M] int FIRINTERP(_execute)(FIRINTERP() _q, TI _x, TO * _y) { // push sample into filterbank FIRPFB(_push)(_q->filterbank, _x); // compute output for each filter in the bank unsigned int i; for (i=0; i<_q->M; i++) FIRPFB(_execute)(_q->filterbank, i, &_y[i]); return LIQUID_OK; } // execute interpolation on block of input samples // _q : firinterp object // _x : input array [size: _n x 1] // _n : size of input array // _y : output sample array [size: M*_n x 1] int FIRINTERP(_execute_block)(FIRINTERP() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute one input at a time with an output stride M FIRINTERP(_execute)(_q, _x[i], &_y[i*_q->M]); } return LIQUID_OK; } // Execute interpolation with zero-valued input (e.g. flush internal state) // _q : firinterp object // _y : output sample array [size: M x 1] int FIRINTERP(_flush)(FIRINTERP() _q, TO * _y) { return FIRINTERP(_execute)(_q, 0, _y); } liquid-dsp-1.7.0/src/filter/src/firpfb.proto.c000066400000000000000000000324331474751757600212470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // finite impulse response (FIR) polyphase filter bank (PFB) // #include #include #include struct FIRPFB(_s) { unsigned int h_len; // total number of filter coefficients unsigned int h_sub_len; // sub-sampled filter length unsigned int num_filters; // number of filters WINDOW() w; // window buffer DOTPROD() * dp; // array of vector dot product objects TC scale; // output scaling factor }; // create firpfb from external coefficients // _num_filters : number of filters in the bank // _h : coefficients [size: _num_filters*_h_len x 1] // _h_len : filter delay (symbols) FIRPFB() FIRPFB(_create)(unsigned int _num_filters, TC * _h, unsigned int _h_len) { // validate input if (_num_filters == 0) return liquid_error_config("firpfb_%s_create(), number of filters must be greater than zero",EXTENSION_FULL); if (_h_len == 0) return liquid_error_config("firpfb_%s_create(), filter length must be greater than zero",EXTENSION_FULL); // create main filter object FIRPFB() q = (FIRPFB()) malloc(sizeof(struct FIRPFB(_s))); // set user-defined parameters q->num_filters = _num_filters; q->h_len = _h_len; // each filter is realized as a dotprod object q->dp = (DOTPROD()*) malloc((q->num_filters)*sizeof(DOTPROD())); // generate bank of sub-samped filters // length of each sub-sampled filter unsigned int h_sub_len = _h_len / q->num_filters; TC h_sub[h_sub_len]; unsigned int i, n; for (i=0; inum_filters; i++) { for (n=0; nnum_filters)]; } // create dot product object q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); } // save sub-sampled filter length q->h_sub_len = h_sub_len; // create window buffer q->w = WINDOW(_create)(q->h_sub_len); // set default scaling q->scale = 1; // reset object and return FIRPFB(_reset)(q); return q; } // create default firpfb FIRPFB() FIRPFB(_create_default)(unsigned int _num_filters, unsigned int _m) { return FIRPFB(_create_kaiser)(_num_filters, _m, 0.5f, 60.0f); } // create firpfb using kaiser window // _num_filters : number of filters in the bank // _m : filter semi-length [samples] // _fc : filter cut-off frequency 0 < _fc < 0.5 // _as : filter stop-band suppression [dB] FIRPFB() FIRPFB(_create_kaiser)(unsigned int _num_filters, unsigned int _m, float _fc, float _as) { // validate input if (_num_filters == 0) return liquid_error_config("firpfb_%s_create_kaiser(), number of filters must be greater than zero", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firpfb_%s_create_kaiser(), filter delay must be greater than 0", EXTENSION_FULL); if (_fc < 0.0f || _fc > 0.5f) return liquid_error_config("firpfb_%s_create_kaiser(), filter cut-off frequence must be in (0,0.5)", EXTENSION_FULL); if (_as < 0.0f) return liquid_error_config("firpfb_%s_create_kaiser(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); // design filter using kaiser window unsigned int H_len = 2*_num_filters*_m + 1; float Hf[H_len]; liquid_firdes_kaiser(H_len, _fc/(float)_num_filters, _as, 0.0f, Hf); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC Hc[H_len]; for (i=0; i 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_rnyquist)(int _type, unsigned int _num_filters, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_num_filters == 0) return liquid_error_config("firpfb_%s_create_rnyquist(), number of filters must be greater than zero", EXTENSION_FULL); if (_k < 2) return liquid_error_config("firpfb_%s_create_rnyquist(), filter samples/symbol must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firpfb_%s_create_rnyquist(), filter delay must be greater than 0", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("firpfb_%s_create_rnyquist(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); // generate square-root Nyquist filter unsigned int H_len = 2*_num_filters*_k*_m + 1; float Hf[H_len]; liquid_firdes_prototype(_type,_num_filters*_k,_m,_beta,0,Hf); // copy coefficients to type-specific array (e.g. float complex) unsigned int i; TC Hc[H_len]; for (i=0; i 1 // _m : filter delay (symbols), _m > 0 // _beta : excess bandwidth factor, 0 < _beta < 1 FIRPFB() FIRPFB(_create_drnyquist)(int _type, unsigned int _num_filters, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_num_filters == 0) return liquid_error_config("firpfb_%s_create_drnyquist(), number of filters must be greater than zero", EXTENSION_FULL); if (_k < 2) return liquid_error_config("firpfb_%s_create_drnyquist(), filter samples/symbol must be greater than 1", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firpfb_%s_create_drnyquist(), filter delay must be greater than 0", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("firpfb_%s_create_drnyquist(), filter excess bandwidth factor must be in [0,1]", EXTENSION_FULL); // generate square-root Nyquist filter unsigned int H_len = 2*_num_filters*_k*_m + 1; float Hf[H_len]; liquid_firdes_prototype(_type,_num_filters*_k,_m,_beta,0,Hf); // compute derivative filter float dHf[H_len]; float HdH_max = 0.0f; unsigned int i; for (i=0; i HdH_max ) HdH_max = fabsf(Hf[i]*dHf[i]); } // copy coefficients to type-specific array (e.g. float complex) // and apply scaling factor for normalized response TC Hc[H_len]; for (i=0; ih_len || _num_filters != _q->num_filters) { // filter length has changed: recreate entire filter FIRPFB(_destroy)(_q); _q = FIRPFB(_create)(_num_filters,_h,_h_len); return _q; } // re-create each dotprod object TC h_sub[_q->h_sub_len]; unsigned int i, n; for (i=0; i<_q->num_filters; i++) { for (n=0; n<_q->h_sub_len; n++) { // load filter in reverse order h_sub[_q->h_sub_len-n-1] = _h[i + n*(_q->num_filters)]; } _q->dp[i] = DOTPROD(_recreate)(_q->dp[i],h_sub,_q->h_sub_len); } return _q; } // copy object FIRPFB() FIRPFB(_copy)(FIRPFB() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("firpfb_%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters FIRPFB() q_copy = (FIRPFB()) malloc(sizeof(struct FIRPFB(_s))); q_copy->h_len = q_orig->h_len; q_copy->h_sub_len = q_orig->h_sub_len; q_copy->num_filters = q_orig->num_filters; q_copy->w = WINDOW(_copy)(q_orig->w); // copy array of dotproduct objects q_copy->dp = (DOTPROD()*) malloc((q_copy->num_filters)*sizeof(DOTPROD())); unsigned int i; for (i=0; inum_filters; i++) q_copy->dp[i] = DOTPROD(_copy)(q_orig->dp[i]); q_copy->scale = q_orig->scale; return q_copy; } // destroy firpfb object, freeing all internal memory int FIRPFB(_destroy)(FIRPFB() _q) { unsigned int i; for (i=0; i<_q->num_filters; i++) DOTPROD(_destroy)(_q->dp[i]); free(_q->dp); WINDOW(_destroy)(_q->w); free(_q); return LIQUID_OK; } // print firpfb object's parameters int FIRPFB(_print)(FIRPFB() _q) { printf("num_filters, _q->h_sub_len); printf(", scale="); PRINTVAL_TC(_q->scale,%g); printf(">\n"); return LIQUID_OK; } // clear/reset firpfb object internal state int FIRPFB(_reset)(FIRPFB() _q) { return WINDOW(_reset)(_q->w); } // set output scaling for filter int FIRPFB(_set_scale)(FIRPFB() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // get output scaling for filter int FIRPFB(_get_scale)(FIRPFB() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // push sample into firpfb internal buffer int FIRPFB(_push)(FIRPFB() _q, TI _x) { // push value into window buffer return WINDOW(_push)(_q->w, _x); } // Write a block of samples into object's internal buffer int FIRPFB(_write)(FIRPFB() _q, TI * _x, unsigned int _n) { return WINDOW(_write)(_q->w, _x, _n); } // execute the filter on internal buffer and coefficients // _q : firpfb object // _i : index of filter to use // _y : pointer to output sample int FIRPFB(_execute)(FIRPFB() _q, unsigned int _i, TO * _y) { // validate input if (_i >= _q->num_filters) { return liquid_error(LIQUID_EICONFIG,"firpfb_execute(), filterbank index (%u) exceeds maximum (%u)",_i,_q->num_filters); } // read buffer TI *r; WINDOW(_read)(_q->w, &r); // execute dot product DOTPROD(_execute)(_q->dp[_i], r, _y); // apply scaling factor *_y *= _q->scale; return LIQUID_OK; } // execute the filter on a block of input samples; the // input and output buffers may be the same // _q : firpfb object // _i : index of filter to use // _x : pointer to input array [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array [size: _n x 1] int FIRPFB(_execute_block)(FIRPFB() _q, unsigned int _i, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // push sample into filter FIRPFB(_push)(_q, _x[i]); // compute output at appropriate index FIRPFB(_execute)(_q, _i, &_y[i]); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/fnyquist.c000066400000000000000000000257441474751757600205260ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Flipped Nyquist/root-Nyquist filter designs // // References: // [Beaulieu:2001] // [Assalini:2004] // #include #include #include #include #include "liquid.internal.h" // Design flipped Nyquist/root-Nyquist filter // _type : filter type (e.g. LIQUID_FIRFILT_FEXP) // _root : square-root Nyquist filter? // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_fnyquist(liquid_firfilt_type _type, int _root, unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if ( _k < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_fnyquist(): k must be greater than 0"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_fnyquist(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_fnyquist(): beta must be in [0,1]"); unsigned int i; // derived values unsigned int h_len = 2*_k*_m+1; // filter length float H_prime[h_len]; // frequency response of Nyquist filter (real) float complex H[h_len]; // frequency response of Nyquist filter float complex h[h_len]; // impulse response of Nyquist filter // compute Nyquist filter frequency response switch (_type) { case LIQUID_FIRFILT_FEXP: liquid_firdes_fexp_freqresponse(_k, _m, _beta, H_prime); break; case LIQUID_FIRFILT_FSECH: liquid_firdes_fsech_freqresponse(_k, _m, _beta, H_prime); break; case LIQUID_FIRFILT_FARCSECH: liquid_firdes_farcsech_freqresponse(_k, _m, _beta, H_prime); break; default: return liquid_error(LIQUID_EICONFIG,"liquid_firdes_fnyquist(), unknown/unsupported filter type"); } // copy result to fft input buffer, computing square root // if required for (i=0; i 0.5f) f = f - 1.0f; // enforce even symmetry f = fabsf(f); if ( f < f0 ) { // pass band _H[i] = 1.0f; } else if (f > f0 && f < f2) { // transition band if ( f < f1) { _H[i] = expf(gamma*(B*(1-_beta) - f)); } else { _H[i] = 1.0f - expf(gamma*(f - (1+_beta)*B)); } } else { // stop band _H[i] = 0.0f; } } return LIQUID_OK; } // Design fsech Nyquist filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_fsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // compute response using generic function return liquid_firdes_fnyquist(LIQUID_FIRFILT_FSECH, 0, _k, _m, _beta, _dt, _h); } // Design fsech square-root Nyquist filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_rfsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // compute response using generic function return liquid_firdes_fnyquist(LIQUID_FIRFILT_FSECH, 1, _k, _m, _beta, _dt, _h); } // flipped exponential frequency response int liquid_firdes_fsech_freqresponse(unsigned int _k, unsigned int _m, float _beta, float * _H) { // TODO : validate input unsigned int i; unsigned int h_len = 2*_k*_m + 1; float f0 = 0.5f*(1.0f - _beta) / (float)_k; float f1 = 0.5f*(1.0f ) / (float)_k; float f2 = 0.5f*(1.0f + _beta) / (float)_k; float B = 0.5f/(float)_k; float gamma = logf(sqrtf(3.0f) + 2.0f) / (_beta*B); // compute frequency response of Nyquist filter for (i=0; i 0.5f) f = f - 1.0f; // enforce even symmetry f = fabsf(f); if ( f < f0 ) { // pass band _H[i] = 1.0f; } else if (f > f0 && f < f2) { // transition band if ( f < f1) { _H[i] = 1.0f / coshf(gamma*(f - B*(1-_beta))); } else { _H[i] = 1.0f - 1.0f / coshf(gamma*(B*(1+_beta) - f)); } } else { // stop band _H[i] = 0.0f; } } return LIQUID_OK; } // Design farcsech Nyquist filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_farcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // compute response using generic function return liquid_firdes_fnyquist(LIQUID_FIRFILT_FARCSECH, 0, _k, _m, _beta, _dt, _h); } // Design farcsech square-root Nyquist filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_rfarcsech(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // compute response using generic function return liquid_firdes_fnyquist(LIQUID_FIRFILT_FARCSECH, 1, _k, _m, _beta, _dt, _h); } // hyperbolic arc-secant float liquid_asechf(float _z) { if (_z <= 0.0f || _z > 1.0f) { liquid_error(LIQUID_EICONFIG,"liquid_asechf(), input (_z=%g)out of range (0,1)", _z); return 0.0f; } float z_inv = 1.0f / _z; return logf( sqrtf(z_inv - 1.0f)*sqrtf(z_inv + 1.0f) + z_inv ); } // flipped exponential frequency response int liquid_firdes_farcsech_freqresponse(unsigned int _k, unsigned int _m, float _beta, float * _H) { // TODO : validate input unsigned int i; unsigned int h_len = 2*_k*_m + 1; float f0 = 0.5f*(1.0f - _beta) / (float)_k; float f1 = 0.5f*(1.0f ) / (float)_k; float f2 = 0.5f*(1.0f + _beta) / (float)_k; float B = 0.5f/(float)_k; float gamma = logf(sqrtf(3.0f) + 2.0f) / (_beta*B); float zeta = 1.0f / (2.0f * _beta * B); // compute frequency response of Nyquist filter for (i=0; i 0.5f) f = f - 1.0f; // enforce even symmetry f = fabsf(f); if ( f < f0 ) { // pass band _H[i] = 1.0f; } else if (f > f0 && f < f2) { // transition band if ( f < f1) { _H[i] = 1.0f - (zeta/gamma)*liquid_asechf(zeta*(B*(1+_beta) - f)); } else { _H[i] = (zeta/gamma)*liquid_asechf(zeta*(f - B*(1-_beta))); } } else { // stop band _H[i] = 0.0f; } } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/gmsk.c000066400000000000000000000156031474751757600175760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Finite impulse response GMSK transmit/receive filter design // #include #include #include #include #include "liquid.internal.h" // Design GMSK transmit filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_gmsktx(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if ( _k < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_gmsktx(): k must be greater than 0"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_gmsktx(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_gmsktx(): beta must be in [0,1]"); // derived values unsigned int h_len = 2*_k*_m+1; // compute filter coefficients unsigned int i; float t; float c0 = 1.0f / sqrtf(logf(2.0f)); for (i=0; i 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_gmskrx(): beta must be in [0,1]"); unsigned int k = _k; unsigned int m = _m; float BT = _beta; // internal options float beta = BT; // prototype filter cut-off float delta = 1e-3f; // filter design correction factor liquid_firfilt_type prototype = LIQUID_FIRFILT_KAISER; // Nyquist prototype unsigned int i; // derived values unsigned int h_len = 2*k*m+1; // filter length // arrays float ht[h_len]; // transmit filter coefficients float hr[h_len]; // receive filter coefficients // design transmit filter liquid_firdes_gmsktx(k,m,BT,0.0f,ht); // // start of filter design procedure // // 'internal' arrays float h_primef[h_len]; // temporary buffer for real 'prototype' coefficients float g_primef[h_len]; // temporary buffer for real 'gain' coefficient float complex h_tx[h_len]; // impulse response of transmit filter float complex h_prime[h_len]; // impulse response of 'prototype' filter float complex g_prime[h_len]; // impulse response of 'gain' filter float complex h_hat[h_len]; // impulse response of receive filter float complex H_tx[h_len]; // frequency response of transmit filter float complex H_prime[h_len]; // frequency response of 'prototype' filter float complex G_prime[h_len]; // frequency response of 'gain' filter float complex H_hat[h_len]; // frequency response of receive filter // create 'prototype' matched filter liquid_firdes_prototype(prototype,k,m,beta,0.0f,h_primef); // create 'gain' filter to improve stop-band rejection float fc = (0.7f + 0.1*beta) / (float)k; float as = 60.0f; liquid_firdes_kaiser(h_len, fc, as, 0.0f, g_primef); // copy to fft input buffer, shifting appropriately for (i=0; i #include #include #include "liquid.internal.h" // Compute group delay for a FIR filter // _h : filter coefficients array [size: _n x 1] // _n : filter length // _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) float fir_group_delay(float * _h, unsigned int _n, float _fc) { // validate input if (_n == 0) { liquid_error(LIQUID_EICONFIG,"fir_group_delay(), length must be greater than zero"); return 0.0f; } else if (_fc < -0.5 || _fc > 0.5) { liquid_error(LIQUID_EICONFIG,"fir_group_delay(), _fc must be in [-0.5,0.5]"); return 0.0f; } unsigned int i; float complex t0=0.0f; float complex t1=0.0f; for (i=0; i<_n; i++) { t0 += _h[i] * cexpf(_Complex_I*2*M_PI*_fc*i) * i; t1 += _h[i] * cexpf(_Complex_I*2*M_PI*_fc*i); } return crealf(t0/t1); } // Compute group delay for an IIR filter // _b : filter coefficients array (numerator), [size: _nb x 1] // _nb : filter length (numerator) // _a : filter coefficients array (denominator), [size: _na x 1] // _na : filter length (denominator) // _fc : frequency at which delay is evaluated (-0.5 < _fc < 0.5) float iir_group_delay(float * _b, unsigned int _nb, float * _a, unsigned int _na, float _fc) { // validate input if (_nb == 0) { liquid_error(LIQUID_EICONFIG,"iir_group_delay(), numerator length must be greater than zero"); return 0.0f; } else if (_na == 0) { liquid_error(LIQUID_EICONFIG,"iir_group_delay(), denominator length must be greater than zero"); return 0.0f; } else if (_fc < -0.5 || _fc > 0.5) { liquid_error(LIQUID_EICONFIG,"iir_group_delay(), _fc must be in [-0.5,0.5]"); return 0.0f; } // compute c = conv(b,fliplr(a)) // c(z) = b(z)*a(1/z)*z^(-_na) unsigned int nc = _na + _nb - 1; float c[nc]; unsigned int i,j; for (i=0; i #include #include #include #include "liquid.internal.h" #define DEBUG_hM3 0 // Design root-Nyquist harris-Moerder filter using Parks-McClellan // algorithm // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] int liquid_firdes_hM3(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { if ( _k < 2 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_hM3(): k must be greater than 1"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_hM3(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_hM3(): beta must be in [0,1]"); unsigned int n=2*_k*_m+1; // filter length // float fc = 1.0 / (float)(2*_k); // filter cutoff float fp = fc*(1.0 - _beta); // pass-band float fs = fc*(1.0 + _beta); // stop-band // root nyquist unsigned int num_bands = 3; float bands[6] = {0.0f, fp, fc, fc, fs, 0.5f}; float des[3] = {1.0f, 1.0f/sqrtf(2.0f), 0.0f}; float weights[3] = {1.0f, 1.0f, 1.0f}; liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; liquid_firdespm_wtype wtype[3] = {LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_FLATWEIGHT, LIQUID_FIRDESPM_EXPWEIGHT}; //unsigned int i; float h[n]; firdespm_run(n,num_bands,bands,des,weights,wtype,btype,h); // copy results memmove(_h, h, n*sizeof(float)); float isi_max; float isi_rms; liquid_filter_isi(h,_k,_m,&isi_rms,&isi_max); // iterate... float isi_rms_min = isi_rms; unsigned int p, pmax=100; for (p=0; p isi_rms_min) { // search complete break; } else { isi_rms_min = isi_rms; // copy results memmove(_h, h, n*sizeof(float)); } }; // normalize float e2 = 0.0f; unsigned int i; for (i=0; i #include #include // decimator structure struct IIRDECIM(_s) { unsigned int M; // decimation factor // TODO: use IIR polyphase filterbank IIRFILT() iirfilt; // filter object }; // create interpolator from external coefficients // _M : interpolation factor // _b : feed-back coefficients [size: _nb x 1] // _nb : feed-back coefficients length // _a : feed-forward coefficients [size: _na x 1] // _na : feed-forward coefficients length IIRDECIM() IIRDECIM(_create)(unsigned int _M, TC * _b, unsigned int _nb, TC * _a, unsigned int _na) { // validate input if (_M < 2) return liquid_error_config("iirinterp_%s_create(), interp factor must be greater than 1", EXTENSION_FULL); // allocate main object memory and set internal parameters IIRDECIM() q = (IIRDECIM()) malloc(sizeof(struct IIRDECIM(_s))); q->M = _M; // create filter q->iirfilt = IIRFILT(_create)(_b, _nb, _a, _na); // return interpolator object return q; } // create decimator with default Butterworth prototype // _M : decimation factor // _order : filter order IIRDECIM() IIRDECIM(_create_default)(unsigned int _M, unsigned int _order) { return IIRDECIM(_create_prototype)(_M, LIQUID_IIRDES_BUTTER, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, _order, 0.5f / (float)_M, // fc 0.0f, // f0 0.1f, // pass-band ripple, 60.0f); // stop-band attenuation } // create interpolator from prototype // _M : interpolation factor IIRDECIM() IIRDECIM(_create_prototype)(unsigned int _M, liquid_iirdes_filtertype _ftype, liquid_iirdes_bandtype _btype, liquid_iirdes_format _format, unsigned int _order, float _fc, float _f0, float _ap, float _as) { // validate input if (_M < 2) return liquid_error_config("iirinterp_%s_create_prototype(), interp factor must be greater than 1", EXTENSION_FULL); // allocate main object memory and set internal parameters IIRDECIM() q = (IIRDECIM()) malloc(sizeof(struct IIRDECIM(_s))); q->M = _M; // create filter q->iirfilt = IIRFILT(_create_prototype)(_ftype, _btype, _format, _order, _fc, _f0, _ap, _as); // return interpolator object return q; } // copy object IIRDECIM() IIRDECIM(_copy)(IIRDECIM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("iirdecim%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy internal memory IIRDECIM() q_copy = (IIRDECIM()) malloc(sizeof(struct IIRDECIM(_s))); memmove(q_copy, q_orig, sizeof(struct IIRDECIM(_s))); // copy internal object and return q_copy->iirfilt = IIRFILT(_copy)(q_orig->iirfilt); return q_copy; } // destroy interpolator object int IIRDECIM(_destroy)(IIRDECIM() _q) { IIRFILT(_destroy)(_q->iirfilt); free(_q); return LIQUID_OK; } // print interpolator state int IIRDECIM(_print)(IIRDECIM() _q) { printf("\n", EXTENSION_FULL, _q->M); return LIQUID_OK; } // clear internal state int IIRDECIM(_reset)(IIRDECIM() _q) { return IIRFILT(_reset)(_q->iirfilt); } // execute decimator // _q : decimator object // _x : input sample array [size: _M x 1] // _y : output sample pointer // _index : decimator output index [0,_M-1] int IIRDECIM(_execute)(IIRDECIM() _q, TI * _x, TO * _y) { TO v; // output value unsigned int i; for (i=0; i<_q->M; i++) { // run filter IIRFILT(_execute)(_q->iirfilt, _x[i], &v); // save output at appropriate index if (i==0) *_y = v; } return LIQUID_OK; } // execute decimator on block of _n*_M input samples // _q : decimator object // _x : input array [size: _n*_M x 1] // _n : number of _output_ samples // _y : output array [_sze: _n x 1] int IIRDECIM(_execute_block)(IIRDECIM() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute _M input samples computing just one output each time IIRDECIM(_execute)(_q, &_x[i*_q->M], &_y[i]); } return LIQUID_OK; } // get system group delay at frequency _fc // _q : interpolator object // _f : frequency float IIRDECIM(_groupdelay)(IIRDECIM() _q, float _fc) { return IIRFILT(_groupdelay)(_q->iirfilt, _fc); } liquid-dsp-1.7.0/src/filter/src/iirdes.c000066400000000000000000000706621474751757600201220ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iir (infinite impulse response) filter design // // References // [Constantinides:1967] A. G. Constantinides, "Frequency // Transformations for Digital Filters." IEEE Electronic // Letters, vol. 3, no. 11, pp 487-489, 1967. // #include #include #include #include #include "liquid.internal.h" #define LIQUID_IIRDES_DEBUG_PRINT 0 // Sorts array _z of complex numbers into complex conjugate pairs to // within a tolerance. Conjugate pairs are ordered by increasing real // component with the negative imaginary element first. All pure-real // elements are placed at the end of the array. // // Example: // v: liquid_cplxpair(v): // 10 + j*3 -3 - j*4 // 5 + j*0 3 + j*4 // -3 + j*4 10 - j*3 // 10 - j*3 10 + j*3 // 3 + j*0 3 + j*0 // -3 + j*4 5 + j*0 // // _z : complex array (size _n) // _n : number of elements in _z // _tol : tolerance for finding complex pairs // _p : resulting pairs, pure real values of _z at end int liquid_cplxpair(float complex * _z, unsigned int _n, float _tol, float complex * _p) { // validate input if (_tol < 0) return liquid_error(LIQUID_EICONFIG,"liquid_cplxpair(), tolerance must be positive"); // keep track of which elements have been paired unsigned char paired[_n]; memset(paired,0,sizeof(paired)); unsigned int num_pairs=0; unsigned int i,j,k=0; for (i=0; i<_n; i++) { // ignore value if already paired, or if imaginary // component is less than tolerance if (paired[i] || fabsf(cimagf(_z[i])) < _tol) continue; for (j=0; j<_n; j++) { // ignore value if already paired, or if imaginary // component is less than tolerance if (j==i || paired[j] || fabsf(cimagf(_z[j])) < _tol) continue; if ( fabsf(cimagf(_z[i])+cimagf(_z[j])) < _tol && fabsf(crealf(_z[i])-crealf(_z[j])) < _tol ) { // found complex conjugate pair _p[k++] = _z[i]; _p[k++] = _z[j]; paired[i] = 1; paired[j] = 1; num_pairs++; break; } } } if (k > _n) return liquid_error(LIQUID_EINT,"liquid_cplxpair(), invalid derived order"); // sort through remaining unpaired values and ensure // they are purely real for (i=0; i<_n; i++) { if (paired[i]) continue; if (cimagf(_z[i]) > _tol) { fprintf(stderr,"warning, liquid_cplxpair(), complex numbers cannot be paired\n"); } else { _p[k++] = _z[i]; paired[i] = 1; } } // clean up result // * force pairs to be perfect conjugates with // negative imaginary component first // * complex conjugate pairs are ordered by // increasing real component // * pure-real elements are ordered by increasing // value return liquid_cplxpair_cleanup(_p, _n, num_pairs); } // post-process cleanup used with liquid_cplxpair // // once pairs have been identified and ordered, this method // will clean up the result by ensuring the following: // * pairs are perfect conjugates // * pairs have negative imaginary component first // * pairs are ordered by increasing real component // * pure-real elements are ordered by increasing value // // _p : pre-processed complex array [size: _n x 1] // _n : array length // _num_pairs : number of complex conjugate pairs int liquid_cplxpair_cleanup(float complex * _p, unsigned int _n, unsigned int _num_pairs) { unsigned int i; unsigned int j; float complex tmp; // ensure perfect conjugates, with negative imaginary // element coming first for (i=0; i<_num_pairs; i++) { // ensure perfect conjugates _p[2*i+0] = cimagf(_p[2*i]) < 0 ? _p[2*i] : conjf(_p[2*i]); _p[2*i+1] = conjf(_p[2*i+0]); } // sort conjugate pairs for (i=0; i<_num_pairs; i++) { for (j=_num_pairs-1; j>i; j--) { if ( crealf(_p[2*(j-1)]) > crealf(_p[2*j]) ) { // swap pairs tmp = _p[2*(j-1)+0]; _p[2*(j-1)+0] = _p[2*j+0]; _p[2*j +0] = tmp; tmp = _p[2*(j-1)+1]; _p[2*(j-1)+1] = _p[2*j+1]; _p[2*j +1] = tmp; } } } // sort pure-real values for (i=2*_num_pairs; i<_n; i++) { for (j=_n-1; j>i; j--) { if ( crealf(_p[j-1]) > crealf(_p[j]) ) { // swap elements tmp = _p[j-1]; _p[j-1] = _p[j]; _p[j ] = tmp; } } } return LIQUID_OK; } // // new IIR design // // Compute frequency pre-warping factor. See [Constantinides:1967] // _btype : band type (e.g. LIQUID_IIRDES_HIGHPASS) // _fc : low-pass cutoff frequency // _f0 : center frequency (band-pass|stop cases only) float iirdes_freqprewarp(liquid_iirdes_bandtype _btype, float _fc, float _f0) { float m = 0.0f; if (_btype == LIQUID_IIRDES_LOWPASS) { // low pass m = tanf(M_PI * _fc); } else if (_btype == LIQUID_IIRDES_HIGHPASS) { // high pass m = -cosf(M_PI * _fc) / sinf(M_PI * _fc); } else if (_btype == LIQUID_IIRDES_BANDPASS) { // band pass m = (cosf(2*M_PI*_fc) - cosf(2*M_PI*_f0) )/ sinf(2*M_PI*_fc); } else if (_btype == LIQUID_IIRDES_BANDSTOP) { // band stop m = sinf(2*M_PI*_fc)/(cosf(2*M_PI*_fc) - cosf(2*M_PI*_f0)); } m = fabsf(m); return m; } // convert analog zeros, poles, gain to digital zeros, poles gain // _za : analog zeros (length: _nza) // _nza : number of analog zeros // _pa : analog poles (length: _npa) // _npa : number of analog poles // _ka : nominal gain (NOTE: this does not necessarily carry over from analog gain) // _m : frequency pre-warping factor // _zd : digital zeros (length: _npa) // _pd : digital poles (length: _npa) // _kd : digital gain // // The filter order is characterized by the number of analog // poles. The analog filter may have up to _npa zeros. // The number of digital zeros and poles is equal to _npa. int bilinear_zpkf(float complex * _za, unsigned int _nza, float complex * _pa, unsigned int _npa, float complex _ka, float _m, float complex * _zd, float complex * _pd, float complex * _kd) { unsigned int i; // filter order is equal to number of analog poles unsigned int n = _npa; float complex G = _ka; // nominal gain for (i=0; i _m*(z-1)/(z+1) ) and expands as // // bd[0] + bd[1]*z^-1 + ... + bd[nb]*z^-n // H(z) = -------------------------------------- // ad[0] + ad[1]*z^-1 + ... + ad[nb]*z^-m // // _b : numerator array, [size: _b_order+1] // _b_order : polynomial order of _b // _a : denominator array, [size: _a_order+1] // _a_order : polynomial order of _a // _m : bilateral warping factor // _bd : output digital filter numerator, [size: _b_order+1] // _ad : output digital filter numerator, [size: _a_order+1] int bilinear_nd(float complex * _b, unsigned int _b_order, float complex * _a, unsigned int _a_order, float _m, float complex * _bd, float complex * _ad) { if (_b_order > _a_order) return liquid_error(LIQUID_EICONFIG,"bilinear_nd(), numerator order cannot be higher than denominator"); #if LIQUID_IIRDES_DEBUG_PRINT printf("***********************************\n"); printf("bilinear(nd), numerator order : %u\n", _b_order); printf("bilinear(nd), denominator order : %u\n", _a_order); #endif // ... unsigned int nb = _b_order+1; // input numerator polynomial array length unsigned int na = _a_order+1; // input denominator polynomial array length unsigned int i, j; // clear output arrays (both are length na = _a_order+1) for (i=0; i= 0.5) return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), cutoff frequency out of range"); if (_f0 < 0 || _f0 > 0.5) return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), center frequency out of range"); if (_ap <= 0) return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), pass-band ripple out of range"); if (_as <= 0) return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), stop-band ripple out of range"); if (_n == 0) return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), filter order must be > 0"); // number of analog poles/zeros unsigned int npa = _n; unsigned int nza; // analog poles/zeros/gain float complex pa[_n]; float complex za[_n]; float complex ka; float complex k0 = 1.0f; // nominal digital gain // derived values unsigned int r = _n%2; // odd/even filter order unsigned int L = (_n-r)/2; // filter semi-length // specific filter variables float epsilon, Gp, Gs, ep, es; // compute zeros and poles of analog prototype switch (_ftype) { case LIQUID_IIRDES_BUTTER: // Butterworth filter design : no zeros, _n poles nza = 0; k0 = 1.0f; if (butter_azpkf(_n,za,pa,&ka) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not design analog filter (butterworth)"); break; case LIQUID_IIRDES_CHEBY1: // Cheby-I filter design : no zeros, _n poles, pass-band ripple nza = 0; epsilon = sqrtf( powf(10.0f, _ap / 10.0f) - 1.0f ); k0 = r ? 1.0f : 1.0f / sqrt(1.0f + epsilon*epsilon); if (cheby1_azpkf(_n,epsilon,za,pa,&ka) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not design analog filter (cheby1)"); break; case LIQUID_IIRDES_CHEBY2: // Cheby-II filter design : _n-r zeros, _n poles, stop-band ripple nza = 2*L; epsilon = powf(10.0f, -_as/20.0f); k0 = 1.0f; if (cheby2_azpkf(_n,epsilon,za,pa,&ka) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not design analog filter (cheby2)"); break; case LIQUID_IIRDES_ELLIP: // elliptic filter design : _n-r zeros, _n poles, pass/stop-band ripple nza = 2*L; Gp = powf(10.0f, -_ap / 20.0f); // pass-band gain Gs = powf(10.0f, -_as / 20.0f); // stop-band gain ep = sqrtf(1.0f/(Gp*Gp) - 1.0f); // pass-band epsilon es = sqrtf(1.0f/(Gs*Gs) - 1.0f); // stop-band epsilon k0 = r ? 1.0f : 1.0f / sqrt(1.0f + ep*ep); if (ellip_azpkf(_n,ep,es,za,pa,&ka) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not design analog filter (elliptical)"); break; case LIQUID_IIRDES_BESSEL: // Bessel filter design : no zeros, _n poles nza = 0; k0 = 1.0f; if (bessel_azpkf(_n,za,pa,&ka) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not design analog filter (bessel)"); break; default: return liquid_error(LIQUID_EICONFIG,"liquid_iirdes(), unknown filter type"); } #if LIQUID_IIRDES_DEBUG_PRINT unsigned int i; printf("poles (analog):\n"); for (i=0; i band-pass transform iirdes_dzpk_lp2bp(zd, pd, // low-pass prototype zeros, poles _n, // filter order _f0, // center frequency zd1,pd1); // transformed zeros, poles (length: 2*n) // copy transformed zeros, poles memmove(zd, zd1, 2*_n*sizeof(float complex)); memmove(pd, pd1, 2*_n*sizeof(float complex)); // update parameters; filter order doubles which changes the // number of second-order sections and forces there to never // be any remainder (r=0 always). _n = 2*_n; // _n is now even #if LIQUID_IIRDES_DEBUG_PRINT r = _n % 2; // r is now zero L = (_n-r)/2; // L is now the original value of _n #endif } if (_format == LIQUID_IIRDES_TF) { // convert complex digital poles/zeros/gain into transfer // function : H(z) = B(z) / A(z) // where length(B,A) = low/high-pass ? _n + 1 : 2*_n + 1 if (iirdes_dzpk2tff(zd,pd,_n,kd,_b,_a) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not perform transfer function expansion"); #if LIQUID_IIRDES_DEBUG_PRINT // print coefficients for (i=0; i<=_n; i++) printf("b[%3u] = %12.8f;\n", i, _b[i]); for (i=0; i<=_n; i++) printf("a[%3u] = %12.8f;\n", i, _a[i]); #endif } else { // convert complex digital poles/zeros/gain into second- // order sections form : // H(z) = prod { (b0 + b1*z^-1 + b2*z^-2) / (a0 + a1*z^-1 + a2*z^-2) } // where size(B,A) = low|high-pass : [3]x[L+r] // band-pass|stop : [3]x[2*L] if (iirdes_dzpk2sosf(zd,pd,_n,kd,_b,_a) != LIQUID_OK) return liquid_error(LIQUID_EINT,"liquid_iirdes(), could not perform second-order sections expansion"); #if LIQUID_IIRDES_DEBUG_PRINT // print coefficients printf("B [%u x 3] :\n", L+r); for (i=0; i 1.0) return 0; } return 1; } liquid-dsp-1.7.0/src/filter/src/iirdes.pll.c000066400000000000000000000076041474751757600207040ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // 2nd-order iir (infinite impulse response) phase-locked loop filter design // // References: // #include #include #include #include #include #include "liquid.internal.h" // design 2nd-order IIR filter (active lag) // 1 + t2 * s // F(s) = ------------ // 1 + t1 * s // // _w : filter bandwidth // _zeta : damping factor (1/sqrt(2) suggested) // _K : loop gain (1000 suggested) // _b : output feed-forward coefficients [size: 3 x 1] // _a : output feed-back coefficients [size: 3 x 1] void iirdes_pll_active_lag(float _w, float _zeta, float _K, float * _b, float * _a) { // validate input if (_w <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_lag(), bandwidth must be greater than 0"); return; } else if (_zeta <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_lag(), damping factor must be greater than 0"); return; } else if (_K <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_lag(), gain must be greater than 0"); return; } float wn = _w; // natural frequency float t1 = _K/(wn*wn); // float t2 = 2*_zeta/wn - 1/_K; // _b[0] = 2*_K*(1.+t2/2.0f); _b[1] = 2*_K*2.; _b[2] = 2*_K*(1.-t2/2.0f); _a[0] = 1 + t1/2.0f; _a[1] = -t1; _a[2] = -1 + t1/2.0f; } // design 2nd-order IIR filter (active PI) // 1 + t2 * s // F(s) = ------------ // t1 * s // // _w : filter bandwidth // _zeta : damping factor (1/sqrt(2) suggested) // _K : loop gain (1000 suggested) // _b : output feed-forward coefficients [size: 3 x 1] // _a : output feed-back coefficients [size: 3 x 1] void iirdes_pll_active_PI(float _w, float _zeta, float _K, float * _b, float * _a) { // validate input if (_w <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_PI(), bandwidth must be greater than 0"); return; } else if (_zeta <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_PI(), damping factor must be greater than 0"); return; } else if (_K <= 0.0f) { liquid_error(LIQUID_EICONFIG,"iirdes_pll_active_PI(), gain must be greater than 0"); return; } // loop filter (active lag) float wn = _w; // natural frequency float t1 = _K/(wn*wn); // float t2 = 2*_zeta/wn; // _b[0] = 2*_K*(1.+t2/2.0f); _b[1] = 2*_K*2.; _b[2] = 2*_K*(1.-t2/2.0f); _a[0] = t1/2.0f; _a[1] = -t1; _a[2] = t1/2.0f; } liquid-dsp-1.7.0/src/filter/src/iirfilt.proto.c000066400000000000000000000574221474751757600214460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt : Infinite impulse response filter // // References: // [Pintelon:1990] Rik Pintelon and Johan Schoukens, "Real-Time // Integration and Differentiation of Analog Signals by Means of // Digital Filtering," IEEE Transactions on Instrumentation and // Measurement, vol 39 no. 6, December 1990. // #include #include #include // defined: // IIRFILT() name-mangling macro // TO output type // TC coefficients type // TI input type // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro // use structured dot product? 0:no, 1:yes #define LIQUID_IIRFILT_USE_DOTPROD (1) struct IIRFILT(_s) { TC * b; // numerator (feed-forward coefficients) TC * a; // denominator (feed-back coefficients) TI * v; // internal filter state (buffer) unsigned int n; // filter length (order+1) unsigned int nb; // numerator length unsigned int na; // denominator length // filter structure type enum { IIRFILT_TYPE_NORM=0, IIRFILT_TYPE_SOS } type; #if LIQUID_IIRFILT_USE_DOTPROD DOTPROD() dpb; // numerator dot product DOTPROD() dpa; // denominator dot product #endif // second-order sections IIRFILTSOS() * qsos; // second-order sections filters unsigned int nsos; // number of second-order sections TC scale; // output scaling factor }; // initialize internal objects/arrays void IIRFILT(_init)(IIRFILT() _q) { _q->b = NULL; _q->a = NULL; _q->v = NULL; _q->qsos = NULL; _q->nsos = 0; #if LIQUID_IIRFILT_USE_DOTPROD _q->dpb = NULL; _q->dpa = NULL; #endif } // create iirfilt (infinite impulse response filter) object // _b : numerator, feed-forward coefficients [size: _nb x 1] // _nb : length of numerator // _a : denominator, feed-back coefficients [size: _na x 1] // _na : length of denominator IIRFILT() IIRFILT(_create)(TC * _b, unsigned int _nb, TC * _a, unsigned int _na) { // validate input if (_nb == 0) return liquid_error_config("iirfilt_%s_create(), numerator length cannot be zero", EXTENSION_FULL); if (_na == 0) return liquid_error_config("iirfilt_%s_create(), denominator length cannot be zero", EXTENSION_FULL); // create structure and initialize IIRFILT() q = (IIRFILT()) malloc(sizeof(struct IIRFILT(_s))); IIRFILT(_init)(q); q->nb = _nb; q->na = _na; q->n = (q->na > q->nb) ? q->na : q->nb; q->type = IIRFILT_TYPE_NORM; // allocate memory for numerator, denominator q->a = (TC *) malloc((q->na)*sizeof(TC)); q->b = (TC *) malloc((q->nb)*sizeof(TC)); // normalize coefficients to _a[0] TC a0 = _a[0]; unsigned int i; #if 0 // read values in reverse order for (i=0; inb; i++) q->b[i] = _b[q->nb - i - 1]; for (i=0; ina; i++) q->a[i] = _a[q->na - i - 1]; #else for (i=0; inb; i++) q->b[i] = _b[i] / a0; for (i=0; ina; i++) q->a[i] = _a[i] / a0; #endif // create buffer and initialize q->v = (TI *) malloc((q->n)*sizeof(TI)); #if LIQUID_IIRFILT_USE_DOTPROD q->dpa = DOTPROD(_create)(q->a+1, q->na-1); q->dpb = DOTPROD(_create)(q->b, q->nb); #endif // reset internal state IIRFILT(_reset)(q); // set scale and return IIRFILT(_set_scale)(q, 1); return q; } // create iirfilt (infinite impulse response filter) object based // on second-order sections form // _B : numerator, feed-forward coefficients [size: _nsos x 3] // _A : denominator, feed-back coefficients [size: _nsos x 3] // _nsos : number of second-order sections // // NOTE: The number of second-order sections can be computed from the // filter's order, n, as such: // r = n % 2 // L = (n-r)/2 // nsos = L+r IIRFILT() IIRFILT(_create_sos)(TC * _B, TC * _A, unsigned int _nsos) { // validate input if (_nsos == 0) return liquid_error_config("iirfilt_%s_create_sos(), filter must have at least one 2nd-order section", EXTENSION_FULL); // create structure and initialize IIRFILT() q = (IIRFILT()) malloc(sizeof(struct IIRFILT(_s))); IIRFILT(_init)(q); q->type = IIRFILT_TYPE_SOS; q->nsos = _nsos; q->qsos = (IIRFILTSOS()*) malloc( (q->nsos)*sizeof(IIRFILTSOS()) ); q->n = _nsos * 2; // create coefficients array and copy over q->b = (TC *) malloc(3*(q->nsos)*sizeof(TC)); q->a = (TC *) malloc(3*(q->nsos)*sizeof(TC)); memmove(q->b, _B, 3*(q->nsos)*sizeof(TC)); memmove(q->a, _A, 3*(q->nsos)*sizeof(TC)); TC at[3]; TC bt[3]; unsigned int i,k; for (i=0; insos; i++) { for (k=0; k<3; k++) { at[k] = q->a[3*i+k]; bt[k] = q->b[3*i+k]; } q->qsos[i] = IIRFILTSOS(_create)(bt,at); //q->qsos[i] = IIRFILT(_create)(q->b+3*i,3,q->a+3*i,3); } // set scale and return IIRFILT(_set_scale)(q, 1); return q; } // create iirfilt (infinite impulse response filter) object based // on prototype // _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) // _btype : band type (e.g. LIQUID_IIRDES_BANDPASS) // _format : coefficients format (e.g. LIQUID_IIRDES_SOS) // _order : filter order // _fc : low-pass prototype cut-off frequency // _f0 : center frequency (band-pass, band-stop) // _ap : pass-band ripple in dB // _as : stop-band ripple in dB IIRFILT() IIRFILT(_create_prototype)(liquid_iirdes_filtertype _ftype, liquid_iirdes_bandtype _btype, liquid_iirdes_format _format, unsigned int _order, float _fc, float _f0, float _ap, float _as) { // derived values : compute filter length unsigned int N = _order; // effective order // filter order effectively doubles for band-pass, band-stop // filters due to doubling the number of poles and zeros as // a result of filter transformation if (_btype == LIQUID_IIRDES_BANDPASS || _btype == LIQUID_IIRDES_BANDSTOP) { N *= 2; } unsigned int r = N%2; // odd/even order unsigned int L = (N-r)/2; // filter semi-length // allocate memory for filter coefficients unsigned int h_len = (_format == LIQUID_IIRDES_SOS) ? 3*(L+r) : N+1; float B[h_len]; float A[h_len]; // design filter (compute coefficients) if (liquid_iirdes(_ftype, _btype, _format, _order, _fc, _f0, _ap, _as, B, A) != LIQUID_OK) return liquid_error_config("iirfilt_%s_create_prototype(), could not design filter", EXTENSION_FULL); // move coefficients to type-specific arrays (e.g. float complex) TC Bc[h_len]; TC Ac[h_len]; unsigned int i; for (i=0; i= 1.0f) return liquid_error_config("iirfilt_%s_create_pll(), bandwidth must be in (0,1)", EXTENSION_FULL); if (_zeta <= 0.0f || _zeta >= 1.0f) return liquid_error_config("iirfilt_%s_create_pll(), damping factor must be in (0,1)", EXTENSION_FULL); if (_K <= 0.0f) return liquid_error_config("iirfilt_%s_create_pll(), loop gain must be greater than zero", EXTENSION_FULL); // compute loop filter coefficients float bf[3]; float af[3]; iirdes_pll_active_lag(_w, _zeta, _K, bf, af); // copy to type-specific array TC b[3]; TC a[3]; b[0] = bf[0]; b[1] = bf[1]; b[2] = bf[2]; a[0] = af[0]; a[1] = af[1]; a[2] = af[2]; // create and return filter object return IIRFILT(_create_sos)(b,a,1); } // copy object IIRFILT() IIRFILT(_copy)(IIRFILT() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("iirfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values IIRFILT() q_copy = (IIRFILT()) malloc(sizeof(struct IIRFILT(_s))); memmove(q_copy, q_orig, sizeof(struct IIRFILT(_s))); if (q_orig->type == IIRFILT_TYPE_NORM) { // allocate memory for numerator, denominator, buffer q_copy->a = (TC *) malloc((q_copy->na)*sizeof(TC)); q_copy->b = (TC *) malloc((q_copy->nb)*sizeof(TC)); q_copy->v = (TI *) malloc((q_copy->n )*sizeof(TI)); // copy coefficients memmove(q_copy->a, q_orig->a, (q_copy->na)*sizeof(TC)); memmove(q_copy->b, q_orig->b, (q_copy->nb)*sizeof(TC)); memmove(q_copy->v, q_orig->v, (q_copy->n )*sizeof(TI)); #if LIQUID_IIRFILT_USE_DOTPROD // copy objects q_copy->dpa = DOTPROD(_copy)(q_orig->dpa); q_copy->dpb = DOTPROD(_copy)(q_orig->dpb); #endif } else if (q_orig->type == IIRFILT_TYPE_SOS) { // create coefficients array and copy over q_copy->b = (TC *) malloc(3*(q_copy->nsos)*sizeof(TC)); q_copy->a = (TC *) malloc(3*(q_copy->nsos)*sizeof(TC)); memmove(q_copy->b, q_orig->b, 3*(q_copy->nsos)*sizeof(TC)); memmove(q_copy->a, q_orig->a, 3*(q_copy->nsos)*sizeof(TC)); // copy internal second-order sections q_copy->qsos = (IIRFILTSOS()*) malloc( (q_copy->nsos)*sizeof(IIRFILTSOS()) ); unsigned int i; for (i=0; insos; i++) q_copy->qsos[i] = IIRFILTSOS(_copy)(q_orig->qsos[i]); } else { return liquid_error_config("iirfilt_%s_copy(), invalid internal type", EXTENSION_FULL); } // return object return q_copy; } // destroy iirfilt object int IIRFILT(_destroy)(IIRFILT() _q) { #if LIQUID_IIRFILT_USE_DOTPROD if (_q->dpa != NULL) DOTPROD(_destroy)(_q->dpa); if (_q->dpb != NULL) DOTPROD(_destroy)(_q->dpb); #endif if (_q->b != NULL) free(_q->b); if (_q->a != NULL) free(_q->a); if (_q->v != NULL) free(_q->v); // if filter is comprised of cascaded second-order sections, // delete sub-filters separately if (_q->qsos != NULL) { unsigned int i; for (i=0; i<_q->nsos; i++) IIRFILTSOS(_destroy)(_q->qsos[i]); free(_q->qsos); } // free main object memory free(_q); return LIQUID_OK; } // print iirfilt object internals int IIRFILT(_print)(IIRFILT() _q) { printf("type == IIRFILT_TYPE_NORM ? "normal" : "sos"); printf(", order=%u", _q->n-1); printf(">\n"); #if 0 unsigned int i; if (_q->type == IIRFILT_TYPE_SOS) { for (i=0; i<_q->nsos; i++) IIRFILTSOS(_print)(_q->qsos[i]); } else { printf(" b :"); for (i=0; i<_q->nb; i++) PRINTVAL_TC(_q->b[i],%12.8f); printf("\n"); printf(" a :"); for (i=0; i<_q->na; i++) PRINTVAL_TC(_q->a[i],%12.8f); printf("\n"); } #endif return LIQUID_OK; } // clear/reset iirfilt object internals int IIRFILT(_reset)(IIRFILT() _q) { unsigned int i; if (_q->type == IIRFILT_TYPE_SOS) { // clear second-order sections for (i=0; i<_q->nsos; i++) { IIRFILTSOS(_reset)(_q->qsos[i]); } } else { // set internal buffer to zero for (i=0; i<_q->n; i++) _q->v[i] = 0; } return LIQUID_OK; } // set scale value to be applied to each output sample int IIRFILT(_set_scale)(IIRFILT() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // get output scaling for filter int IIRFILT(_get_scale)(IIRFILT() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // execute normal iir filter using traditional numerator/denominator // form (not second-order sections form) // _q : iirfilt object // _x : input sample // _y : output sample int IIRFILT(_execute_norm)(IIRFILT() _q, TI _x, TO * _y) { unsigned int i; // advance buffer for (i=_q->n-1; i>0; i--) _q->v[i] = _q->v[i-1]; #if LIQUID_IIRFILT_USE_DOTPROD // compute new v TI v0; DOTPROD(_execute)(_q->dpa, _q->v+1, &v0); v0 = _x - v0; _q->v[0] = v0; // compute new y DOTPROD(_execute)(_q->dpb, _q->v, _y); #else // compute new v TI v0 = _x; for (i=1; i<_q->na; i++) v0 -= _q->a[i] * _q->v[i]; _q->v[0] = v0; // compute new y TO y0 = 0; for (i=0; i<_q->nb; i++) y0 += _q->b[i] * _q->v[i]; // set return value *_y = y0; #endif // apply scaling *_y *= _q->scale; return LIQUID_OK; } // execute iir filter using second-order sections form // _q : iirfilt object // _x : input sample // _y : output sample int IIRFILT(_execute_sos)(IIRFILT() _q, TI _x, TO * _y) { TI t0 = _x; // intermediate input TO t1 = 0.; // intermediate output unsigned int i; for (i=0; i<_q->nsos; i++) { // run each filter separately IIRFILTSOS(_execute)(_q->qsos[i], t0, &t1); // output for filter n becomes input to filter n+1 t0 = t1; } *_y = t1 * _q->scale; return LIQUID_OK; } // execute iir filter, switching to type-specific function // _q : iirfilt object // _x : input sample // _y : output sample int IIRFILT(_execute)(IIRFILT() _q, TI _x, TO * _y) { if (_q->type == IIRFILT_TYPE_NORM) { return IIRFILT(_execute_norm)(_q,_x,_y); } else { return IIRFILT(_execute_sos)(_q,_x,_y); } return liquid_error(LIQUID_EINT,"iirfilt_%s_execute(), invalid internal type", EXTENSION_FULL); } // execute the filter on a block of input samples; the // input and output buffers may be the same // _q : filter object // _x : pointer to input array [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array [size: _n x 1] int IIRFILT(_execute_block)(IIRFILT() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // compute output sample IIRFILT(_execute)(_q, _x[i], &_y[i]); } return LIQUID_OK; } // get filter length (order + 1) unsigned int IIRFILT(_get_length)(IIRFILT() _q) { return _q->n; } // compute complex frequency response // _q : filter object // _fc : frequency // _H : output frequency response int IIRFILT(_freqresponse)(IIRFILT() _q, float _fc, float complex * _H) { unsigned int i; float complex H = 0.0f; if (_q->type == IIRFILT_TYPE_NORM) { // float complex Ha = 0.0f; float complex Hb = 0.0f; for (i=0; i<_q->nb; i++) Hb += _q->b[i] * cexpf(_Complex_I*2*M_PI*_fc*i); for (i=0; i<_q->na; i++) Ha += _q->a[i] * cexpf(_Complex_I*2*M_PI*_fc*i); // TODO : check to see if we need to take conjugate H = Hb / Ha; } else { H = 1.0f; // compute 3-point DFT for each second-order section for (i=0; i<_q->nsos; i++) { float complex Hb = _q->b[3*i+0] * cexpf(_Complex_I*2*M_PI*_fc*0) + _q->b[3*i+1] * cexpf(_Complex_I*2*M_PI*_fc*1) + _q->b[3*i+2] * cexpf(_Complex_I*2*M_PI*_fc*2); float complex Ha = _q->a[3*i+0] * cexpf(_Complex_I*2*M_PI*_fc*0) + _q->a[3*i+1] * cexpf(_Complex_I*2*M_PI*_fc*1) + _q->a[3*i+2] * cexpf(_Complex_I*2*M_PI*_fc*2); // TODO : check to see if we need to take conjugate H *= Hb / Ha; } } // set return value *_H = H * _q->scale; return LIQUID_OK; } // Compute power spectral density response of filter object in dB float IIRFILT(_get_psd)(IIRFILT() _q, float _fc) { float complex H; IIRFILT(_freqresponse)(_q, _fc, &H); return 10*log10f( crealf(H * conjf(H)) ); } // compute group delay in samples // _q : filter object // _fc : frequency float IIRFILT(_groupdelay)(IIRFILT() _q, float _fc) { float groupdelay = 0; unsigned int i; if (_q->type == IIRFILT_TYPE_NORM) { // compute group delay from regular transfer function form // copy coefficients float b[_q->nb]; float a[_q->na]; for (i=0; i<_q->nb; i++) b[i] = crealf(_q->b[i]); for (i=0; i<_q->na; i++) a[i] = crealf(_q->a[i]); groupdelay = iir_group_delay(b, _q->nb, a, _q->na, _fc); } else { // accumulate group delay from second-order sections for (i=0; i<_q->nsos; i++) groupdelay += IIRFILTSOS(_groupdelay)(_q->qsos[i], _fc) - 2; } return groupdelay; } liquid-dsp-1.7.0/src/filter/src/iirfiltsos.proto.c000066400000000000000000000170061474751757600221650ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Infinite impulse response filter (second-order section) // #include #include #include // defined: // IIRFILTSOS() name-mangling macro // TO output type // TC coefficients type // TI input type // PRINTVAL() print macro(s) // use structured dot product? 0:no, 1:yes #define LIQUID_IIRFILTSOS_USE_DOTPROD (0) struct IIRFILTSOS(_s) { TC b[3]; // feed-forward coefficients TC a[3]; // feed-back coefficients // internal buffering TI x[3]; // Direct form I buffer (input) TO y[3]; // Direct form I buffer (output) TO v[3]; // Direct form II buffer #if LIQUID_IIRFILTSOS_USE_DOTPROD DOTPROD() dpb; // numerator dot product DOTPROD() dpa; // denominator dot product #endif }; // create iirfiltsos object IIRFILTSOS() IIRFILTSOS(_create)(TC * _b, TC * _a) { // create filter object IIRFILTSOS() q = (IIRFILTSOS()) malloc(sizeof(struct IIRFILTSOS(_s))); // set the internal coefficients IIRFILTSOS(_set_coefficients)(q, _b, _a); // clear filter state and return object IIRFILTSOS(_reset)(q); return q; } // set internal filter coefficients // NOTE : this does not reset the internal state of the filter and // could result in instability if executed on existing filter! // explicitly set 2nd-order IIR filter coefficients // _q : iirfiltsos object // _b : feed-forward coefficients [size: _3 x 1] // _a : feed-back coefficients [size: _3 x 1] int IIRFILTSOS(_set_coefficients)(IIRFILTSOS() _q, TC * _b, TC * _a) { // retain a0 coefficient for normalization TC a0 = _a[0]; // copy feed-forward coefficients (numerator) _q->b[0] = _b[0] / a0; _q->b[1] = _b[1] / a0; _q->b[2] = _b[2] / a0; // copy feed-back coefficients (denominator) _q->a[0] = _a[0] / a0; // unity _q->a[1] = _a[1] / a0; _q->a[2] = _a[2] / a0; #if LIQUID_IIRFILTSOS_USE_DOTPROD _q->dpa = DOTPROD(_create)(_q->a+1, 2); _q->dpb = DOTPROD(_create)(_q->b, 3); #endif return LIQUID_OK; } // copy object IIRFILTSOS() IIRFILTSOS(_copy)(IIRFILTSOS() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("iirfiltsos_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values IIRFILTSOS() q_copy = (IIRFILTSOS()) malloc(sizeof(struct IIRFILTSOS(_s))); memmove(q_copy, q_orig, sizeof(struct IIRFILTSOS(_s))); #if LIQUID_IIRFILTSOS_USE_DOTPROD // copy objects q_copy->dpa = DOTPROD(_copy)(q_orig->dpa); q_copy->dpb = DOTPROD(_copy)(q_orig->dpb); #endif // return object return q_copy; } // destroy iirfiltsos object, freeing all internal memory int IIRFILTSOS(_destroy)(IIRFILTSOS() _q) { #if LIQUID_IIRFILTSOS_USE_DOTPROD DOTPROD(_destroy)(_q->dpa); DOTPROD(_destroy)(_q->dpb); #endif free(_q); return LIQUID_OK; } // print iirfiltsos object properties to stdout int IIRFILTSOS(_print)(IIRFILTSOS() _q) { printf("b[0],%g); printf(","); PRINTVAL_TC(_q->b[1],%g); printf(","); PRINTVAL_TC(_q->b[2],%g); printf("]"); printf(", a=["); PRINTVAL_TC(_q->a[0],%g); printf(","); PRINTVAL_TC(_q->a[1],%g); printf(","); PRINTVAL_TC(_q->a[2],%g); printf("]"); printf(">\n"); return LIQUID_OK; } // clear/reset iirfiltsos object internals int IIRFILTSOS(_reset)(IIRFILTSOS() _q) { // set to zero _q->v[0] = 0; _q->v[1] = 0; _q->v[2] = 0; _q->x[0] = 0; _q->x[1] = 0; _q->x[2] = 0; _q->y[0] = 0; _q->y[1] = 0; _q->y[2] = 0; return LIQUID_OK; } // compute filter output // _q : iirfiltsos object // _x : input sample // _y : output sample pointer int IIRFILTSOS(_execute)(IIRFILTSOS() _q, TI _x, TO * _y) { // execute type-specific code return IIRFILTSOS(_execute_df2)(_q,_x,_y); } // compute filter output, direct form I method // _q : iirfiltsos object // _x : input sample // _y : output sample pointer int IIRFILTSOS(_execute_df1)(IIRFILTSOS() _q, TI _x, TO * _y) { // advance buffer x _q->x[2] = _q->x[1]; _q->x[1] = _q->x[0]; _q->x[0] = _x; // advance buffer y _q->y[2] = _q->y[1]; _q->y[1] = _q->y[0]; #if LIQUID_IIRFILTSOS_USE_DOTPROD // NOTE: this is actually slower than the non-dotprod version // compute new v TI v; DOTPROD(_execute)(_q->dpb, _q->x, &v); // compute new y[0] TI y0; DOTPROD(_execute)(_q->dpa, _q->y+1, &y0); _q->y[0] = v - y0; #else // compute new v TI v = _q->x[0] * _q->b[0] + _q->x[1] * _q->b[1] + _q->x[2] * _q->b[2]; // compute new y[0] _q->y[0] = v - _q->y[1] * _q->a[1] - _q->y[2] * _q->a[2]; #endif // set output *_y = _q->y[0]; return LIQUID_OK; } // compute filter output, direct form II method // _q : iirfiltsos object // _x : input sample // _y : output sample pointer int IIRFILTSOS(_execute_df2)(IIRFILTSOS() _q, TI _x, TO * _y) { // advance buffer _q->v[2] = _q->v[1]; _q->v[1] = _q->v[0]; #if LIQUID_IIRFILTSOS_USE_DOTPROD // NOTE: this is actually slower than the non-dotprod version // compute new v TI v0; DOTPROD(_execute)(_q->dpa, _q->v+1, &v0); v0 = _x - v0; _q->v[0] = v0; // compute new y DOTPROD(_execute)(_q->dpb, _q->v, _y); #else // compute new v[0] _q->v[0] = _x - _q->a[1]*_q->v[1] - _q->a[2]*_q->v[2]; // compute output _y *_y = _q->b[0]*_q->v[0] + _q->b[1]*_q->v[1] + _q->b[2]*_q->v[2]; #endif return LIQUID_OK; } // compute group delay in samples // _q : filter object // _fc : frequency float IIRFILTSOS(_groupdelay)(IIRFILTSOS() _q, float _fc) { // copy coefficients float b[3]; float a[3]; unsigned int i; for (i=0; i<3; i++) { b[i] = crealf(_q->b[i]); a[i] = crealf(_q->a[i]); } return iir_group_delay(b, 3, a, 3, _fc) + 2.0; } liquid-dsp-1.7.0/src/filter/src/iirhilb.proto.c000066400000000000000000000252661474751757600214270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // infinite impulse response (IIR) Hilbert transform #include #include #include #include struct IIRHILB(_s) { // filter objects IIRFILT() filt_0; // upper filter branch IIRFILT() filt_1; // lower filter branch unsigned int state; // bookkeeping state }; // create iirhilb object // _ftype : filter type (e.g. LIQUID_IIRDES_BUTTER) // _n : filter order, _n > 0 // _ap : pass-band ripple [dB], _ap > 0 // _as : stop-band ripple [dB], _as > 0 IIRHILB() IIRHILB(_create)(liquid_iirdes_filtertype _ftype, unsigned int _n, float _ap, float _as) { // validate iirhilb inputs if (_n == 0) return liquid_error_config("iirhilb_create(), filter order must be greater than zero"); // allocate memory for main object IIRHILB() q = (IIRHILB()) malloc(sizeof(struct IIRHILB(_s))); // design filters int btype = LIQUID_IIRDES_LOWPASS; // filter band type int format = LIQUID_IIRDES_SOS; // filter coefficients format float fc = 0.25f; // cutoff frequency [normalized] float f0 = 0.0f; // center frequency [normalized] q->filt_0 = IIRFILT(_create_prototype)(_ftype,btype,format,_n,fc,f0,_ap,_as); q->filt_1 = IIRFILT(_create_prototype)(_ftype,btype,format,_n,fc,f0,_ap,_as); // reset internal state and return object IIRHILB(_reset)(q); return q; } // Create a default iirhilb object with a particular filter order. // _n : filter order, _n > 0 IIRHILB() IIRHILB(_create_default)(unsigned int _n) { // validate iirhilb inputs if (_n == 0) return liquid_error_config("iirhilb_create_default(), filter order must be greater than zero"); int ftype = LIQUID_IIRDES_BUTTER; // filter design type float Ap = 0.1f; // pass-band ripple [dB] float as = 60.0f; // stop-band attenuation [dB] return IIRHILB(_create)(ftype,_n,Ap,as); } IIRHILB() IIRHILB(_copy)(IIRHILB() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("iirhilb%s_copy(), object cannot be NULL", EXTENSION_SHORT); // create filter object and copy base parameters IIRHILB() q_copy = (IIRHILB()) malloc(sizeof(struct IIRHILB(_s))); memmove(q_copy, q_orig, sizeof(struct IIRHILB(_s))); // copy objects and return q_copy->filt_0 = IIRFILT(_copy)(q_orig->filt_0); q_copy->filt_1 = IIRFILT(_copy)(q_orig->filt_1); return q_copy; } // destroy iirhilb object int IIRHILB(_destroy)(IIRHILB() _q) { // destroy window buffers int rc_0 = IIRFILT(_destroy)(_q->filt_0); int rc_1 = IIRFILT(_destroy)(_q->filt_1); // free main object memory free(_q); return (rc_0 == LIQUID_OK && rc_1 == LIQUID_OK) ? LIQUID_OK : liquid_error(LIQUID_EINT,"iirhilb%s_destroy(), could not destroy object", EXTENSION_SHORT); } // print iirhilb object internals int IIRHILB(_print)(IIRHILB() _q) { printf("\n"); return LIQUID_OK; } // reset iirhilb object internal state int IIRHILB(_reset)(IIRHILB() _q) { // clear window buffers int rc_0 = IIRFILT(_reset)(_q->filt_0); int rc_1 = IIRFILT(_reset)(_q->filt_1); // reset state flag _q->state = 0; return (rc_0 == LIQUID_OK && rc_1 == LIQUID_OK) ? LIQUID_OK : liquid_error(LIQUID_EINT,"iirhilb%s_reset(), could not reset object", EXTENSION_SHORT); } // execute Hilbert transform (real to complex) // _q : iirhilb object // _x : real-valued input sample // _y : complex-valued output sample int IIRHILB(_r2c_execute)(IIRHILB() _q, T _x, T complex * _y) { // compute relevant output depending on state T yi = 0; T yq = 0; switch ( _q->state ) { case 0: IIRFILT(_execute)(_q->filt_0, _x, &yi); IIRFILT(_execute)(_q->filt_1, 0, &yq); *_y = 2*(yi + _Complex_I*yq); break; case 1: IIRFILT(_execute)(_q->filt_0, 0, &yi); IIRFILT(_execute)(_q->filt_1, -_x, &yq); *_y = 2*(-yq + _Complex_I*yi); break; case 2: IIRFILT(_execute)(_q->filt_0, -_x, &yi); IIRFILT(_execute)(_q->filt_1, 0, &yq); *_y = 2*(-yi - _Complex_I*yq); break; case 3: IIRFILT(_execute)(_q->filt_0, 0, &yi); IIRFILT(_execute)(_q->filt_1, _x, &yq); *_y = 2*( yq - _Complex_I*yi); break; default:; } // cycle through state _q->state = (_q->state + 1) & 0x3; return LIQUID_OK; } // Execute Hilbert transform (real to complex) on a block of samples int IIRHILB(_r2c_execute_block)(IIRHILB() _q, T * _x, unsigned int _n, T complex * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_r2c_execute)(_q, _x[i], _y+i); return LIQUID_OK; } // execute Hilbert transform (complex to real) // _q : iirhilb object // _y : complex-valued input sample // _x : real-valued output sample int IIRHILB(_c2r_execute)(IIRHILB() _q, T complex _x, T * _y) { // compute relevant output depending on state T yi = 0; T yq = 0; switch ( _q->state ) { case 0: IIRFILT(_execute)(_q->filt_0, crealf(_x), &yi); IIRFILT(_execute)(_q->filt_1, cimagf(_x), &yq); *_y = yi; break; case 1: IIRFILT(_execute)(_q->filt_0, cimagf(_x), &yi); IIRFILT(_execute)(_q->filt_1, -crealf(_x), &yq); *_y = -yq; break; case 2: IIRFILT(_execute)(_q->filt_0, -crealf(_x), &yi); IIRFILT(_execute)(_q->filt_1, -cimagf(_x), &yq); *_y = -yi; break; case 3: IIRFILT(_execute)(_q->filt_0, -cimagf(_x), &yi); IIRFILT(_execute)(_q->filt_1, crealf(_x), &yq); *_y = yq; break; default:; } // cycle through state _q->state = (_q->state + 1) & 0x3; return LIQUID_OK; } // Execute Hilbert transform (complex to real) on a block of samples int IIRHILB(_c2r_execute_block)(IIRHILB() _q, T complex * _x, unsigned int _n, T * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_c2r_execute)(_q, _x[i], _y+i); return LIQUID_OK; } // execute Hilbert transform decimator (real to complex) // _q : iirhilb object // _x : real-valued input array [size: 2 x 1] // _y : complex-valued output sample int IIRHILB(_decim_execute)(IIRHILB() _q, T * _x, T complex * _y) { // mix down by Fs/4 T xi = _q->state ? -_x[0] : _x[0]; T xq = _q->state ? _x[1] : -_x[1]; // upper branch T yi0, yi1; IIRFILT(_execute)(_q->filt_0, xi, &yi0); IIRFILT(_execute)(_q->filt_0, 0, &yi1); // lower branch T yq0, yq1; IIRFILT(_execute)(_q->filt_1, 0, &yq0); IIRFILT(_execute)(_q->filt_1, xq, &yq1); // set return value *_y = 2*(yi0 + _Complex_I*yq0); // toggle state flag _q->state = 1 - _q->state; return LIQUID_OK; } // execute Hilbert transform decimator (real to complex) on // a block of samples // _q : Hilbert transform object // _x : real-valued input array [size: 2*_n x 1] // _n : number of *output* samples // _y : complex-valued output array [size: _n x 1] int IIRHILB(_decim_execute_block)(IIRHILB() _q, T * _x, unsigned int _n, T complex * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_decim_execute)(_q, &_x[2*i], &_y[i]); return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) // _q : iirhilb object // _y : complex-valued input sample // _x : real-valued output array [size: 2 x 1] int IIRHILB(_interp_execute)(IIRHILB() _q, T complex _x, T * _y) { // upper branch T yi0, yi1; IIRFILT(_execute)(_q->filt_0, crealf(_x), &yi0); IIRFILT(_execute)(_q->filt_0, 0, &yi1); // lower branch T yq0, yq1; IIRFILT(_execute)(_q->filt_1, cimagf(_x), &yq0); IIRFILT(_execute)(_q->filt_1, 0, &yq1); // mix up by Fs/4 and retain real component // {yi0 + j yq0, yi1 + j yq1} // 0: Re{+1 (yi0 + j yq0), +j (yi1 + j yq1)} = Re{ yi0 + j yq0, -yq1 + j yi1} = { yi0, -yq1} // 1: Re{-1 (yi0 + j yq0), -j (yi1 + j yq1)} = Re{-yi0 - j yq0, yq1 - j yi1} = {-yi0, yq1} _y[0] = 2*(_q->state ? -yi0 : yi0); _y[1] = 2*(_q->state ? yq1 : -yq1); // toggle state flag _q->state = 1 - _q->state; return LIQUID_OK; } // execute Hilbert transform interpolator (complex to real) // on a block of samples // _q : Hilbert transform object // _x : complex-valued input array [size: _n x 1] // _n : number of *input* samples // _y : real-valued output array [size: 2*_n x 1] int IIRHILB(_interp_execute_block)(IIRHILB() _q, T complex * _x, unsigned int _n, T * _y) { unsigned int i; for (i=0; i<_n; i++) IIRHILB(_interp_execute)(_q, _x[i], &_y[2*i]); return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/iirinterp.proto.c000066400000000000000000000146771474751757600220160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // infinite impulse response interpolator // #include #include #include struct IIRINTERP(_s) { unsigned int M; // interpolation factor // TODO: use IIR polyphase filterbank IIRFILT() iirfilt; // filter object }; // create interpolator from external coefficients // _M : interpolation factor // _b : feed-back coefficients [size: _nb x 1] // _nb : feed-back coefficients length // _a : feed-forward coefficients [size: _na x 1] // _na : feed-forward coefficients length IIRINTERP() IIRINTERP(_create)(unsigned int _M, TC * _b, unsigned int _nb, TC * _a, unsigned int _na) { // validate input if (_M < 2) return liquid_error_config("iirinterp_%s_create(), interp factor must be greater than 1", EXTENSION_FULL); // allocate main object memory and set internal parameters IIRINTERP() q = (IIRINTERP()) malloc(sizeof(struct IIRINTERP(_s))); q->M = _M; // create filter q->iirfilt = IIRFILT(_create)(_b, _nb, _a, _na); // return interpolator object return q; } // create decimator with default Butterworth prototype // _M : decimation factor // _order : filter order IIRINTERP() IIRINTERP(_create_default)(unsigned int _M, unsigned int _order) { return IIRINTERP(_create_prototype)(_M, LIQUID_IIRDES_CHEBY2, LIQUID_IIRDES_LOWPASS, LIQUID_IIRDES_SOS, _order, 0.5f / (float)_M, // fc 0.0f, // f0 0.1f, // pass-band ripple, 60.0f); // stop-band attenuation } // create interpolator from prototype // _M : interpolation factor IIRINTERP() IIRINTERP(_create_prototype)(unsigned int _M, liquid_iirdes_filtertype _ftype, liquid_iirdes_bandtype _btype, liquid_iirdes_format _format, unsigned int _order, float _fc, float _f0, float _ap, float _as) { // validate input if (_M < 2) return liquid_error_config("iirinterp_%s_create_prototype(), interp factor must be greater than 1", EXTENSION_FULL); // allocate main object memory and set internal parameters IIRINTERP() q = (IIRINTERP()) malloc(sizeof(struct IIRINTERP(_s))); q->M = _M; // create filter q->iirfilt = IIRFILT(_create_prototype)(_ftype, _btype, _format, _order, _fc, _f0, _ap, _as); // set appropriate scale IIRFILT(_set_scale)(q->iirfilt, q->M); // return interpolator object return q; } // copy object IIRINTERP() IIRINTERP(_copy)(IIRINTERP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("iirinterp_%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy internal memory IIRINTERP() q_copy = (IIRINTERP()) malloc(sizeof(struct IIRINTERP(_s))); memmove(q_copy, q_orig, sizeof(struct IIRINTERP(_s))); // copy internal object and return q_copy->iirfilt = IIRFILT(_copy)(q_orig->iirfilt); return q_copy; } // destroy interpolator object int IIRINTERP(_destroy)(IIRINTERP() _q) { IIRFILT(_destroy)(_q->iirfilt); free(_q); return LIQUID_OK; } // print interpolator state int IIRINTERP(_print)(IIRINTERP() _q) { printf("\n", EXTENSION_FULL, _q->M); return LIQUID_OK; } // clear internal state int IIRINTERP(_reset)(IIRINTERP() _q) { return IIRFILT(_reset)(_q->iirfilt); } // execute interpolator // _q : interpolator object // _x : input sample // _y : output array [size: 1 x _M] int IIRINTERP(_execute)(IIRINTERP() _q, TI _x, TO * _y) { // TODO: use iirpfb unsigned int i; for (i=0; i<_q->M; i++) IIRFILT(_execute)(_q->iirfilt, i==0 ? _x : 0.0f, &_y[i]); return LIQUID_OK; } // execute interpolation on block of input samples // _q : iirinterp object // _x : input array [size: _n x 1] // _n : size of input array // _y : output sample array [size: _M*_n x 1] int IIRINTERP(_execute_block)(IIRINTERP() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // execute one input at a time with an output stride _M IIRINTERP(_execute)(_q, _x[i], &_y[i*_q->M]); } return LIQUID_OK; } // get system group delay at frequency _fc // _q : interpolator object // _f : frequency float IIRINTERP(_groupdelay)(IIRINTERP() _q, float _fc) { return IIRFILT(_groupdelay)(_q->iirfilt, _fc) / (float) (_q->M); } liquid-dsp-1.7.0/src/filter/src/lpc.c000066400000000000000000000107311474751757600174100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // lpc.c // // linear prediction coefficients // #include #include #include #include #include "liquid.internal.h" #define LIQUID_LEVINSON_MAXORDER (256) // compute the linear prediction coefficients for an input signal _x // _x : input signal [size: _n x 1] // _p : prediction filter order // _a : prediction filter [size: _p+1 x 1] // _e : prediction error variance [size: _p+1 x 1] void liquid_lpc(float * _x, unsigned int _n, unsigned int _p, float * _a, float * _g) { // validate input if (_p > _n) { liquid_error(LIQUID_EICONFIG,"liquid_lpc(), prediction filter length cannot exceed input signal length"); return; } // compute auto-correlation with lags float r[_p+1]; // auto-correlation array unsigned int i; for (i=0; i<_p+1; i++) { unsigned int lag = i; unsigned int j; r[i] = 0.0f; for (j=lag; j<_n; j++) r[i] += _x[j] * _x[j-lag]; printf("r[%3u] = %12.8f\n", i, r[i]); } // solve the Toeplitz inversion using Levinson-Durbin recursion liquid_levinson(r,_p,_a,_g); } // solve the Yule-Walker equations using Levinson-Durbin recursion // for _symmetric_ autocorrelation // _r : autocorrelation array [size: _p+1 x 1] // _p : filter order // _a : output coefficients [size: _p+1 x 1] // _e : error variance [size: _p+1 x 1] // // NOTES: // By definition _a[0] = 1.0 void liquid_levinson(float * _r, unsigned int _p, float * _a, float * _e) { // check allocation length if (_p > LIQUID_LEVINSON_MAXORDER) { liquid_error(LIQUID_EICONFIG,"liquid_levinson(), filter order (%u) exceeds maximum (%u)",_p,LIQUID_LEVINSON_MAXORDER); return; } // allocate arrays float a0[_p+1]; // temporary coefficients array, index [n] float a1[_p+1]; // temporary coefficients array, index [n-1] float e[_p+1]; // prediction error float k[_p+1]; // reflection coefficients // initialize k[0] = 1.0f; e[0] = _r[0]; unsigned int i; for (i=0; i<_p+1; i++) { a0[i] = (i==0) ? 1.0f : 0.0f; a1[i] = (i==0) ? 1.0f : 0.0f; } unsigned int n; for (n=1; n<_p+1; n++) { float q = 0.0f; for (i=0; i #include #include #include #include "liquid.internal.h" #define min(a,b) ((a)<(b)?(a):(b)) // // forward declaration of internal methods // // execute multi-stage interpolation int MSRESAMP(_interp_execute)(MSRESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _num_written); // execute multi-stage decimation int MSRESAMP(_decim_execute)(MSRESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _num_written); struct MSRESAMP(_s) { // user-defined parameters float rate; // re-sampling rate float as; // filter stop-band attenuation [dB] // type: interpolator or decimator int type; // run half-band resamplers as interp or decim // half-band resampler parameters unsigned int num_halfband_stages; // number of halfband stages MSRESAMP2() halfband_resamp; // multi-stage halfband resampler float rate_halfband; // halfband rate // arbitrary resampler parameters RESAMP() arbitrary_resamp; // arbitrary resampling object float rate_arbitrary; // clean-up resampling rate, in (0.5, 2.0) // internal buffers (ping-pong) unsigned int buffer_len; // length of each buffer T * buffer; // buffer[0] unsigned int buffer_index; // index of buffer }; // create msresamp object // TODO: add signal bandwidth parameter? // TODO: add center frequency parameter; facilitates DDS object synthesis // _r : resampling rate [output/input] // _as : stop-band attenuation MSRESAMP() MSRESAMP(_create)(float _r, float _as) { // validate input if (_r <= 0.0f) return liquid_error_config("msresamp_%s_create(), resampling rate must be greater than zero", EXTENSION_FULL); // create object MSRESAMP() q = (MSRESAMP()) malloc(sizeof(struct MSRESAMP(_s))); // set internal properties q->rate = _r; // composite rate q->as = _as; // stop-band suppression // decimation or interpolation? q->type = (q->rate > 1.0f) ? LIQUID_RESAMP_INTERP : LIQUID_RESAMP_DECIM; // compute derived values q->rate_arbitrary = q->rate; q->rate_halfband = 1.0f; q->num_halfband_stages = 0; switch(q->type) { case LIQUID_RESAMP_INTERP: while (q->rate_arbitrary > 2.0f) { q->num_halfband_stages++; q->rate_halfband *= 2.0f; q->rate_arbitrary *= 0.5f; } break; case LIQUID_RESAMP_DECIM: while (q->rate_arbitrary < 0.5f) { q->num_halfband_stages++; q->rate_halfband *= 0.5f; q->rate_arbitrary *= 2.0f; } break; default:; } // allocate memory for buffer q->buffer_len = 4 + (1 << q->num_halfband_stages); q->buffer = (T*) malloc( q->buffer_len*sizeof(T) ); // create single multi-stage half-band resampler object // TODO: compute appropriate cut-off frequency q->halfband_resamp = MSRESAMP2(_create)(q->type, q->num_halfband_stages, 0.4f, 0.0f, q->as); // create arbitrary resampler object // TODO: compute appropriate parameters q->arbitrary_resamp = RESAMP(_create)(q->rate_arbitrary, 7, min(0.515f*q->rate_arbitrary,0.49f), q->as, 256); // reset object MSRESAMP(_reset)(q); // return main object return q; } // copy object MSRESAMP() MSRESAMP(_copy)(MSRESAMP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("msresamp_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values MSRESAMP() q_copy = (MSRESAMP()) malloc(sizeof(struct MSRESAMP(_s))); memmove(q_copy, q_orig, sizeof(struct MSRESAMP(_s))); // copy internal objects q_copy->halfband_resamp = MSRESAMP2(_copy)(q_orig->halfband_resamp); q_copy->arbitrary_resamp = RESAMP(_copy)(q_orig->arbitrary_resamp); // create and copy buffer q_copy->buffer = (T*) malloc( q_copy->buffer_len*sizeof(T) ); memmove(q_copy->buffer, q_orig->buffer, q_copy->buffer_len*sizeof(T) ); // return object return q_copy; } // destroy msresamp object, freeing all internally-allocated memory int MSRESAMP(_destroy)(MSRESAMP() _q) { // free buffer free(_q->buffer); // destroy arbitrary resampler RESAMP(_destroy)(_q->arbitrary_resamp); // destroy multi-stage half-band resampler object MSRESAMP2(_destroy)(_q->halfband_resamp); // destroy main object free(_q); return LIQUID_OK; } // print msresamp object internals int MSRESAMP(_print)(MSRESAMP() _q) { printf("\n", EXTENSION_FULL, _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim", _q->num_halfband_stages, _q->rate); #if 0 printf("multi-stage resampler\n"); printf(" composite rate : %12.10f\n", _q->rate); printf(" type : %s\n", _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim"); printf(" num halfband stages : %u\n", _q->num_halfband_stages); printf(" halfband rate : %s%u\n", _q->type == LIQUID_RESAMP_INTERP ? "" : "1/", 1<<_q->num_halfband_stages); printf(" arbitrary rate : %12.10f\n", _q->rate_arbitrary); printf(" stages:\n"); //float delay_halfband = MSRESAMP2(_get_delay)(_q->halfband_resamp); //float delay_arbitrary = RESAMP(_get_delay)(_q->arbitrary_resamp); // print each stage unsigned int stage=0; float r = 1.0f; // accumulated rate // arbitrary (interpolator) if (_q->type == LIQUID_RESAMP_INTERP) { float rate = _q->rate_arbitrary; r *= rate; // update rate printf(" [%2u, r=%11.7f] : arbitrary, r=%12.8f\n", stage, r, rate); stage++; } // print stages of half-band resampling unsigned int i; for (i=0; i<_q->num_halfband_stages; i++) { float rate = _q->type == LIQUID_RESAMP_INTERP ? 2.0f : 0.5f; r *= rate; printf(" [%2u, r=%11.7f] : halfband, r=%5.1f\n", stage, r, rate); stage++; } // arbitrary (decimator) if (_q->type == LIQUID_RESAMP_DECIM) { float rate = _q->rate_arbitrary; r *= rate; printf(" [%2u, r=%11.7f] : arbitrary, r=%12.8f\n", stage, r, rate); stage++; } #endif return LIQUID_OK; } // reset msresamp object internals, clear filters and nco phase int MSRESAMP(_reset)(MSRESAMP() _q) { // reset multi-stage half-band resampler object MSRESAMP2(_reset)(_q->halfband_resamp); // reset arbitrary resampler RESAMP(_reset)(_q->arbitrary_resamp); // reset buffer write pointer _q->buffer_index = 0; // TODO: clear internal buffers? return LIQUID_OK; } // get filter delay (output samples) float MSRESAMP(_get_delay)(MSRESAMP() _q) { float delay_halfband = MSRESAMP2(_get_delay)(_q->halfband_resamp); float delay_arbitrary = RESAMP(_get_delay)(_q->arbitrary_resamp); #if 0 printf("halfband : rate=%12.8f, delay=%12.8f\n", (float)(1<<_q->num_halfband_stages), delay_halfband); printf("arbitrary : rate=%12.8f, delay=%12.8f\n", _q->rate_arbitrary, delay_arbitrary); #endif // compute delay based on interpolation or decimation type if (_q->num_halfband_stages == 0) { // no half-band stages; just arbitrary resampler delay return delay_arbitrary; } else if (_q->type == LIQUID_RESAMP_INTERP) { // interpolation return delay_halfband / _q->rate_arbitrary + delay_arbitrary; } else { // decimation unsigned int M = 1 << _q->num_halfband_stages; return delay_halfband + M*delay_arbitrary; } return 0.0f; } // get resampling rate float MSRESAMP(_get_rate)(MSRESAMP() _q) { return _q->rate; } // Get the number of output samples given current state and input buffer size. unsigned int MSRESAMP(_get_num_output)(MSRESAMP() _q, unsigned int _num_input) { if (_q->type == LIQUID_RESAMP_INTERP) { // compute number of arbitrary resampler outputs unsigned int n = RESAMP(_get_num_output)(_q->arbitrary_resamp,_num_input); // scale by half-band interpolation stage return n * (1 << _q->num_halfband_stages); } else { // compute number of outputs from half-band decimation stage // NOTE: this compensates for the number of samples already buffers unsigned int n = (_q->buffer_index+_num_input) >> _q->num_halfband_stages; return RESAMP(_get_num_output)(_q->arbitrary_resamp,n); } return 0; // should never occur } // execute multi-stage resampler // _q : msresamp object // _x : input sample array // _y : output sample array // _ny : number of samples written to _y int MSRESAMP(_execute)(MSRESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { switch(_q->type) { case LIQUID_RESAMP_INTERP: return MSRESAMP(_interp_execute)(_q, _x, _nx, _y, _ny); case LIQUID_RESAMP_DECIM: return MSRESAMP(_decim_execute)(_q, _x, _nx, _y, _ny); default:; } return liquid_error(LIQUID_EINT,"msresamp_%s_execute(), unknown/unsupported internal state",EXTENSION_FULL); } // // internal methods // // execute multi-stage resampler as interpolator // _q : msresamp object // _x : input sample array // _y : output sample array // _nw : number of samples written to _y int MSRESAMP(_interp_execute)(MSRESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { unsigned int i; unsigned int nw; unsigned int ny = 0; // operate one sample at a time so that we don't overflow the internal // buffer for (i=0; i<_nx; i++) { // run arbitrary resampler RESAMP(_execute)(_q->arbitrary_resamp, _x[i], _q->buffer, &nw); // run multi-stage half-band resampler on each output sample unsigned int k; for (k=0; khalfband_resamp, &_q->buffer[k], &_y[ny]); // increase output counter by halfband interpolation rate ny += 1 << _q->num_halfband_stages; } } // set return value for number of samples written *_ny = ny; return LIQUID_OK; } // execute multi-stage resampler as decimator // _q : msresamp object // _x : input sample array // _y : output sample array // _nw : number of samples written to _y int MSRESAMP(_decim_execute)(MSRESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { unsigned int i; unsigned int M = 1 << _q->num_halfband_stages; unsigned int nw; // number of samples written for arbitrary resamp unsigned int ny = 0; // running counter of output samples TO halfband_output; // single half-band decimator output sample // write samples to buffer until it contains 2^num_halfband_stages // TODO: write block of samples for (i=0; i<_nx; i++) { // push sample into buffer _q->buffer[_q->buffer_index++] = _x[i]; // check if buffer has 'M' elements if (_q->buffer_index == M) { // run half-band decimation, producing a single output MSRESAMP2(_execute)(_q->halfband_resamp, _q->buffer, &halfband_output); // run resulting sample through arbitrary resampler RESAMP(_execute)(_q->arbitrary_resamp, halfband_output, &_y[ny], &nw); // increment output counter ny += nw; // reset buffer index _q->buffer_index = 0; } } // set return value for number of samples written *_ny = ny; return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/msresamp2.proto.c000066400000000000000000000357261474751757600217200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // multi-stage half-band resampler // #include #include #include #include #include "liquid.internal.h" // // forward declaration of internal methods // struct MSRESAMP2(_s) { // user-defined parameters liquid_resamp_type type; // resampler type (LIQUID_RESAMP_INTERP, LIQUID_RESAMP_DECIM) unsigned int num_stages; // number of half-band stages float fc; // initial cut-off frequency float f0; // initial center frequency float as; // stop-band attenuation // derived values unsigned int M; // integer resampling rate: 2^num_stages // half-band resamplers float * fc_stage; // cut-off frequency for each stage float * f0_stage; // center frequency for each stage float * as_stage; // stop-band attenuation for each stage unsigned int * m_stage; // filter semi-length for each stage RESAMP2() * resamp2; // array of half-band resamplers T * buffer0; // buffer[0] T * buffer1; // buffer[1] unsigned int buffer_index; // index of buffer float zeta; // scaling factor }; // execute multi-stage resampler as interpolator // _q : msresamp object // _x : input sample // _y : output sample array [size:2^_num_stages x 1] int MSRESAMP2(_interp_execute)(MSRESAMP2() _q, TI _x, TO * _y); // execute multi-stage resampler as decimator // _q : msresamp object // _x : input sample array [size: 2^_num_stages x 1] // _y : output sample pointer int MSRESAMP2(_decim_execute)(MSRESAMP2() _q, TI * _x, TO * _y); // create multi-stage half-band resampler // _type : resampler type (e.g. LIQUID_RESAMP_DECIM) // _num_stages : number of resampling stages // _fc : filter cut-off frequency 0 < _fc < 0.5 // _f0 : filter center frequency // _as : stop-band attenuation [dB] MSRESAMP2() MSRESAMP2(_create)(int _type, unsigned int _num_stages, float _fc, float _f0, float _as) { // validate input if (_num_stages > 16) return liquid_error_config("msresamp2_%s_create(), number of stages should not exceed 16", EXTENSION_FULL); if ( _fc <= 0.0f || _fc >= 0.5f ) return liquid_error_config("msresamp2_%s_create(), cut-off frequency must be in (0,0.5)", EXTENSION_FULL); if ( _f0 != 0. ) return liquid_error_config("msresamp2_%s_create(), non-zero center frequency not yet supported", EXTENSION_FULL); // truncate cut-off frequency to avoid excessive filter response if ( _fc > 0.499f ) _fc = 0.499f; // check center frequency unsigned int i; // create object MSRESAMP2() q = (MSRESAMP2()) malloc(sizeof(struct MSRESAMP2(_s))); // set internal properties q->type = _type == LIQUID_RESAMP_INTERP ? LIQUID_RESAMP_INTERP : LIQUID_RESAMP_DECIM; q->num_stages = _num_stages; q->fc = _fc; q->f0 = _f0; q->as = _as; // derived values q->M = 1 << q->num_stages; q->zeta = 1.0f / (float)(q->M); // allocate memory for buffers q->buffer0 = (T*) malloc( q->M * sizeof(T) ); q->buffer1 = (T*) malloc( q->M * sizeof(T) ); // allocate arrays for half-band resampler parameters q->fc_stage = (float*) malloc(q->num_stages*sizeof(float) ); q->f0_stage = (float*) malloc(q->num_stages*sizeof(float) ); q->as_stage = (float*) malloc(q->num_stages*sizeof(float) ); q->m_stage = (unsigned int*) malloc(q->num_stages*sizeof(unsigned int)); // determine half-band resampler parameters float fc = q->fc; // cut-off frequency float f0 = q->f0; // center frequency float as = q->as+5; // small margin for (i=0; inum_stages; i++) { // compute parameters based on filter requirements; fc = (i==1) ? (0.5-fc)/2.0f : 0.5f*fc; // cut-off frequency f0 = 0.5f*f0; // center frequency float ft = 2*(0.25f - fc); // two-sided transition bandwidth // estimate required filter length unsigned int h_len = estimate_req_filter_len(ft, as); unsigned int m = ceilf( (float)(h_len-1) / 4.0f ); //printf(" >>> fc: %8.6f, ft: %8.6f, h_len : %u (m=%u)\n", fc, ft, h_len, m); q->fc_stage[i] = fc; // filter pass-band q->f0_stage[i] = f0; // filter center frequency q->as_stage[i] = as; // filter stop-band attenuation q->m_stage[i] = m < 3 ? 3 : m; // minimum } // create half-band resampler objects q->resamp2 = (RESAMP2()*) malloc(q->num_stages*sizeof(RESAMP2())); for (i=0; inum_stages; i++) { // create half-band resampler q->resamp2[i] = RESAMP2(_create)(q->m_stage[i], q->f0_stage[i], q->as_stage[i]); } // reset object MSRESAMP2(_reset)(q); // return main object return q; } // copy object MSRESAMP2() MSRESAMP2(_copy)(MSRESAMP2() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("msresamp2_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values MSRESAMP2() q_copy = (MSRESAMP2()) malloc(sizeof(struct MSRESAMP2(_s))); memmove(q_copy, q_orig, sizeof(struct MSRESAMP2(_s))); // allocate memory for buffers q_copy->buffer0 = (T*) malloc( q_copy->M * sizeof(T) ); q_copy->buffer1 = (T*) malloc( q_copy->M * sizeof(T) ); // allocate arrays for half-band resampler parameters q_copy->fc_stage = (float*) malloc(q_copy->num_stages*sizeof(float) ); q_copy->f0_stage = (float*) malloc(q_copy->num_stages*sizeof(float) ); q_copy->as_stage = (float*) malloc(q_copy->num_stages*sizeof(float) ); q_copy->m_stage = (unsigned int*) malloc(q_copy->num_stages*sizeof(unsigned int)); // copy values memmove(q_copy->fc_stage, q_orig->fc_stage, q_copy->num_stages*sizeof(float) ); memmove(q_copy->f0_stage, q_orig->f0_stage, q_copy->num_stages*sizeof(float) ); memmove(q_copy->as_stage, q_orig->as_stage, q_copy->num_stages*sizeof(float) ); memmove(q_copy->m_stage , q_orig->m_stage , q_copy->num_stages*sizeof(unsigned int)); // create array of half-band resamplers and copy objects q_copy->resamp2 = (RESAMP2()*) malloc(q_copy->num_stages*sizeof(RESAMP2())); unsigned int i=0; for (i=0; inum_stages; i++) q_copy->resamp2[i] = RESAMP2(_copy)(q_orig->resamp2[i]); // return object return q_copy; } // destroy msresamp2 object, freeing all internally-allocated memory int MSRESAMP2(_destroy)(MSRESAMP2() _q) { // free buffers free(_q->buffer0); free(_q->buffer1); // free half-band resampler design parameter arrays free(_q->fc_stage); free(_q->f0_stage); free(_q->as_stage); free(_q->m_stage); // destroy/free half-band resampler objects unsigned int i; for (i=0; i<_q->num_stages; i++) RESAMP2(_destroy)(_q->resamp2[i]); // free half-band resampler array free(_q->resamp2); // destroy main object free(_q); return LIQUID_OK; } // print msresamp2 object internals int MSRESAMP2(_print)(MSRESAMP2() _q) { printf("\n", EXTENSION_FULL, _q->type == LIQUID_RESAMP_INTERP ? "interp" : "decim", _q->num_stages, MSRESAMP2(_get_rate)(_q)); #if 0 printf("multi-stage half-band resampler:\n"); printf(" type : %s\n", _q->type == LIQUID_RESAMP_DECIM ? "decimator" : "interpolator"); printf(" number of stages : %u stage%s\n", _q->num_stages, _q->num_stages == 1 ? "" : "s"); printf(" cut-off frequency, fc : %12.8f Fs\n", _q->fc); printf(" center frequency, f0 : %12.8f Fs\n", _q->f0); printf(" stop-band attenuation : %.2f dB\n", _q->as); printf(" delay (total) : %.3f samples\n", MSRESAMP2(_get_delay)(_q)); // print each stage unsigned int i; for (i=0; i<_q->num_stages; i++) { // get index of stage (reversed for decimator) unsigned int g = _q->type == LIQUID_RESAMP_INTERP ? i : _q->num_stages-i-1; // print stage information printf(" stage[%2u] {m=%3u, as=%6.2f dB, fc=%6.3f, f0=%6.3f}\n", i, _q->m_stage[g], _q->as_stage[g], _q->fc_stage[g], _q->f0_stage[g]); } #endif return LIQUID_OK; } // reset msresamp2 object internals, clear filters and nco phase int MSRESAMP2(_reset)(MSRESAMP2() _q) { // reset half-band resampler objects unsigned int i; for (i=0; i<_q->num_stages; i++) RESAMP2(_reset)(_q->resamp2[i]); // reset buffer write pointer _q->buffer_index = 0; // NOTE: not necessary to clear internal buffers return LIQUID_OK; } // Get multi-stage half-band resampling rate float MSRESAMP2(_get_rate)(MSRESAMP2() _q) { return _q->type == LIQUID_RESAMP_INTERP ? (float)(_q->M) : 1.0f/(float)(_q->M); } // Get number of half-band resampling stages in object unsigned int MSRESAMP2(_get_num_stages)(MSRESAMP2() _q) { return _q->num_stages; } // Get resampling type (LIQUID_RESAMP_DECIM, LIQUID_RESAMP_INTERP) int MSRESAMP2(_get_type)(MSRESAMP2() _q) { return _q->type; } // get group delay (number of output samples) float MSRESAMP2(_get_delay)(MSRESAMP2() _q) { // initialize delay float delay = 0; unsigned int i; // add half-band resampling delay if (_q->type == LIQUID_RESAMP_INTERP) { // interpolator for (i=0; i<_q->num_stages; i++) { // filter semi-length unsigned int m = _q->m_stage[_q->num_stages-i-1]; delay *= 0.5f; delay += m; } } else { // decimator for (i=0; i<_q->num_stages; i++) { // filter semi-length unsigned int m = _q->m_stage[i]; delay *= 2; delay += 2*m - 1; } } return delay; } // execute multi-stage resampler as interpolator // _q : msresamp object // _x : input sample // _y : output sample array [size:2^_num_stages x 1] int MSRESAMP2(_execute)(MSRESAMP2() _q, TI * _x, TO * _y) { // switch resampling method based on type if (_q->num_stages == 0) { // pass through _y[0] = _x[0]; return LIQUID_OK; } else if (_q->type == LIQUID_RESAMP_INTERP) { // execute multi-stage resampler as interpolator return MSRESAMP2(_interp_execute)(_q, _x[0], _y); } else { // execute multi-stage resampler as decimator return MSRESAMP2(_decim_execute)(_q, _x, _y); } return liquid_error(LIQUID_EINT,"msresamp2_%s_execute(), invalid internal mode",EXTENSION_FULL); } // // internal methods // // execute multi-stage resampler as interpolator // _q : msresamp object // _x : input sample // _y : output sample array [size:2^_num_stages x 1] int MSRESAMP2(_interp_execute)(MSRESAMP2() _q, TI _x, TO * _y) { // buffer pointers (initialize BOTH to _q->buffer0); T * b0 = _q->buffer0; // input buffer pointer T * b1 = _q->buffer1; // output buffer pointer // set input sample in first buffer b0[0] = _x; unsigned int s; // half-band decimator stage counter unsigned int k; // number of inputs for this stage for (s=0; s<_q->num_stages; s++) { // compute number of inputs for this stage k = 1 << s; // set final stage output as supplied output pointer if (s == _q->num_stages-1) b1 = _y; // run half-band stages as interpolators unsigned int i; for (i=0; iresamp2[s], b0[i], &b1[2*i]); // toggle output buffer pointers b0 = (s % 2) == 0 ? _q->buffer1 : _q->buffer0; b1 = (s % 2) == 0 ? _q->buffer0 : _q->buffer1; } return LIQUID_OK; } // execute multi-stage resampler as decimator // _q : msresamp object // _x : input sample array [size: 2^_num_stages x 1] // _y : output sample pointer int MSRESAMP2(_decim_execute)(MSRESAMP2() _q, TI * _x, TO * _y) { // buffer pointers (initialize BOTH to _q->buffer0); T * b0 = _x; // input buffer pointer T * b1 = _q->buffer1; // output buffer pointer unsigned int s; // half-band decimator stage counter unsigned int k; // number of outputs for this stage for (s=0; s<_q->num_stages; s++) { // compute number of outputs for this stage k = 1 << (_q->num_stages - s - 1); // run half-band stages as decimators unsigned int i; unsigned int g = _q->num_stages-s-1; // reversed resampler index for (i=0; iresamp2[g], &b0[2*i], &b1[i]); // toggle output buffer pointers b0 = (s % 2) == 0 ? _q->buffer1 : _q->buffer0; b1 = (s % 2) == 0 ? _q->buffer0 : _q->buffer1; } // set single output sample and scale appropriately *_y = b0[0] * _q->zeta; return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/ordfilt.proto.c000066400000000000000000000156001474751757600214370ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // ordfilt : order-statistics filter // #include #include #include // defined: // ORDFILT() name-mangling macro // T coefficients type // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro #define LIQUID_ORDFILT_USE_WINDOW 1 #if LIQUID_ORDFILT_USE_WINDOW int ordfilt_sort_compf(const void * _v1, const void * _v2) { return *(float*)_v1 > *(float*)_v2 ? 1 : -1; } #endif // ordfilt object structure struct ORDFILT(_s) { unsigned int n; // buffer length unsigned int k; // sample index of order statistic #if LIQUID_ORDFILT_USE_WINDOW // simple to implement but much slower WINDOW() buf; // input buffer TI * buf_sorted; // input buffer (sorted) #else // trickier to implement but faster TI * buf; // input buffer uint16_t * buf_index; // buffer index of sorted values #endif }; // Create a order-statistic filter (ordfilt) object by specifying // the buffer size and appropriate sample index of order statistic. // _n : buffer size // _k : sample index for order statistic, 0 <= _k < _n ORDFILT() ORDFILT(_create)(unsigned int _n, unsigned int _k) { // validate input if (_n == 0) return liquid_error_config("ordfilt_%s_create(), filter length must be greater than zero", EXTENSION_FULL); if (_k >= _n) return liquid_error_config("ordfilt_%s_create(), filter index must be in [0,n-1]", EXTENSION_FULL); // create filter object and initialize ORDFILT() q = (ORDFILT()) malloc(sizeof(struct ORDFILT(_s))); q->n = _n; q->k = _k; #if LIQUID_ORDFILT_USE_WINDOW // create window (internal buffer) q->buf = WINDOW(_create)(q->n); q->buf_sorted = (TI*) malloc(q->n * sizeof(TI)); #else #endif // reset filter state (clear buffer) ORDFILT(_reset)(q); return q; } // Create a median filter by specifying buffer semi-length. // _m : buffer semi-length ORDFILT() ORDFILT(_create_medfilt)(unsigned int _m) { return ORDFILT(_create)(2*_m+1, _m); } // copy object ORDFILT() ORDFILT(_copy)(ORDFILT() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("ordfilt_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy base parameters ORDFILT() q_copy = (ORDFILT()) malloc(sizeof(struct ORDFILT(_s))); memmove(q_copy, q_orig, sizeof(struct ORDFILT(_s))); #if LIQUID_ORDFILT_USE_WINDOW // copy window q_copy->buf = WINDOW(_copy)(q_orig->buf); q_copy->buf_sorted = (TI*) liquid_malloc_copy(q_orig->buf_sorted, q_orig->n, sizeof(TI)); #else // copy buffers q_copy->buf_ = (TI*) liquid_malloc_copy(q_orig->buf, q_orig->n, sizeof(TI)); q_copy->buf_index = (uint16_t*) liquid_malloc_copy(q_orig->buf_index, q_orig->n, sizeof(uint16_t)); #endif return q_copy; } // destroy ordfilt object int ORDFILT(_destroy)(ORDFILT() _q) { #if LIQUID_ORDFILT_USE_WINDOW WINDOW(_destroy)(_q->buf); free(_q->buf_sorted); #else #endif free(_q); return LIQUID_OK; } // reset internal state of filter object int ORDFILT(_reset)(ORDFILT() _q) { #if LIQUID_ORDFILT_USE_WINDOW return WINDOW(_reset)(_q->buf); #else #endif return LIQUID_OK; } // print filter object internals (taps, buffer) int ORDFILT(_print)(ORDFILT() _q) { printf("\n", EXTENSION_FULL, _q->n, _q->k); return LIQUID_OK; } // push sample into filter object's internal buffer // _q : filter object // _x : input sample int ORDFILT(_push)(ORDFILT() _q, TI _x) { #if LIQUID_ORDFILT_USE_WINDOW return WINDOW(_push)(_q->buf, _x); #else #endif return LIQUID_OK; } // Write block of samples into object's internal buffer // _q : filter object // _x : array of input samples, [size: _n x 1] // _n : number of input elements int ORDFILT(_write)(ORDFILT() _q, TI * _x, unsigned int _n) { #if LIQUID_ORDFILT_USE_WINDOW return WINDOW(_write)(_q->buf, _x, _n); #else #endif return LIQUID_OK; } // Execute on the filter's internal buffer // _q : filter object // _y : output sample pointer int ORDFILT(_execute)(ORDFILT() _q, TO * _y) { #if LIQUID_ORDFILT_USE_WINDOW // read buffer (retrieve pointer to aligned memory array) TI *r; WINDOW(_read)(_q->buf, &r); // copy to buffer and sort memmove(_q->buf_sorted, r, _q->n*sizeof(TI)); // sort results qsort((void*)_q->buf_sorted, _q->n, sizeof(TI), ªilt_sort_compf); // save output *_y = _q->buf_sorted[_q->k]; #else #endif return LIQUID_OK; } // Execute filter on one sample, equivalent to push() and execute() // _q : filter object // _x : single input sample // _y : pointer to single output sample int ORDFILT(_execute_one)(ORDFILT() _q, TI _x, TO * _y) { ORDFILT(_push)(_q, _x); return ORDFILT(_execute)(_q, _y); } // execute the filter on a block of input samples; the // input and output buffers may be the same // _q : filter object // _x : pointer to input array [size: _n x 1] // _n : number of input, output samples // _y : pointer to output array [size: _n x 1] int ORDFILT(_execute_block)(ORDFILT() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { // push sample into filter ORDFILT(_push)(_q, _x[i]); // compute output sample ORDFILT(_execute)(_q, &_y[i]); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/rcos.c000066400000000000000000000051241474751757600176000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Design raised-cosine filter // #include #include #include #include "liquid.internal.h" // Design Nyquist raised-cosine filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_rcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { if ( _k < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rcos(): k must be greater than 0"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rcos(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rcos(): beta must be in [0,1]"); unsigned int n; float z, t1, t2, t3; float nf, kf, mf; unsigned int h_len = 2*_k*_m + 1; // Calculate filter coefficients for (n=0; n #include #include #include #define DEBUG_RESAMP_PRINT 0 // main object struct RESAMP(_s) { // filter design parameters unsigned int m; // filter semi-length, h_len = 2*m + 1 float as; // filter stop-band attenuation float fc; // filter cutoff frequency // internal state variables float r; // resampling rate uint32_t step; // step size (quantized resampling rate) uint32_t phase; // sampling phase unsigned int bits_index; unsigned int npfb; // 256 FIRPFB() pfb; // filter bank }; // create arbitrary resampler // _rate : resampling rate // _m : prototype filter semi-length // _fc : prototype filter cutoff frequency, fc in (0, 0.5) // _as : prototype filter stop-band attenuation [dB] (e.g. 60) // _npfb : number of filters in polyphase filterbank RESAMP() RESAMP(_create)(float _rate, unsigned int _m, float _fc, float _as, unsigned int _npfb) { // validate input if (_rate <= 0) return liquid_error_config("resamp_%s_create(), resampling rate must be greater than zero", EXTENSION_FULL); if (_m == 0) return liquid_error_config("resamp_%s_create(), filter semi-length must be greater than zero", EXTENSION_FULL); if (_fc <= 0.0f || _fc >= 0.5f) return liquid_error_config("resamp_%s_create(), filter cutoff must be in (0,0.5)", EXTENSION_FULL); if (_as <= 0.0f) return liquid_error_config("resamp_%s_create(), filter stop-band suppression must be greater than zero", EXTENSION_FULL); // check number of bits representing filter bank resolution unsigned int bits = liquid_nextpow2(_npfb); if (bits < 1 || bits > 16) return liquid_error_config("resamp_%s_create(), number of filter banks must be in (2^0,2^16)", EXTENSION_FULL); // allocate memory for resampler RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); // set rate using formal method (specifies output stride // value 'del') RESAMP(_set_rate)(q, _rate); // set properties q->m = _m; // prototype filter semi-length q->fc = _fc; // prototype filter cutoff frequency q->as = _as; // prototype filter stop-band attenuation q->bits_index = bits; // number of bits representing filters in bank q->npfb = 1<bits_index; // number of filters in bank // design filter unsigned int n = 2*q->m*q->npfb+1; float hf[n]; TC h[n]; liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->as,0.0f,hf); // normalize filter coefficients by DC gain unsigned int i; float gain=0.0f; for (i=0; inpfb)/(gain); // copy to type-specific array, applying gain for (i=0; ipfb = FIRPFB(_create)(q->npfb,h,n-1); // reset object and return RESAMP(_reset)(q); return q; } // create arbitrary resampler object with a specified input // resampling rate and default parameters // m (filter semi-length) = 7 // fc (filter cutoff frequency) = 0.25 // as (filter stop-band attenuation) = 60 dB // npfb (number of filters in the bank) = 256 RESAMP() RESAMP(_create_default)(float _rate) { // validate input if (_rate <= 0) return liquid_error_config("resamp_%s_create_default(), resampling rate must be greater than zero", EXTENSION_FULL); // det default parameters unsigned int m = 7; float fc = 0.25f; float as = 60.0f; unsigned int npfb = 256; // create and return resamp object return RESAMP(_create)(_rate, m, fc, as, npfb); } // copy object RESAMP() RESAMP(_copy)(RESAMP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("resamp_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values RESAMP() q_copy = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); memmove(q_copy, q_orig, sizeof(struct RESAMP(_s))); // copy filter bank q_copy->pfb = FIRPFB(_copy)(q_orig->pfb); // return object return q_copy; } // free arbitrary resampler object int RESAMP(_destroy)(RESAMP() _q) { // free polyphase filterbank FIRPFB(_destroy)(_q->pfb); // free main object memory free(_q); return LIQUID_OK; } // print resampler object int RESAMP(_print)(RESAMP() _q) { printf("\n", EXTENSION_FULL, _q->r, _q->m, _q->as, _q->fc, _q->npfb); return LIQUID_OK; } // reset resampler object int RESAMP(_reset)(RESAMP() _q) { // reset state _q->phase = 0; // clear filterbank return FIRPFB(_reset)(_q->pfb); } // get resampler filter delay (semi-length m) unsigned int RESAMP(_get_delay)(RESAMP() _q) { return _q->m; } // set rate of arbitrary resampler // _q : resampling object // _rate : new sampling rate, _rate > 0 int RESAMP(_set_rate)(RESAMP() _q, float _rate) { if (_rate <= 0) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_rate(), resampling rate must be greater than zero", EXTENSION_FULL); } else if (_rate < 0.004f || _rate > 250.0f) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_rate(), resampling rate must be in [0.004,250]", EXTENSION_FULL); } // set internal rate _q->r = _rate; // set output stride // TODO: ensure step is reasonable size _q->step = (uint32_t)round((1<<24)/_q->r); return LIQUID_OK; } // get rate of arbitrary resampler float RESAMP(_get_rate)(RESAMP() _q) { return _q->r; } // adjust resampling rate int RESAMP(_adjust_rate)(RESAMP() _q, float _gamma) { if (_gamma <= 0) return liquid_error(LIQUID_EICONFIG,"resamp_%s_adjust_rate(), resampling adjustment (%12.4e) must be greater than zero", EXTENSION_FULL, _gamma); // adjust internal rate return RESAMP(_set_rate)(_q, _q->r * _gamma); } // set resampling timing phase // _q : resampling object // _tau : sample timing int RESAMP(_set_timing_phase)(RESAMP() _q, float _tau) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_timing_phase(), method not implemented",EXTENSION_FULL); if (_tau < -1.0f || _tau > 1.0f) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_timing_phase(), timing phase must be in [-1,1], is %f.",EXTENSION_FULL,_tau); } // TODO: set internal timing phase (quantized) //_q->tau = _tau; return LIQUID_OK; } // adjust resampling timing phase // _q : resampling object // _delta : sample timing adjustment int RESAMP(_adjust_timing_phase)(RESAMP() _q, float _delta) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_adjust_timing_phase(), method not implemented",EXTENSION_FULL); if (_delta < -1.0f || _delta > 1.0f) { return liquid_error(LIQUID_EICONFIG,"resamp_%s_adjust_timing_phase(), timing phase adjustment must be in [-1,1], is %f.",EXTENSION_FULL,_delta); } // TODO: adjust internal timing phase (quantized) //_q->tau += _delta; return LIQUID_OK; } // Get the number of output samples given current state and input buffer size. unsigned int RESAMP(_get_num_output)(RESAMP() _q, unsigned int _num_input) { // count the number of rollovers uint32_t phase = _q->phase; unsigned int i, num_output=0; for (i=0; i<_num_input; i++) { while (phase <= 0x00ffffff) { num_output++; phase += _q->step; } phase -= (1<<24); } return num_output; } // run arbitrary resampler // _q : resampling object // _x : single input sample // _y : output array // _num_written: number of samples written to output int RESAMP(_execute)(RESAMP() _q, TI _x, TO * _y, unsigned int * _num_written) { // push input FIRPFB(_push)(_q->pfb, _x); // continue to produce output unsigned int n=0; while (_q->phase <= 0x00ffffff) { //unsigned int index = (_q->phase + 0x00008000) >> 16; unsigned int index = _q->phase >> (24 - _q->bits_index); // round down FIRPFB(_execute)(_q->pfb, index, &_y[n++]); _q->phase += _q->step; } // decrement filter-bank index by output rate _q->phase -= (1<<24); // error checking for now *_num_written = n; return LIQUID_OK; } // execute arbitrary resampler on a block of samples // _q : resamp object // _x : input buffer [size: _nx x 1] // _nx : input buffer // _y : output sample array (pointer) // _ny : number of samples written to _y int RESAMP(_execute_block)(RESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { // initialize number of output samples to zero unsigned int ny = 0; // number of samples written for each individual iteration unsigned int num_written; // iterate over each input sample unsigned int i; for (i=0; i<_nx; i++) { // run resampler on single input RESAMP(_execute)(_q, _x[i], &_y[ny], &num_written); // update output counter ny += num_written; } // set return value for number of output samples written *_ny = ny; return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/resamp.proto.c000066400000000000000000000332471474751757600212720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Arbitrary resampler // #include #include #include #include // defined: // TO output data type // TC coefficient data type // TI input data type // RESAMP() name-mangling macro // FIRPFB() firpfb macro // enable run-time debug printing of resampler #define DEBUG_RESAMP_PRINT 0 // internal: update timing int RESAMP(_update_timing_state)(RESAMP() _q); struct RESAMP(_s) { // filter design parameters unsigned int m; // filter semi-length, h_len = 2*m + 1 float as; // filter stop-band attenuation float fc; // filter cutoff frequency // resampling properties/states float rate; // resampling rate (output/input) float del; // fractional delay step // floating-point phase float tau; // accumulated timing phase, 0 <= tau < 1 float bf; // soft filterbank index, bf = tau*npfb = b + mu int b; // base filterbank index, 0 <= b < npfb float mu; // fractional filterbank interpolation value, 0 <= mu < 1 TO y0; // filterbank output at index b TO y1; // filterbank output at index b+1 // polyphase filterbank properties/object unsigned int npfb; // number of filters in the bank FIRPFB() f; // filterbank object (interpolator) enum { RESAMP_STATE_BOUNDARY, // boundary between input samples RESAMP_STATE_INTERP, // regular interpolation } state; }; // create arbitrary resampler // _rate : resampling rate // _m : prototype filter semi-length // _fc : prototype filter cutoff frequency, fc in (0, 0.5) // _as : prototype filter stop-band attenuation [dB] (e.g. 60) // _npfb : number of filters in polyphase filterbank RESAMP() RESAMP(_create)(float _rate, unsigned int _m, float _fc, float _as, unsigned int _npfb) { // validate input if (_rate <= 0) return liquid_error_config("resamp_%s_create(), resampling rate must be greater than zero", EXTENSION_FULL); if (_m == 0) return liquid_error_config("resamp_%s_create(), filter semi-length must be greater than zero", EXTENSION_FULL); if (_fc <= 0.0f || _fc >= 0.5f) return liquid_error_config("resamp_%s_create(), filter cutoff must be in (0,0.5)", EXTENSION_FULL); if (_as <= 0.0f) return liquid_error_config("resamp_%s_create(), filter stop-band suppression must be greater than zero", EXTENSION_FULL); if (_npfb == 0) return liquid_error_config("resamp_%s_create(), number of filter banks must be greater than zero", EXTENSION_FULL); // allocate memory for resampler RESAMP() q = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); // set rate using formal method (specifies output stride // value 'del') RESAMP(_set_rate)(q, _rate); // set properties q->m = _m; // prototype filter semi-length q->fc = _fc; // prototype filter cutoff frequency q->as = _as; // prototype filter stop-band attenuation q->npfb = _npfb; // number of filters in bank // design filter unsigned int n = 2*q->m*q->npfb+1; float hf[n]; TC h[n]; liquid_firdes_kaiser(n,q->fc/((float)(q->npfb)),q->as,0.0f,hf); // normalize filter coefficients by DC gain unsigned int i; float gain=0.0f; for (i=0; inpfb)/(gain); // copy to type-specific array, applying gain for (i=0; if = FIRPFB(_create)(q->npfb,h,n-1); // reset object and return RESAMP(_reset)(q); return q; } // create arbitrary resampler object with a specified input // resampling rate and default parameters // m (filter semi-length) = 7 // fc (filter cutoff frequency) = 0.25 // as (filter stop-band attenuation) = 60 dB // npfb (number of filters in the bank) = 64 RESAMP() RESAMP(_create_default)(float _rate) { // validate input if (_rate <= 0) return liquid_error_config("resamp_%s_create_default(), resampling rate must be greater than zero", EXTENSION_FULL); // det default parameters unsigned int m = 7; float fc = 0.5f*_rate > 0.49f ? 0.49f : 0.5f*_rate; float as = 60.0f; unsigned int npfb = 64; // create and return resamp object return RESAMP(_create)(_rate, m, fc, as, npfb); } // copy object RESAMP() RESAMP(_copy)(RESAMP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("resamp_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values RESAMP() q_copy = (RESAMP()) malloc(sizeof(struct RESAMP(_s))); memmove(q_copy, q_orig, sizeof(struct RESAMP(_s))); // copy filter bank q_copy->f = FIRPFB(_copy)(q_orig->f); // return object return q_copy; } // free arbitrary resampler object int RESAMP(_destroy)(RESAMP() _q) { // free polyphase filterbank FIRPFB(_destroy)(_q->f); // free main object memory free(_q); return LIQUID_OK; } // print resampler object int RESAMP(_print)(RESAMP() _q) { printf("\n", EXTENSION_FULL, _q->r, _q->m, _q->as, _q->fc, _q->npfb); return FIRPFB(_print)(_q->f); } // reset resampler object int RESAMP(_reset)(RESAMP() _q) { // clear filterbank FIRPFB(_reset)(_q->f); // reset states _q->state = RESAMP_STATE_INTERP;// input/output sample state _q->tau = 0.0f; // accumulated timing phase _q->bf = 0.0f; // soft-valued filterbank index _q->b = 0; // base filterbank index _q->mu = 0.0f; // fractional filterbank interpolation value _q->y0 = 0; // filterbank output at index b _q->y1 = 0; // filterbank output at index b+1 return LIQUID_OK; } // get resampler filter delay (semi-length m) unsigned int RESAMP(_get_delay)(RESAMP() _q) { return _q->m; } // Set output scaling for resampler int RESAMP(_set_scale)(RESAMP() _q, TC _scale) { return FIRPFB(_set_scale)(_q->f, _scale); } // Get output scaling for resampler int RESAMP(_get_scale)(RESAMP() _q, TC * _scale) { return FIRPFB(_get_scale)(_q->f, _scale); } // set rate of arbitrary resampler // _q : resampling object // _rate : new sampling rate, _rate > 0 int RESAMP(_set_rate)(RESAMP() _q, float _rate) { if (_rate <= 0) return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_rate(), resampling rate must be greater than zero", EXTENSION_FULL); // set internal rate _q->rate = _rate; // set output stride _q->del = 1.0f / _q->rate; return LIQUID_OK; } // get rate of arbitrary resampler float RESAMP(_get_rate)(RESAMP() _q) { return _q->rate; } // adjust resampling rate int RESAMP(_adjust_rate)(RESAMP() _q, float _gamma) { if (_gamma <= 0) return liquid_error(LIQUID_EICONFIG,"resamp_%s_adjust_rate(), resampling adjustment (%12.4e) must be greater than zero", EXTENSION_FULL, _gamma); // adjust internal rate _q->rate *= _gamma; // set output stride _q->del = 1.0f / _q->rate; return LIQUID_OK; } // set resampling timing phase // _q : resampling object // _tau : sample timing int RESAMP(_set_timing_phase)(RESAMP() _q, float _tau) { if (_tau < -1.0f || _tau > 1.0f) return liquid_error(LIQUID_EICONFIG,"resamp_%s_set_timing_phase(), timing phase must be in [-1,1], is %f.",EXTENSION_FULL,_tau); // set internal timing phase _q->tau = _tau; return LIQUID_OK; } // adjust resampling timing phase // _q : resampling object // _delta : sample timing adjustment int RESAMP(_adjust_timing_phase)(RESAMP() _q, float _delta) { if (_delta < -1.0f || _delta > 1.0f) return liquid_error(LIQUID_EICONFIG,"resamp_%s_adjust_timing_phase(), timing phase adjustment must be in [-1,1], is %f.",EXTENSION_FULL,_delta); // adjust internal timing phase _q->tau += _delta; return LIQUID_OK; } // Get the number of output samples given current state and input buffer size. unsigned int RESAMP(_get_num_output)(RESAMP() _q, unsigned int _num_input) { liquid_error(LIQUID_EINT,"resamp_%s_get_num_output(), function not implemented",EXTENSION_FULL); return 0; } // run arbitrary resampler // _q : resampling object // _x : single input sample // _y : output array // _num_written: number of samples written to output int RESAMP(_execute)(RESAMP() _q, TI _x, TO * _y, unsigned int * _num_written) { // push input sample into filterbank FIRPFB(_push)(_q->f, _x); unsigned int n=0; while (_q->b < _q->npfb) { #if DEBUG_RESAMP_PRINT printf(" [%2u] : s=%1u, tau=%12.8f, b : %12.8f (%4d + %8.6f)\n", n+1, _q->state, _q->tau, _q->bf, _q->b, _q->mu); #endif switch (_q->state) { case RESAMP_STATE_BOUNDARY: // compute filterbank output FIRPFB(_execute)(_q->f, 0, &_q->y1); // interpolate _y[n++] = (1.0f - _q->mu)*_q->y0 + _q->mu*_q->y1; // update timing state RESAMP(_update_timing_state)(_q); _q->state = RESAMP_STATE_INTERP; break; case RESAMP_STATE_INTERP: // compute output at base index FIRPFB(_execute)(_q->f, _q->b, &_q->y0); // check to see if base index is last filter in the bank, in // which case the resampler needs an additional input sample // to finish the linear interpolation process if (_q->b == _q->npfb-1) { // last filter: need additional input sample _q->state = RESAMP_STATE_BOUNDARY; // set index to indicate new sample is needed _q->b = _q->npfb; } else { // do not need additional input sample; compute // output at incremented base index FIRPFB(_execute)(_q->f, _q->b+1, &_q->y1); // perform linear interpolation between filterbank outputs _y[n++] = (1.0f - _q->mu)*_q->y0 + _q->mu*_q->y1; // update timing state RESAMP(_update_timing_state)(_q); } break; default: return liquid_error(LIQUID_EICONFIG,"resamp_%s_execute(), invalid/unknown state", EXTENSION_FULL); } } // decrement timing phase by one sample _q->tau -= 1.0f; _q->bf -= (float)(_q->npfb); _q->b -= _q->npfb; // specify number of samples written *_num_written = n; return LIQUID_OK; } // execute arbitrary resampler on a block of samples // _q : resamp object // _x : input buffer [size: _nx x 1] // _nx : input buffer // _y : output sample array (pointer) // _ny : number of samples written to _y int RESAMP(_execute_block)(RESAMP() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { // initialize number of output samples to zero unsigned int ny = 0; // number of samples written for each individual iteration unsigned int num_written; // iterate over each input sample unsigned int i; for (i=0; i<_nx; i++) { // run resampler on single input RESAMP(_execute)(_q, _x[i], &_y[ny], &num_written); // update output counter ny += num_written; } // set return value for number of output samples written *_ny = ny; return LIQUID_OK; } // // internal methods // // update timing state; increment output timing stride and // quantize filterbank indices int RESAMP(_update_timing_state)(RESAMP() _q) { // update high-resolution timing phase _q->tau += _q->del; // convert to high-resolution filterbank index _q->bf = _q->tau * (float)(_q->npfb); // split into integer filterbank index and fractional interpolation _q->b = (int)floorf(_q->bf); // base index _q->mu = _q->bf - (float)(_q->b); // fractional index return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/resamp2.proto.c000066400000000000000000000275161474751757600213560ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Halfband resampler (interpolator/decimator) #include #include #include #include // defined: // RESAMP2() name-mangling macro // TO output data type // TC coefficient data type // TI input data type // WINDOW() window macro // DOTPROD() dotprod macro // PRINTVAL() print macro struct RESAMP2(_s) { TC * h; // filter prototype unsigned int m; // primitive filter length unsigned int h_len; // actual filter length: h_len = 4*m+1 float f0; // center frequency [-1.0 <= f0 <= 1.0] float as; // stop-band attenuation [dB] // filter component TC * h1; // filter branch coefficients DOTPROD() dp; // inner dot product object unsigned int h1_len; // filter length (2*m) // input buffers WINDOW() w0; // input buffer (even samples) WINDOW() w1; // input buffer (odd samples) TC scale; // output scaling factor // halfband filter operation unsigned int toggle; }; // create a resamp2 object // _m : filter semi-length (effective length: 4*_m+1) // _f0 : center frequency of half-band filter // _as : stop-band attenuation [dB], _as > 0 RESAMP2() RESAMP2(_create)(unsigned int _m, float _f0, float _as) { // validate input if (_m < 2) return liquid_error_config("resamp2_%s_create(), filter semi-length must be at least 2", EXTENSION_FULL); if (_f0 < -0.5f || _f0 > 0.5f) return liquid_error_config("resamp2_%s_create(), f0 (%12.4e) must be in [-0.5,0.5]", EXTENSION_FULL, _f0); if (_as < 0.0f) return liquid_error_config("resamp2_%s_create(), as (%12.4e) must be greater than zero", EXTENSION_FULL, _as); RESAMP2() q = (RESAMP2()) malloc(sizeof(struct RESAMP2(_s))); q->m = _m; q->f0 = _f0; q->as = _as; // change filter length as necessary q->h_len = 4*(q->m) + 1; q->h = (TC *) malloc((q->h_len)*sizeof(TC)); q->h1_len = 2*(q->m); q->h1 = (TC *) malloc((q->h1_len)*sizeof(TC)); // design filter prototype unsigned int i; float hf[q->h_len]; liquid_firdespm_halfband_as(q->m, q->as, hf); for (i=0; ih_len; i++) { float t = (float)i - (float)(q->h_len-1)/2.0f; #if TC_COMPLEX == 1 q->h[i] = 2 * hf[i] * ( cosf(2.0f*M_PI*t*q->f0) + _Complex_I*sinf(2.0f*M_PI*t*q->f0) ); #else q->h[i] = 2 * hf[i] * cosf(2.0f*M_PI*t*q->f0); #endif } // resample, alternate sign, [reverse direction] unsigned int j=0; for (i=1; ih_len; i+=2) q->h1[j++] = q->h[q->h_len - i - 1]; // create dotprod object q->dp = DOTPROD(_create)(q->h1, 2*q->m); // create window buffers q->w0 = WINDOW(_create)(2*(q->m)); q->w1 = WINDOW(_create)(2*(q->m)); RESAMP2(_reset)(q); RESAMP2(_set_scale)(q, 1); return q; } // re-create a resamp2 object with new properties // _q : original resamp2 object // _m : filter semi-length (effective length: 4*_m+1) // _f0 : center frequency of half-band filter // _as : stop-band attenuation [dB], _as > 0 RESAMP2() RESAMP2(_recreate)(RESAMP2() _q, unsigned int _m, float _f0, float _as) { // only re-design filter if necessary if (_m != _q->m) { // destroy resampler and re-create from scratch RESAMP2(_destroy)(_q); _q = RESAMP2(_create)(_m, _f0, _as); } else { // re-design filter prototype unsigned int i; float t, h1, h2; TC h3; float beta = kaiser_beta_As(_q->as); for (i=0; i<_q->h_len; i++) { t = (float)i - (float)(_q->h_len-1)/2.0f; h1 = sincf(t/2.0f); h2 = liquid_kaiser(i,_q->h_len,beta); #if TC_COMPLEX == 1 h3 = cosf(2.0f*M_PI*t*_q->f0) + _Complex_I*sinf(2.0f*M_PI*t*_q->f0); #else h3 = cosf(2.0f*M_PI*t*_q->f0); #endif _q->h[i] = h1*h2*h3; } // resample, alternate sign, [reverse direction] unsigned int j=0; for (i=1; i<_q->h_len; i+=2) _q->h1[j++] = _q->h[_q->h_len - i - 1]; // create dotprod object _q->dp = DOTPROD(_recreate)(_q->dp, _q->h1, 2*_q->m); } return _q; } // copy object RESAMP2() RESAMP2(_copy)(RESAMP2() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("resamp2_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create object, copy internal memory, overwrite with specific values RESAMP2() q_copy = (RESAMP2()) malloc(sizeof(struct RESAMP2(_s))); memmove(q_copy, q_orig, sizeof(struct RESAMP2(_s))); // allocate memory for filter coefficients q_copy->h = (TC *) malloc((q_copy->h_len )*sizeof(TC)); q_copy->h1 = (TC *) malloc((q_copy->h1_len)*sizeof(TC)); // copy filter coefficients memmove(q_copy->h, q_orig->h, (q_copy->h_len )*sizeof(TC)); memmove(q_copy->h1, q_orig->h1, (q_copy->h1_len)*sizeof(TC)); // copy dot product and window objects q_copy->dp = DOTPROD(_copy)(q_orig->dp); q_copy->w0 = WINDOW (_copy)(q_orig->w0); q_copy->w1 = WINDOW (_copy)(q_orig->w1); // return object return q_copy; } // destroy a resamp2 object, clearing up all allocated memory int RESAMP2(_destroy)(RESAMP2() _q) { // destroy dotprod object DOTPROD(_destroy)(_q->dp); // destroy window buffers WINDOW(_destroy)(_q->w0); WINDOW(_destroy)(_q->w1); // free arrays free(_q->h); free(_q->h1); // free main object memory free(_q); return LIQUID_OK; } // print a resamp2 object's internals int RESAMP2(_print)(RESAMP2() _q) { printf("\n", EXTENSION_FULL, _q->h_len,_q->f0); return LIQUID_OK; } // clear internal buffer int RESAMP2(_reset)(RESAMP2() _q) { WINDOW(_reset)(_q->w0); WINDOW(_reset)(_q->w1); _q->toggle = 0; return LIQUID_OK; } // get filter delay (samples) unsigned int RESAMP2(_get_delay)(RESAMP2() _q) { return 2*_q->m - 1; } // set output scaling for filter int RESAMP2(_set_scale)(RESAMP2() _q, TC _scale) { _q->scale = _scale; return LIQUID_OK; } // get output scaling for filter int RESAMP2(_get_scale)(RESAMP2() _q, TC * _scale) { *_scale = _q->scale; return LIQUID_OK; } // execute resamp2 as half-band filter // _q : resamp2 object // _x : input sample // _y0 : output sample pointer (low frequency) // _y1 : output sample pointer (high frequency) int RESAMP2(_filter_execute)(RESAMP2() _q, TI _x, TO * _y0, TO * _y1) { TI * r; // buffer read pointer TO yi; // delay branch TO yq; // filter branch if ( _q->toggle == 0 ) { // push sample into upper branch WINDOW(_push)(_q->w0, _x); // upper branch (delay) WINDOW(_index)(_q->w0, _q->m-1, &yi); // lower branch (filter) WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dp, r, &yq); } else { // push sample into lower branch WINDOW(_push)(_q->w1, _x); // upper branch (delay) WINDOW(_index)(_q->w1, _q->m-1, &yi); // lower branch (filter) WINDOW(_read)(_q->w0, &r); DOTPROD(_execute)(_q->dp, r, &yq); } // toggle flag _q->toggle = 1 - _q->toggle; // set return values, normalizing gain, applying scaling factor *_y0 = 0.5f*(yi + yq)*_q->scale; // lower band *_y1 = 0.5f*(yi - yq)*_q->scale; // upper band return LIQUID_OK; } // execute analysis half-band filterbank // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output array [size: 2 x 1] int RESAMP2(_analyzer_execute)(RESAMP2() _q, TI * _x, TO * _y) { TI * r; // buffer read pointer TO y0; // delay branch TO y1; // filter branch // compute filter branch WINDOW(_push)(_q->w1, 0.5*_x[0]); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dp, r, &y1); // compute delay branch WINDOW(_push)(_q->w0, 0.5*_x[1]); WINDOW(_index)(_q->w0, _q->m-1, &y0); // set return value, applying scaling factor _y[0] = (y1 + y0) * _q->scale; _y[1] = (y1 - y0) * _q->scale; return LIQUID_OK; } // execute synthesis half-band filterbank // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output array [size: 2 x 1] int RESAMP2(_synthesizer_execute)(RESAMP2() _q, TI * _x, TO * _y) { TI * r; // buffer read pointer TI x0 = _x[0] + _x[1]; // delay branch input TI x1 = _x[0] - _x[1]; // filter branch input // compute delay branch WINDOW(_push)(_q->w0, x0); WINDOW(_index)(_q->w0, _q->m-1, &_y[0]); // compute second branch (filter) WINDOW(_push)(_q->w1, x1); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dp, r, &_y[1]); // apply scaling factor _y[0] *= _q->scale; _y[1] *= _q->scale; return LIQUID_OK; } // execute half-band decimation // _q : resamp2 object // _x : input array [size: 2 x 1] // _y : output sample pointer int RESAMP2(_decim_execute)(RESAMP2() _q, TI * _x, TO * _y) { TI * r; // buffer read pointer TO y0; // delay branch TO y1; // filter branch // compute filter branch WINDOW(_push)(_q->w1, _x[0]); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dp, r, &y1); // compute delay branch WINDOW(_push)(_q->w0, _x[1]); WINDOW(_index)(_q->w0, _q->m-1, &y0); // set return value, applying scaling factor *_y = (y0 + y1) * _q->scale; return LIQUID_OK; } // execute half-band interpolation // _q : resamp2 object // _x : input sample // _y : output array [size: 2 x 1] int RESAMP2(_interp_execute)(RESAMP2() _q, TI _x, TO * _y) { TI * r; // buffer read pointer // compute delay branch WINDOW(_push)(_q->w0, _x); WINDOW(_index)(_q->w0, _q->m-1, &_y[0]); // compute second branch (filter) WINDOW(_push)(_q->w1, _x); WINDOW(_read)(_q->w1, &r); DOTPROD(_execute)(_q->dp, r, &_y[1]); // apply scaling factor _y[0] *= _q->scale; _y[1] *= _q->scale; return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/rkaiser.c000066400000000000000000000442251474751757600202770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Design root-Nyquist Kaiser filter // // References // [Vaidyanathan:1993] Vaidyanathan, P. P., "Multirate Systems and // Filter Banks," 1993, Prentice Hall, Section 3.2.1 // #include #include #include #include "liquid.internal.h" #define DEBUG_RKAISER 0 // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] int liquid_firdes_rkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if (_k < 2) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser(), k must be at least 2"); if (_m < 1) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser(), m must be at least 1"); if (_beta <= 0.0f || _beta >= 1.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser(), beta must be in (0,1)"); if (_dt < -1.0f || _dt > 1.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser(), dt must be in [-1,1]"); // simply call internal method and ignore output rho value float rho; return liquid_firdes_rkaiser_quadratic(_k,_m,_beta,_dt,_h,&rho); } // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc using approximation for rho. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] int liquid_firdes_arkaiser(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { // validate input if (_k < 2) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_arkaiser(), k must be at least 2"); if (_m < 1) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_arkaiser(), m must be at least 1"); if (_beta <= 0.0f || _beta >= 1.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_arkaiser(), beta must be in (0,1)"); if (_dt < -1.0f || _dt > 1.0f) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_arkaiser(), dt must be in [-1,1]"); // compute bandwidth correction factor, rho ~ c0 + c1*log(_beta) + c2*log^2(_beta) float c0 = 0.762886 + 0.067663*logf(_m); float c1 = 0.065515; float c2 = logf( 1 - 0.088*powf(_m,-1.6 ) ); float log_beta = logf(_beta); float rho_hat = c0 + c1*log_beta + c2*log_beta*log_beta; // ensure range is valid and override if approximation is out of range if (rho_hat <= 0.0f || rho_hat >= 1.0f) rho_hat = rkaiser_approximate_rho(_m,_beta); // compute filter design parameters unsigned int n=2*_k*_m+1; // filter length float kf = (float)_k; // samples/symbol (float) float del = _beta*rho_hat / kf; // transition bandwidth float as = estimate_req_filter_As(del, n); // stop-band suppression float fc = 0.5f*(1 + _beta*(1.0f-rho_hat))/kf; // filter cutoff #if DEBUG_RKAISER printf("rho-hat : %12.8f (compare to %12.8f)\n", rho_hat, rkaiser_approximate_rho(_m,_beta)); printf("fc : %12.8f\n", fc); printf("delta-f : %12.8f\n", del); printf("as : %12.8f dB\n", as); printf("alpha : %12.8f\n", kaiser_beta_As(as)); #endif // compute filter coefficients liquid_firdes_kaiser(n,fc,as,_dt,_h); // normalize coefficients float e2 = 0.0f; unsigned int i; for (i=0; i 1.0f) ) { liquid_error(LIQUID_EICONFIG,"rkaiser_approximate_rho(): beta must be in [0,1]"); return 0.0f; } // compute bandwidth adjustment estimate float c0=0.0f, c1=0.0f, c2=0.0f; switch (_m) { case 1: c0=0.75749731; c1=0.06134303; c2=-0.08729663; break; case 2: c0=0.81151861; c1=0.07437658; c2=-0.01427088; break; case 3: c0=0.84249538; c1=0.07684185; c2=-0.00536879; break; case 4: c0=0.86140782; c1=0.07144126; c2=-0.00558652; break; case 5: c0=0.87457740; c1=0.06578694; c2=-0.00650447; break; case 6: c0=0.88438797; c1=0.06074265; c2=-0.00736405; break; case 7: c0=0.89216620; c1=0.05669236; c2=-0.00791222; break; case 8: c0=0.89874983; c1=0.05361696; c2=-0.00815301; break; case 9: c0=0.90460032; c1=0.05167952; c2=-0.00807893; break; case 10: c0=0.91034430; c1=0.05130753; c2=-0.00746192; break; case 11: c0=0.91587675; c1=0.05180436; c2=-0.00670711; break; case 12: c0=0.92121875; c1=0.05273801; c2=-0.00588351; break; case 13: c0=0.92638195; c1=0.05400764; c2=-0.00508452; break; case 14: c0=0.93123555; c1=0.05516163; c2=-0.00437306; break; case 15: c0=0.93564993; c1=0.05596561; c2=-0.00388152; break; case 16: c0=0.93976742; c1=0.05662274; c2=-0.00348280; break; case 17: c0=0.94351703; c1=0.05694120; c2=-0.00318821; break; case 18: c0=0.94557273; c1=0.05227591; c2=-0.00400676; break; case 19: c0=0.95001614; c1=0.05681641; c2=-0.00300628; break; case 20: c0=0.95281708; c1=0.05637607; c2=-0.00304790; break; case 21: c0=0.95536256; c1=0.05575880; c2=-0.00312988; break; case 22: c0=0.95754206; c1=0.05426060; c2=-0.00385945; break; default: c0 = 0.056873*logf(_m+1e-3f) + 0.781388; c1 = 0.05426f; c2 = -0.00386f; } float b = logf(_beta); float rho_hat = c0 + c1*b + c2*b*b; // ensure estimate is in [0,1] if (rho_hat < 0.0f) { rho_hat = 0.0f; } else if (rho_hat > 1.0f) { rho_hat = 1.0f; } return rho_hat; } #if 0 // Design frequency-shifted root-Nyquist filter based on // the Kaiser-windowed sinc. // // _k : filter over-sampling rate (samples/symbol) // _m : filter delay (symbols) // _beta : filter excess bandwidth factor (0,1) // _dt : filter fractional sample delay // _h : resulting filter [size: 2*_k*_m+1] // _rho : transition bandwidth adjustment, 0 < _rho < 1 int liquid_firdes_rkaiser_bisection(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h, float * _rho) { if ( _k < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_bisection(): k must be greater than 0"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_bisection(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_bisection(): beta must be in [0,1]"); // algorithm: // 1. choose three initial points [x0, x1, x2] where x0 < x1 < x2 // 2. choose xa = 0.5*(x0 + x1), bisection of [x0 x1] // 3. choose xb = 0.5*(x1 + x2), bisection of [x1 x2] // 4. x0 < xa < x1 < xb < x2 // 5. evaluate points to obtain [y0, ya, y1, yb, y2] // 6. find minimum of three midpoints [ya, y1, yb] // 7. update initial points [x0, x1, x2] and go to step 2 unsigned int i; unsigned int n=2*_k*_m+1; // filter length // compute bandwidth adjustment estimate float rho_hat = rkaiser_approximate_rho(_m,_beta); // bandwidth adjustment float x0 = 0.5f * rho_hat; // lower bound, old: rho_hat*0.9f; float x1 = rho_hat; // midpoint: use initial estimate float x2 = 1.0f; // upper bound, old: 1.0f - 0.9f*(1.0f-rho_hat); //x1 = 0.5f*(x0 + x2); // bisect [x0,x1] // evaluate performance (ISI) of each bandwidth adjustment float y0 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x0,_h); float y1 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x1,_h); float y2 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x2,_h); // run parabolic search to find bandwidth adjustment x_hat which // minimizes the inter-symbol interference of the filter unsigned int p, pmax=14; float x_hat = rho_hat; float xa, xb; float ya, yb; #if DEBUG_RKAISER FILE * fid = fopen("rkaiser_debug.m", "w"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"x = [%12.4e %12.4e %12.4e];\n", x0, x1, x2); fprintf(fid,"y = [%12.4e %12.4e %12.4e];\n", y0, y1, y2); #endif for (p=0; p y0 || y1 > y2) { liquid_error(LIQUID_ENOCONV,"liquid_firdes_rkaiser_bisection(): bounding region is ill-conditioned, y:{%g,%g,%g}", y0, y1, y2); } // choose midway points xa, xb and compute ISI xa = 0.5f*(x0 + x1); // bisect [x0,x1] xb = 0.5f*(x1 + x2); // bisect [x1,x2] ya = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,xa,_h); yb = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,xb,_h); #if DEBUG_RKAISER fprintf(fid,"x = [x %12.4e %12.4e];\n", xa, xb); fprintf(fid,"y = [y %12.4e %12.4e];\n", ya, yb); #endif // find the minimum of [ya,y1,yb], update bounds if (y1 < ya && y1 < yb) { x0 = xa; y0 = ya; x2 = xb; y2 = yb; } else if (ya < yb) { x2 = x1; y2 = y1; x1 = xa; y1 = ya; } else { x0 = x1; y0 = y1; x1 = xb; y1 = yb; } x_hat = x1; #if DEBUG_RKAISER float y_hat = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x_hat,_h); printf(" %4u : rho=%12.8f, isi=%12.6f dB\n", p+1, x_hat, 20*log10f(y_hat)); #endif }; #if DEBUG_RKAISER fprintf(fid,"figure;\n"); fprintf(fid,"plot(x,20*log10(y),'x');\n"); fclose(fid); printf("results written to rkaiser_debug.m\n"); #endif // re-design filter with optimal value for rho liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x_hat,_h); // normalize filter magnitude float e2 = 0.0f; for (i=0; i x1 // (x2,y2) <- (x1,y1) otherwise // 5. go to step 2 unsigned int i; unsigned int n=2*_k*_m+1; // filter length // compute bandwidth adjustment estimate float rho_hat = rkaiser_approximate_rho(_m,_beta); float rho_opt = rho_hat; // bandwidth adjustment float x0; // lower bound float x1 = rho_hat; // initial estimate float x2; // upper bound // evaluate performance (ISI) of each bandwidth adjustment float y0; float y1; float y2; float y_opt = 0.0f; // run parabolic search to find bandwidth adjustment x_hat which // minimizes the inter-symbol interference of the filter unsigned int p, pmax=14; float x_hat = rho_hat; float dx = 0.2f; // bounding size float del = 0.0f; // computed step size float tol = 1e-6f; // tolerance #if DEBUG_RKAISER FILE * fid = fopen("rkaiser_debug.m", "w"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n"); fprintf(fid,"x = [];\n"); fprintf(fid,"y = [];\n"); #endif for (p=0; p= 1.0f) x2 = 0.99f; // evaluate all points y0 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x0,_h); y1 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x1,_h); y2 = liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,x2,_h); // save optimum if (p==0 || y1 < y_opt) { rho_opt = x1; y_opt = y1; } #if DEBUG_RKAISER fprintf(fid,"x = [x %12.4e %12.4e %12.4e];\n", x0, x1, x2); fprintf(fid,"y = [y %12.4e %12.4e %12.4e];\n", y0, y1, y2); //printf(" %4u : [%8.4f %8.4f %8.4f] rho=%12.8f, isi=%12.6f dB\n", p+1, x0, x1, x2, x1, 20*log10f(y1)); printf(" %4u : [%8.4f,%8.2f] [%8.4f,%8.2f] [%8.4f,%8.2f]\n", p+1, x0, 20*log10f(y0), x1, 20*log10f(y1), x2, 20*log10f(y2)); #endif // compute minimum of quadratic function double ta = y0*(x1*x1 - x2*x2) + y1*(x2*x2 - x0*x0) + y2*(x0*x0 - x1*x1); double tb = y0*(x1 - x2) + y1*(x2 - x0) + y2*(x0 - x1); // update estimate x_hat = 0.5f * ta / tb; // ensure x_hat is within boundary (this will fail if y1 > y0 || y1 > y2) if (x_hat < x0 || x_hat > x2) { //liquid_error(LIQUID_ENOCONV,"liquid_firdes_rkaiser_quadratic(): quadratic minimum outside boundary, y:{%g,%g,%g}, x-hat:%g,{%g,%g}", // y0, y1, y2, x_hat, x0, x2); break; } // break if step size is sufficiently small del = x_hat - x1; if (p > 3 && fabsf(del) < tol) break; // update estimate, reduce bound x1 = x_hat; dx *= 0.5f; }; #if DEBUG_RKAISER fprintf(fid,"figure;\n"); fprintf(fid,"plot(x,20*log10(y),'x');\n"); fclose(fid); printf("results written to rkaiser_debug.m\n"); #endif // re-design filter with optimal value for rho liquid_firdes_rkaiser_internal_isi(_k,_m,_beta,_dt,rho_opt,_h); // normalize filter magnitude float e2 = 0.0f; for (i=0; i 1.0f) { liquid_error(LIQUID_EICONFIG,"liquid_firdes_rkaiser_internal_isi(), rho > 1"); } unsigned int n=2*_k*_m+1; // filter length float kf = (float)_k; // samples/symbol (float) float del = _beta*_rho / kf; // transition bandwidth float as = estimate_req_filter_As(del, n); // stop-band suppression float fc = 0.5f*(1 + _beta*(1.0f-_rho))/kf; // filter cutoff // evaluate performance (ISI) float isi_max; float isi_rms; // compute filter liquid_firdes_kaiser(n,fc,as,_dt,_h); // compute filter ISI liquid_filter_isi(_h,_k,_m,&isi_rms,&isi_max); // return RMS of ISI return isi_rms; } liquid-dsp-1.7.0/src/filter/src/rrcos.c000066400000000000000000000062371474751757600177700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Design root raised-cosine filter // #include #include #include #include "liquid.internal.h" // Design root-Nyquist raised-cosine filter // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _dt : fractional sample delay // _h : output coefficient buffer (length: 2*k*m+1) int liquid_firdes_rrcos(unsigned int _k, unsigned int _m, float _beta, float _dt, float * _h) { if ( _k < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rrcos(): k must be greater than 0"); if ( _m < 1 ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rrcos(): m must be greater than 0"); if ( (_beta < 0.0f) || (_beta > 1.0f) ) return liquid_error(LIQUID_EICONFIG,"liquid_firdes_rrcos(): beta must be in [0,1]"); unsigned int n; float z, t1, t2, t3, t4, T=1.0f; float nf, kf, mf; unsigned int h_len = 2*_k*_m + 1; // Calculate filter coefficients for (n=0; n #include #include #include #include struct RRESAMP(_s) { // filter design parameters unsigned int P; // interpolation factor (primitive) unsigned int Q; // decimation factor (primitive) unsigned int m; // filter semi-length, h_len = 2*m + 1 unsigned int block_len; // number of blocks to run in execute() FIRPFB() pfb; // filterbank object (interpolator), Q filters in bank }; // internal: execute rational-rate resampler on a primitive-length block of // input samples and store the resulting samples in the output array. int RRESAMP(_execute_primitive)(RRESAMP() _q, TI * _x, TO * _y); // Create rational-rate resampler object from external coefficients // _interp : interpolation factor // _decim : decimation factor // _m : filter semi-length (delay) // _h : filter coefficients, [size: 2*_interp*_m x 1] RRESAMP() RRESAMP(_create)(unsigned int _interp, unsigned int _decim, unsigned int _m, TC * _h) { // validate input if (_interp == 0) return liquid_error_config("rresamp_%s_create(), interpolation rate must be greater than zero", EXTENSION_FULL); if (_decim == 0) return liquid_error_config("rresamp_%s_create(), decimation rate must be greater than zero", EXTENSION_FULL); if (_m == 0) return liquid_error_config("rresamp_%s_create(), filter semi-length must be greater than zero", EXTENSION_FULL); // allocate memory for resampler RRESAMP() q = (RRESAMP()) malloc(sizeof(struct RRESAMP(_s))); // set properties q->P = _interp; q->Q = _decim; q->m = _m; q->block_len = 1; // create poly-phase filter bank q->pfb = FIRPFB(_create)(q->P, _h, 2*q->P*q->m); // reset object and return RRESAMP(_reset)(q); return q; } // Create rational-rate resampler object from filter prototype // _interp : interpolation factor // _decim : decimation factor // _m : filter semi-length (delay) // _bw : filter bandwidth relative to sample rate // _as : filter stop-band attenuation [dB] RRESAMP() RRESAMP(_create_kaiser)(unsigned int _interp, unsigned int _decim, unsigned int _m, float _bw, float _as) { // scale interpolation and decimation factors by their greatest common divisor unsigned int gcd = liquid_gcd(_interp, _decim); _interp /= gcd; _decim /= gcd; // check for critical bandwidth if (_bw < 0) _bw = _interp > _decim ? 0.5f : 0.5f * (float)_interp / (float)_decim; else if (_bw > 0.5f) return liquid_error_config("rresamp_%s_create_kaiser(), invalid bandwidth (%g), must be less than 0.5", EXTENSION_FULL, _bw); // design filter unsigned int h_len = 2*_interp*_m + 1; float * hf = (float*) malloc(h_len*sizeof(float)); TC * h = (TC*) malloc(h_len*sizeof(TC) ); liquid_firdes_kaiser(h_len, _bw/(float)_interp, _as, 0.0f, hf); // convert to type-specific coefficients unsigned int i; for (i=0; iQ)/(float)(q->P))); q->block_len = gcd; // free allocated memory and return object free(hf); free(h); return q; } // create rational-rate resampler object from prototype RRESAMP() RRESAMP(_create_prototype)(int _type, unsigned int _interp, unsigned int _decim, unsigned int _m, float _beta) { // scale interpolation and decimation factors by their greatest common divisor unsigned int gcd = liquid_gcd(_interp, _decim); _interp /= gcd; _decim /= gcd; // design filter int decim = _interp < _decim; // interpolator? or decimator unsigned int k = decim ? _decim : _interp; // prototype samples per symbol unsigned int h_len = 2*k*_m + 1; // filter length float * hf = (float*) malloc(h_len*sizeof(float)); TC * h = (TC*) malloc(h_len*sizeof(TC) ); liquid_firdes_prototype(_type, k, _m, _beta, 0, hf); // convert to type-specific coefficients unsigned int i; for (i=0; iblock_len = gcd; // adjust gain according to resampling rate float rate = RRESAMP(_get_rate)(q); RRESAMP(_set_scale)(q, decim ? sqrtf(rate) : 1.0f / sqrtf(rate)); // free allocated memory and return object free(hf); free(h); return q; } // create rational-rate resampler object with a specified input // resampling rate and default parameters // m (filter semi-length) = 12 // as (filter stop-band attenuation) = 60 dB RRESAMP() RRESAMP(_create_default)(unsigned int _interp, unsigned int _decim) { // det default parameters unsigned int m = 12; float bw = 0.5f; float as = 60.0f; // create and return resamp object return RRESAMP(_create_kaiser)(_interp, _decim, m, bw, as); } // copy object RRESAMP() RRESAMP(_copy)(RRESAMP() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("rresamp_%s_create(), object cannot be NULL", EXTENSION_FULL); // create filter object and copy internal memory RRESAMP() q_copy = (RRESAMP()) malloc(sizeof(struct RRESAMP(_s))); memmove(q_copy, q_orig, sizeof(struct RRESAMP(_s))); // copy internal object and return q_copy->pfb = FIRPFB(_copy)(q_orig->pfb); return q_copy; } // free resampler object int RRESAMP(_destroy)(RRESAMP() _q) { // free polyphase filterbank FIRPFB(_destroy)(_q->pfb); // free main object memory free(_q); return LIQUID_OK; } // print resampler object int RRESAMP(_print)(RRESAMP() _q) { printf("\n", EXTENSION_FULL, _q->P, _q->Q, (float)(_q->P) / (float)(_q->Q), _q->block_len, _q->m); return LIQUID_OK; } // reset resampler object int RRESAMP(_reset)(RRESAMP() _q) { // clear filterbank return FIRPFB(_reset)(_q->pfb); } // Set output scaling for filter, default: \( 2 w \sqrt{P/Q} \) // _q : resampler object // _scale : scaling factor to apply to each output sample int RRESAMP(_set_scale)(RRESAMP() _q, TC _scale) { return FIRPFB(_set_scale)(_q->pfb, _scale); } // Get output scaling for filter // _q : resampler object // _scale : scaling factor to apply to each output sample int RRESAMP(_get_scale)(RRESAMP() _q, TC * _scale) { return FIRPFB(_get_scale)(_q->pfb, _scale); } // get resampler filter delay (semi-length m) unsigned int RRESAMP(_get_delay)(RRESAMP() _q) { return _q->m; } // get block length unsigned int RRESAMP(_get_block_len)(RRESAMP() _q) { return _q->block_len; } // Get rate of resampler, r = P/Q float RRESAMP(_get_rate)(RRESAMP() _q) { return (float)(_q->P) / (float)(_q->Q); } // Get original interpolation factor of resampler, P unsigned int RRESAMP(_get_P)(RRESAMP() _q) { return _q->P * _q->block_len; } // Get internal interpolation factor of resampler, \(P\), after removing gcd unsigned int RRESAMP(_get_interp)(RRESAMP() _q) { return _q->P; } // Get original decimation factor of resampler, Q unsigned int RRESAMP(_get_Q)(RRESAMP() _q) { return _q->Q * _q->block_len; } // Get internal decimator factor of resampler, \(Q\), after removing gcd unsigned int RRESAMP(_get_decim)(RRESAMP() _q) { return _q->Q; } // Write \(Q\) input samples (after removing greatest common divisor) // into buffer, but do not compute output. This effectively updates the // internal state of the resampler. // _q : resamp object // _buf : input sample array, [size: Q x 1] int RRESAMP(_write)(RRESAMP() _q, TI * _buf) { return FIRPFB(_write)(_q->pfb, _buf, _q->Q); } // Execute rational-rate resampler on a block of input samples and // store the resulting samples in the output array. // _q : resamp object // _x : input sample array, [size: Q x 1] // _y : output sample array [size: P x 1] int RRESAMP(_execute)(RRESAMP() _q, TI * _x, TO * _y) { // run in blocks unsigned int i; for (i=0; i<_q->block_len; i++) { // compute P outputs for Q inputs RRESAMP(_execute_primitive)(_q, _x, _y); // update input pointers accordingly _x += _q->Q; _y += _q->P; } return LIQUID_OK; } // Execute on a block of samples // _q : resamp object // _x : input sample array, [size: Q*n x 1] // _n : block size // _y : output sample array [size: P*n x 1] int RRESAMP(_execute_block)(RRESAMP() _q, TI * _x, unsigned int _n, TO * _y) { unsigned int i; for (i=0; i<_n; i++) { RRESAMP(_execute)(_q, _x, _y); _x += _q->Q; _y += _q->P; } return LIQUID_OK; } // internal int RRESAMP(_execute_primitive)(RRESAMP() _q, TI * _x, TO * _y) { unsigned int index = 0; // filterbank index unsigned int i, n=0; for (i=0; i<_q->Q; i++) { // push input FIRPFB(_push)(_q->pfb, _x[i]); // continue to produce output while (index < _q->P) { FIRPFB(_execute)(_q->pfb, index, &_y[n++]); index += _q->Q; } // decrement filter-bank index by output rate index -= _q->P; } if (index != 0) { return liquid_error(LIQUID_EINT,"rresamp_%s_execute_primitive(), index=%u (expected 0)", EXTENSION_FULL, index); } else if (n != _q->P) { return liquid_error(LIQUID_EINT,"rresamp_%s_execute_primitive(), n=%u (expected P=%u)", EXTENSION_FULL, n, _q->P); } return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/src/symsync.proto.c000066400000000000000000000420221474751757600214770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Symbol synchronizer // // References: // [Mengali:1997] Umberto Mengali and Aldo N. D'Andrea, // "Synchronization Techniques for Digital Receivers," // Plenum Press, New York & London, 1997. // [harris:2001] frederic j. harris and Michael Rice, // "Multirate Digital Filters for Symbol Timing Synchronization // in Software Defined Radios," IEEE Journal on Selected Areas // of Communications, vol. 19, no. 12, December, 2001, pp. // 2346-2357. // #include #include #include #include // // forward declaration of internal methods // // step synchronizer // _q : symsync object // _x : input sample // _y : output sample array pointer // _ny : number of output samples written int SYMSYNC(_step)(SYMSYNC() _q, TI _x, TO * _y, unsigned int * _ny); // advance synchronizer's internal loop filter // _q : synchronizer object // _mf : matched-filter output // _dmf : derivative matched-filter output int SYMSYNC(_advance_internal_loop)(SYMSYNC() _q, TO _mf, TO _dmf); // internal structure struct SYMSYNC(_s) { unsigned int h_len; // matched filter length unsigned int k; // samples/symbol (input) unsigned int k_out; // samples/symbol (output) unsigned int decim_counter; // decimation counter int is_locked; // synchronizer locked flag float rate; // internal resampling rate float del; // fractional delay step // floating-point timing phase float tau; // accumulated timing phase (0 <= tau <= 1) float tau_decim; // timing phase, retained for get_tau() method float bf; // soft filterbank index int b; // filterbank index // loop filter float q; // instantaneous timing error float q_hat; // filtered timing error float B[3]; // loop filter feed-forward coefficients float A[3]; // loop filter feed-back coefficients iirfiltsos_rrrf pll; // loop filter object (iir filter) float rate_adjustment; // internal rate adjustment factor unsigned int npfb; // number of filters in the bank FIRPFB() mf; // matched filter FIRPFB() dmf; // derivative matched filter }; // create synchronizer object from external coefficients // _k : samples per symbol // _M : number of filters in the bank // _h : matched filter coefficients // _h_len : length of matched filter SYMSYNC() SYMSYNC(_create)(unsigned int _k, unsigned int _M, TC * _h, unsigned int _h_len) { // validate input if (_k < 2) return liquid_error_config("symsync_%s_create(), input sample rate must be at least 2", EXTENSION_FULL); if (_M == 0) return liquid_error_config("symsync_%s_create(), number of filter banks must be greater than zero", EXTENSION_FULL); if (_h_len == 0) return liquid_error_config("symsync_%s_create(), filter length must be greater than zero", EXTENSION_FULL); if ( (_h_len-1) % _M ) return liquid_error_config("symsync_%s_create(), filter length must be of the form: h_len = m*_k*_M + 1 ", EXTENSION_FULL); // create main object SYMSYNC() q = (SYMSYNC()) malloc(sizeof(struct SYMSYNC(_s))); // set internal properties q->k = _k; // input samples per symbol q->npfb = _M; // number of filters in the polyphase filter bank // set output rate (nominally 1, full decimation) SYMSYNC(_set_output_rate)(q, 1); // set internal sub-filter length q->h_len = (_h_len-1)/q->npfb; // compute derivative filter TC dh[_h_len]; float hdh_max = 0.0f; unsigned int i; for (i=0; i<_h_len; i++) { if (i==0) { dh[i] = _h[i+1] - _h[_h_len-1]; } else if (i==_h_len-1) { dh[i] = _h[0] - _h[i-1]; } else { dh[i] = _h[i+1] - _h[i-1]; } // find maximum of h*dh if ( fabsf(_h[i]*dh[i]) > hdh_max || i==0 ) hdh_max = fabsf(_h[i]*dh[i]); } // apply scaling factor for normalized response for (i=0; i<_h_len; i++) dh[i] *= 0.06f / hdh_max; q->mf = FIRPFB(_create)(q->npfb, _h, _h_len); q->dmf = FIRPFB(_create)(q->npfb, dh, _h_len); // reset state and initialize loop filter q->A[0] = 1.0f; q->B[0] = 0.0f; q->A[1] = 0.0f; q->B[1] = 0.0f; q->A[2] = 0.0f; q->B[2] = 0.0f; q->pll = iirfiltsos_rrrf_create(q->B, q->A); SYMSYNC(_reset)(q); SYMSYNC(_set_lf_bw)(q, 0.01f); // unlock loop control SYMSYNC(_unlock)(q); // return main object return q; } // create square-root Nyquist symbol synchronizer // _type : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples/symbol // _m : symbol delay // _beta : rolloff factor (0 < beta <= 1) // _M : number of filters in the bank SYMSYNC() SYMSYNC(_create_rnyquist)(int _type, unsigned int _k, unsigned int _m, float _beta, unsigned int _M) { // validate input if (_k < 2) return liquid_error_config("symsync_%s_create_rnyquist(), samples/symbol must be at least 2", EXTENSION_FULL); if (_m == 0) return liquid_error_config("symsync_%s_create_rnyquist(), filter delay (m) must be greater than zero", EXTENSION_FULL); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("symsync_%s_create_rnyquist(), filter excess bandwidth must be in [0,1]", EXTENSION_FULL); if (_M == 0) return liquid_error_config("symsync_%s_create_rnyquist(), number of filters in bnak must be greater than zero", EXTENSION_FULL); // allocate memory for filter coefficients unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; // design square-root Nyquist pulse-shaping filter liquid_firdes_prototype(_type, _k*_M, _m, _beta, 0, Hf); // copy coefficients to type-specific array TC H[H_len]; unsigned int i; for (i=0; i 1.0f) return liquid_error_config("symsync_%s_create_kaiser(), filter excess bandwidth must be in [0,1]", EXTENSION_FULL); if (_M == 0) return liquid_error_config("symsync_%s_create_kaiser(), number of filters in bnak must be greater than zero", EXTENSION_FULL); // allocate memory for filter coefficients unsigned int H_len = 2*_M*_k*_m + 1; float Hf[H_len]; // design interpolating filter whose bandwidth is outside the cut-off // frequency of input signal // TODO: use _beta to compute more accurate cut-off frequency float fc = 0.75f; // filter cut-off frequency (nominal) float as = 40.0f; // filter stop-band attenuation liquid_firdes_kaiser(H_len, fc / (float)(_k*_M), as, 0.0f, Hf); // copy coefficients to type-specific array, adjusting to relative // filter gain unsigned int i; TC H[H_len]; for (i=0; ipll = iirfiltsos_rrrf_copy(q_orig->pll); // copy filter banks q_copy->mf = FIRPFB(_copy)(q_orig->mf); q_copy->dmf = FIRPFB(_copy)(q_orig->dmf); // return object return q_copy; } // destroy symsync object, freeing all internal memory int SYMSYNC(_destroy)(SYMSYNC() _q) { // destroy filterbank objects FIRPFB(_destroy)(_q->mf); FIRPFB(_destroy)(_q->dmf); // destroy timing phase-locked loop filter iirfiltsos_rrrf_destroy(_q->pll); // free main object memory free(_q); return LIQUID_OK; } // print symsync object's parameters int SYMSYNC(_print)(SYMSYNC() _q) { printf("\n", EXTENSION_FULL, _q->rate, _q->k, _q->k_out); return FIRPFB(_print)(_q->mf); } // reset symsync internal state int SYMSYNC(_reset)(SYMSYNC() _q) { // reset polyphase filterbank FIRPFB(_reset)(_q->mf); // reset counters, etc. _q->rate = (float)_q->k / (float)_q->k_out; _q->del = _q->rate; _q->b = 0; // filterbank index _q->bf = 0.0f; // filterbank index (soft value) _q->tau = 0.0f; // instantaneous timing estimate _q->tau_decim = 0.0f; // instantaneous timing estaimte (decimated) _q->q = 0.0f; // timing error _q->q_hat = 0.0f; // filtered timing error _q->decim_counter = 0; // decimated output counter // reset timing phase-locked loop filter return iirfiltsos_rrrf_reset(_q->pll); } // lock synchronizer object int SYMSYNC(_lock)(SYMSYNC() _q) { _q->is_locked = 1; return LIQUID_OK; } // unlock synchronizer object int SYMSYNC(_unlock)(SYMSYNC() _q) { _q->is_locked = 0; return LIQUID_OK; } // check lock state int SYMSYNC(_is_locked)(SYMSYNC() _q) { return _q->is_locked; } // set synchronizer output rate (samples/symbol) // _q : synchronizer object // _k_out : output samples/symbol int SYMSYNC(_set_output_rate)(SYMSYNC() _q, unsigned int _k_out) { // validate input if (_k_out == 0) return liquid_error(LIQUID_EICONFIG,"symsync_%s_output_rate(), output rate must be greater than 0", EXTENSION_FULL); // set output rate _q->k_out = _k_out; _q->rate = (float)_q->k / (float)_q->k_out; _q->del = _q->rate; return LIQUID_OK; } // set synchronizer loop filter bandwidth // _q : synchronizer object // _bt : loop bandwidth int SYMSYNC(_set_lf_bw)(SYMSYNC() _q, float _bt) { // validate input if (_bt < 0.0f || _bt > 1.0f) return liquid_error(LIQUID_EICONFIG,"symsync_%s_set_lf_bt(), bandwidth must be in [0,1]", EXTENSION_FULL); // compute filter coefficients from bandwidth float alpha = 1.000f - _bt; float beta = 0.220f * _bt; float a = 0.500f; float b = 0.495f; _q->B[0] = beta; _q->B[1] = 0.00f; _q->B[2] = 0.00f; _q->A[0] = 1.00f - a*alpha; _q->A[1] = -b*alpha; _q->A[2] = 0.00f; // set internal parameters of 2nd-order IIR filter iirfiltsos_rrrf_set_coefficients(_q->pll, _q->B, _q->A); // update rate adjustment factor _q->rate_adjustment = 0.5*_bt; return LIQUID_OK; } // return instantaneous fractional timing offset estimate float SYMSYNC(_get_tau)(SYMSYNC() _q) { return _q->tau_decim; } // execute synchronizer on input data array // _q : synchronizer object // _x : input data array // _nx : number of input samples // _y : output data array // _ny : number of samples written to output buffer int SYMSYNC(_execute)(SYMSYNC() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { unsigned int i, ny=0, k=0; for (i=0; i<_nx; i++) { SYMSYNC(_step)(_q, _x[i], &_y[ny], &k); ny += k; //printf("%u\n",k); } *_ny = ny; return LIQUID_OK; } // // internal methods // // step synchronizer with single input sample // _q : symsync object // _x : input sample // _y : output sample array pointer // _ny : number of output samples written int SYMSYNC(_step)(SYMSYNC() _q, TI _x, TO * _y, unsigned int * _ny) { // push sample into MF and dMF filterbanks FIRPFB(_push)(_q->mf, _x); FIRPFB(_push)(_q->dmf, _x); // matched and derivative matched-filter outputs TO mf; // matched filter output TO dmf; // derivative matched filter output unsigned int n=0; // continue loop until filterbank index rolls over while (_q->b < _q->npfb) { // compute filterbank output FIRPFB(_execute)(_q->mf, _q->b, &mf); // scale output by samples/symbol _y[n] = mf / (float)(_q->k); // check output count and determine if this is 'ideal' timing output if (_q->decim_counter == _q->k_out) { // reset counter _q->decim_counter = 0; // if synchronizer is locked, don't update internal timing offset if (_q->is_locked) continue; // compute dMF output FIRPFB(_execute)(_q->dmf, _q->b, &dmf); // update internal state SYMSYNC(_advance_internal_loop)(_q, mf, dmf); _q->tau_decim = _q->tau; // save return value } // increment decimation counter _q->decim_counter++; // update states _q->tau += _q->del; // instantaneous fractional offset _q->bf = _q->tau * (float)(_q->npfb); // filterbank index (soft) _q->b = (int)roundf(_q->bf); // filterbank index n++; // number of output samples } // filterbank index rolled over; update states _q->tau -= 1.0f; // instantaneous fractional offset _q->bf -= (float)(_q->npfb); // filterbank index (soft) _q->b -= _q->npfb; // filterbank index // set output number of samples written *_ny = n; return LIQUID_OK; } // advance synchronizer's internal loop filter // _q : synchronizer object // _mf : matched-filter output // _dmf : derivative matched-filter output int SYMSYNC(_advance_internal_loop)(SYMSYNC() _q, TO _mf, TO _dmf) { // 1. compute timing error signal, clipping large levels #if 0 _q->q = crealf(_mf)*crealf(_dmf) + cimagf(_mf)*cimagf(_dmf); #else // TODO : use more efficient method to compute this _q->q = crealf( conjf(_mf)*_dmf ); // [Mengali:1997] Eq.~(8.3.5) #endif // constrain timing error if (_q->q > 1.0f) _q->q = 1.0f; // clip large positive values else if (_q->q < -1.0f) _q->q = -1.0f; // clip large negative values // 2. filter error signal through timing loop filter: retain large // portion of old estimate and small percent of new estimate iirfiltsos_rrrf_execute(_q->pll, _q->q, &_q->q_hat); // 3. update rate and timing phase _q->rate += _q->rate_adjustment * _q->q_hat; _q->del = _q->rate + _q->q_hat; return LIQUID_OK; } liquid-dsp-1.7.0/src/filter/tests/000077500000000000000000000000001474751757600170375ustar00rootroot00000000000000liquid-dsp-1.7.0/src/filter/tests/data/000077500000000000000000000000001474751757600177505ustar00rootroot00000000000000liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_cccf_data_h13x256.c000066400000000000000000000657331474751757600246370ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_cccf_data_h13x256.c: autotest fftfilt data // #include float complex fftfilt_cccf_data_h13x256_h[] = { 0.101274943352 + -0.122793912888*_Complex_I, 0.058305418491 + -0.133282411098*_Complex_I, 0.040646758676 + -0.024372637272*_Complex_I, 0.079661983252 + -0.054072910547*_Complex_I, 0.001840994880 + 0.061087465286*_Complex_I, -0.087824678421 + -0.017600339651*_Complex_I, 0.218935108185 + -0.191448485851*_Complex_I, 0.063519352674 + 0.238570642471*_Complex_I, 0.062901532650 + 0.024227905273*_Complex_I, 0.047201344371 + -0.122910189629*_Complex_I, -0.052710837126 + -0.028337442875*_Complex_I, 0.155722010136 + -0.206684422493*_Complex_I, 0.158807659149 + -0.032457110286*_Complex_I}; float complex fftfilt_cccf_data_h13x256_x[] = { 0.033812573552 + 0.167574334145*_Complex_I, -0.180972433090 + 0.003268009797*_Complex_I, -0.158811461926 + 0.096975576878*_Complex_I, 0.089864820242 + -0.129931354523*_Complex_I, -0.048388853669 + 0.209818410873*_Complex_I, -0.174670159817 + -0.000558722531*_Complex_I, 0.184307169914 + -0.097096782923*_Complex_I, 0.055431371927 + -0.085229063034*_Complex_I, -0.005678167194 + -0.008018184453*_Complex_I, -0.069053018093 + 0.055740833282*_Complex_I, -0.064427644014 + 0.147326159477*_Complex_I, 0.257856726646 + -0.008164577186*_Complex_I, -0.001989185810 + -0.019182929397*_Complex_I, 0.034131622314 + -0.019393232465*_Complex_I, 0.107628858089 + 0.122120463848*_Complex_I, 0.023927879333 + 0.069706928730*_Complex_I, -0.053020107746 + -0.083087205887*_Complex_I, -0.080838572979 + -0.011525543034*_Complex_I, 0.031260085106 + 0.001133395731*_Complex_I, -0.001233685296 + -0.189275312424*_Complex_I, -0.038783121109 + 0.028758850694*_Complex_I, 0.036648643017 + -0.011882914603*_Complex_I, -0.020449468493 + 0.139192247391*_Complex_I, -0.075582921505 + -0.002107951231*_Complex_I, -0.181470632553 + -0.014771178365*_Complex_I, 0.026783564687 + -0.128984892368*_Complex_I, -0.047539860010 + 0.222328519821*_Complex_I, 0.005170624331 + 0.030745416880*_Complex_I, 0.053824990988 + -0.026686629653*_Complex_I, 0.099266970158 + -0.031245106459*_Complex_I, 0.039606907964 + -0.065418809652*_Complex_I, -0.127475917339 + 0.064139616489*_Complex_I, -0.042834937572 + -0.150583517551*_Complex_I, 0.139883732796 + 0.082940441370*_Complex_I, -0.064364117384 + -0.044677674770*_Complex_I, 0.055855596066 + 0.017247803509*_Complex_I, -0.173977994919 + -0.052533900738*_Complex_I, 0.027730098367 + 0.080870586634*_Complex_I, -0.091971349716 + -0.051875424385*_Complex_I, 0.051230835915 + -0.061945867538*_Complex_I, -0.044583868980 + -0.032021436095*_Complex_I, 0.068678015471 + -0.015937516093*_Complex_I, 0.019641043246 + 0.090001666546*_Complex_I, -0.050730788708 + -0.067964708805*_Complex_I, -0.117348599434 + 0.225804829597*_Complex_I, -0.024700947106 + -0.226277422905*_Complex_I, 0.044463178515 + 0.038473030925*_Complex_I, 0.146118962765 + 0.228452873230*_Complex_I, 0.148312568665 + -0.089482551813*_Complex_I, 0.002765571699 + 0.218297338486*_Complex_I, -0.058677202463 + -0.040143096447*_Complex_I, 0.151873219013 + 0.038929876685*_Complex_I, -0.054030978680 + 0.087771093845*_Complex_I, 0.053254860640 + -0.107342064381*_Complex_I, -0.004281488806 + -0.147849392891*_Complex_I, 0.124097406864 + -0.161590623856*_Complex_I, -0.083864957094 + 0.077308541536*_Complex_I, 0.091537797451 + 0.140995931625*_Complex_I, -0.099840551615 + 0.043124458194*_Complex_I, -0.121636021137 + 0.081380259991*_Complex_I, -0.011938279122 + 0.019365566969*_Complex_I, -0.029302325845 + -0.002548613772*_Complex_I, 0.039761963487 + 0.151991939545*_Complex_I, 0.057192808390 + -0.059029465914*_Complex_I, -0.095872926712 + -0.044790551066*_Complex_I, 0.095753777027 + -0.164024686813*_Complex_I, 0.037644055486 + -0.033171021938*_Complex_I, 0.071704179049 + 0.047472149134*_Complex_I, -0.072857999802 + 0.045551717281*_Complex_I, -0.004142929241 + -0.048290520906*_Complex_I, -0.180688798428 + 0.006293178350*_Complex_I, 0.038382813334 + 0.122165417671*_Complex_I, -0.050295007229 + -0.127239310741*_Complex_I, -0.109994089603 + -0.176806294918*_Complex_I, 0.085634392500 + -0.091329562664*_Complex_I, -0.137377023697 + 0.066401362419*_Complex_I, 0.109237027168 + -0.000195262639*_Complex_I, -0.111181199551 + 0.181575310230*_Complex_I, -0.088704961538 + 0.101208889484*_Complex_I, 0.227800679207 + 0.017428271472*_Complex_I, -0.072724056244 + -0.158883297443*_Complex_I, -0.046088048816 + 0.034102421999*_Complex_I, -0.086277353764 + 0.048207068443*_Complex_I, 0.189791500568 + 0.111536753178*_Complex_I, 0.043753921986 + 0.042386168242*_Complex_I, 0.175305640697 + -0.077729618549*_Complex_I, -0.090353775024 + -0.086115002632*_Complex_I, 0.163218414783 + 0.005952451378*_Complex_I, -0.010694872588 + 0.037079387903*_Complex_I, -0.067783647776 + 0.015387859941*_Complex_I, -0.001508052554 + 0.005860465765*_Complex_I, -0.103225553036 + -0.091570162773*_Complex_I, -0.181873428822 + -0.033351799846*_Complex_I, 0.014190819860 + -0.107816028595*_Complex_I, 0.049625259638 + -0.131252551079*_Complex_I, -0.003888563812 + -0.083181303740*_Complex_I, -0.044093203545 + 0.053719127178*_Complex_I, -0.059636509418 + -0.062606734037*_Complex_I, 0.043757092953 + 0.143932354450*_Complex_I, 0.023032055795 + -0.073675203323*_Complex_I, 0.074079465866 + -0.133735966682*_Complex_I, -0.016778314114 + -0.077572107315*_Complex_I, -0.213720870018 + -0.010327737033*_Complex_I, -0.011057607085 + 0.039916378260*_Complex_I, 0.108575832844 + -0.097652089596*_Complex_I, 0.169485592842 + 0.195236229897*_Complex_I, -0.094353854656 + -0.053460478783*_Complex_I, -0.111175501347 + -0.177497363091*_Complex_I, 0.004201298580 + -0.125308763981*_Complex_I, 0.051966518164 + 0.123850774765*_Complex_I, -0.096300393343 + -0.013914050162*_Complex_I, 0.106172311306 + -0.164844048023*_Complex_I, 0.124734151363 + -0.008266538382*_Complex_I, -0.008394107223 + 0.042837706208*_Complex_I, -0.269948434830 + -0.133680295944*_Complex_I, 0.077266824245 + 0.018269205093*_Complex_I, -0.018016268313 + -0.040084049106*_Complex_I, 0.095163732767 + 0.081313228607*_Complex_I, -0.208993816376 + -0.040263220668*_Complex_I, 0.064939141273 + -0.018769615889*_Complex_I, -0.037253284454 + -0.092296826839*_Complex_I, 0.123162364960 + 0.068240380287*_Complex_I, -0.132501530647 + -0.228929615021*_Complex_I, 0.168357527256 + -0.092901027203*_Complex_I, 0.088688296080 + -0.001608422026*_Complex_I, 0.221683001518 + 0.066785657406*_Complex_I, 0.083319008350 + -0.164619421959*_Complex_I, -0.057560896873 + 0.080689120293*_Complex_I, 0.017244935036 + -0.052605807781*_Complex_I, -0.103263401985 + 0.128316771984*_Complex_I, -0.048902520537 + 0.101460754871*_Complex_I, -0.101036417484 + 0.059622770548*_Complex_I, -0.006965886056 + 0.062334090471*_Complex_I, 0.098089504242 + 0.189659333229*_Complex_I, -0.170798206329 + 0.049062070251*_Complex_I, 0.165300846100 + 0.029215490818*_Complex_I, -0.075640136003 + -0.087369698286*_Complex_I, -0.013823843002 + 0.127059864998*_Complex_I, 0.095502263308 + 0.068228989840*_Complex_I, 0.171380794048 + -0.077519750595*_Complex_I, 0.129892742634 + -0.012643009424*_Complex_I, 0.023339818418 + 0.093716734648*_Complex_I, -0.058398854733 + 0.106715428829*_Complex_I, -0.013301552832 + 0.002579919435*_Complex_I, 0.088806277514 + -0.297042322159*_Complex_I, -0.046128720045 + 0.126318335533*_Complex_I, 0.051016080379 + -0.158195829391*_Complex_I, -0.137489342690 + 0.012126408517*_Complex_I, 0.076124078035 + 0.094534236193*_Complex_I, 0.055480271578 + 0.034476712346*_Complex_I, 0.197368288040 + -0.003630393744*_Complex_I, -0.132637274265 + 0.016389763355*_Complex_I, -0.018736995757 + 0.069434946775*_Complex_I, 0.024380022287 + 0.032195645571*_Complex_I, -0.110287964344 + 0.105914473534*_Complex_I, 0.180047070980 + 0.122122013569*_Complex_I, 0.021164430678 + -0.021511299908*_Complex_I, -0.083895099163 + -0.094187325239*_Complex_I, -0.085609924793 + -0.089779102802*_Complex_I, -0.026364889741 + -0.034728026390*_Complex_I, -0.039741188288 + 0.061549043655*_Complex_I, -0.182061326504 + -0.117300724983*_Complex_I, 0.051411151886 + -0.039550358057*_Complex_I, 0.115115880966 + 0.132340645790*_Complex_I, -0.172311210632 + 0.157257282734*_Complex_I, -0.066816413403 + 0.050810027122*_Complex_I, 0.075493675470 + -0.024358917773*_Complex_I, 0.037579393387 + -0.105334246159*_Complex_I, -0.032166060805 + 0.304082226753*_Complex_I, -0.115465772152 + -0.083099174500*_Complex_I, 0.213583827019 + -0.033120486140*_Complex_I, 0.049020007253 + 0.103692758083*_Complex_I, 0.039526313543 + 0.159559214115*_Complex_I, -0.014911358058 + -0.009031812847*_Complex_I, 0.140197467804 + 0.188218057156*_Complex_I, -0.014860840142 + -0.114006638527*_Complex_I, 0.111025202274 + -0.101571118832*_Complex_I, -0.031162160635 + -0.044938939810*_Complex_I, -0.088898491859 + -0.196167945862*_Complex_I, 0.074709993601 + -0.042812746763*_Complex_I, 0.020372083783 + -0.102141439915*_Complex_I, 0.036488103867 + 0.061840379238*_Complex_I, 0.113381445408 + -0.077737921476*_Complex_I, 0.003184536844 + 0.024977919459*_Complex_I, -0.130429613590 + -0.062496966124*_Complex_I, -0.109437787533 + 0.033421832323*_Complex_I, -0.107781338692 + -0.036825361848*_Complex_I, -0.121548032761 + -0.071893042326*_Complex_I, -0.032831138372 + 0.036911919713*_Complex_I, 0.101628661156 + 0.116993212700*_Complex_I, -0.052929800749 + -0.061160600185*_Complex_I, -0.155849313736 + -0.126586461067*_Complex_I, -0.093626201153 + -0.085899829865*_Complex_I, 0.093120694160 + 0.010586068779*_Complex_I, -0.071643483639 + 0.044553604722*_Complex_I, 0.096362644434 + -0.005238156021*_Complex_I, -0.191972267628 + 0.062410986423*_Complex_I, 0.175240826607 + 0.055103266239*_Complex_I, 0.217493343353 + 0.057524204254*_Complex_I, 0.137563228607 + 0.136677563190*_Complex_I, -0.002121994831 + -0.160035789013*_Complex_I, -0.106702613831 + 0.129322338104*_Complex_I, 0.077257323265 + 0.190817809105*_Complex_I, 0.030118304491 + 0.068840289116*_Complex_I, 0.001969731040 + -0.019872169197*_Complex_I, 0.038756659627 + -0.110168564320*_Complex_I, -0.094096481800 + 0.178715145588*_Complex_I, -0.045212453604 + -0.001988123916*_Complex_I, -0.050746786594 + -0.038362777233*_Complex_I, 0.085383939743 + 0.041049334407*_Complex_I, -0.044858980179 + 0.073414093256*_Complex_I, 0.074703049660 + 0.103927171230*_Complex_I, 0.055366307497 + -0.115881478786*_Complex_I, 0.133115530014 + -0.054990023375*_Complex_I, -0.060879433155 + -0.052990645170*_Complex_I, -0.014458604157 + 0.024620576203*_Complex_I, 0.035869082808 + 0.070715308189*_Complex_I, 0.001854417846 + -0.032330670953*_Complex_I, 0.217453384399 + -0.031029167771*_Complex_I, -0.012186873704 + 0.007021924853*_Complex_I, 0.082451862097 + -0.078747928143*_Complex_I, -0.079927939177 + -0.026517114043*_Complex_I, -0.049421241879 + -0.003672285378*_Complex_I, -0.050635516644 + -0.204359102249*_Complex_I, 0.114336001873 + -0.075574308634*_Complex_I, 0.017275553942 + -0.004209178686*_Complex_I, 0.093194973469 + -0.117229437828*_Complex_I, 0.055422365665 + 0.058078074455*_Complex_I, 0.051127582788 + -0.056875407696*_Complex_I, -0.033710032701 + -0.024449241161*_Complex_I, 0.098715597391 + 0.075275701284*_Complex_I, 0.049691435695 + -0.010312996805*_Complex_I, -0.143938088417 + -0.057803511620*_Complex_I, 0.004402134567 + -0.171495795250*_Complex_I, 0.050372958183 + -0.030280271173*_Complex_I, -0.066968792677 + 0.049716952443*_Complex_I, -0.030198466778 + -0.093219310045*_Complex_I, 0.020674671233 + 0.049302938581*_Complex_I, -0.082176977396 + 0.004003078118*_Complex_I, 0.051144361496 + -0.025944027305*_Complex_I, -0.136934876442 + 0.030611222982*_Complex_I, 0.072055798769 + 0.072714412212*_Complex_I, 0.006607705355 + -0.154940152168*_Complex_I, -0.055419456959 + 0.142084217072*_Complex_I, 0.127882242203 + -0.068437719345*_Complex_I, -0.028541901708 + 0.125126791000*_Complex_I, -0.071173512936 + 0.003831871226*_Complex_I, -0.040117982030 + -0.071510893106*_Complex_I, -0.036725261807 + 0.037219762802*_Complex_I, 0.018186755478 + 0.046204718947*_Complex_I, 0.145269620419 + 0.059547924995*_Complex_I, 0.040549764037 + 0.051019173861*_Complex_I, 0.017368020117 + 0.015167059004*_Complex_I, 0.018691918254 + -0.096917903423*_Complex_I, 0.085063648224 + 0.024469487369*_Complex_I, 0.107211554050 + -0.066898560524*_Complex_I}; float complex fftfilt_cccf_data_h13x256_y[] = { 0.024001474660 + 0.012819102986*_Complex_I, 0.006379486345 + 0.027817151043*_Complex_I, -0.008833116513 + 0.059620513709*_Complex_I, 0.001290360957 + 0.018691901680*_Complex_I, -0.019720088289 + 0.027870569701*_Complex_I, -0.000089104333 + 0.022554509191*_Complex_I, 0.048983753430 + 0.008870419475*_Complex_I, -0.059738782036 + 0.031503141884*_Complex_I, -0.072004160761 + 0.015777738903*_Complex_I, -0.011979216083 + -0.114153406857*_Complex_I, 0.084719374355 + 0.122759620341*_Complex_I, -0.002652524124 + 0.074081920456*_Complex_I, -0.010647425116 + -0.055247615062*_Complex_I, 0.009826036454 + 0.077018691837*_Complex_I, 0.043050527194 + -0.030195436945*_Complex_I, 0.096977257426 + 0.014196001707*_Complex_I, -0.069749349540 + 0.084922275308*_Complex_I, -0.020592821729 + -0.078815687497*_Complex_I, 0.015344750806 + 0.046911643882*_Complex_I, 0.003215160982 + -0.044654666098*_Complex_I, 0.045065388666 + -0.014762372700*_Complex_I, -0.000649914548 + 0.078685026348*_Complex_I, 0.004242245469 + -0.018256519858*_Complex_I, 0.068463378080 + 0.002186618045*_Complex_I, -0.013886532699 + -0.006164365808*_Complex_I, -0.023002266230 + -0.024231940574*_Complex_I, 0.059444806653 + 0.063727454712*_Complex_I, 0.005199838368 + -0.013523702394*_Complex_I, -0.014439329476 + 0.017624416202*_Complex_I, -0.021969811821 + 0.031968738864*_Complex_I, -0.099775723814 + -0.032339826558*_Complex_I, -0.023202788664 + -0.102402077252*_Complex_I, 0.039130993156 + 0.049187762643*_Complex_I, -0.024993065771 + 0.041659056463*_Complex_I, -0.035177096744 + 0.034267402820*_Complex_I, -0.012813786527 + 0.035585893453*_Complex_I, -0.010166359548 + -0.030098941996*_Complex_I, 0.035012509492 + 0.104480427481*_Complex_I, -0.067925226605 + -0.033727903935*_Complex_I, 0.038150929611 + -0.034144316119*_Complex_I, -0.031836563804 + 0.003970737127*_Complex_I, 0.022331990340 + -0.044052273250*_Complex_I, -0.024273008320 + 0.027787498353*_Complex_I, -0.035557076930 + -0.024109903696*_Complex_I, -0.015439201027 + 0.010120871946*_Complex_I, -0.005667692817 + 0.009808534446*_Complex_I, -0.023993809759 + -0.001976323260*_Complex_I, 0.033939569756 + 0.006322746502*_Complex_I, 0.038339628046 + -0.021022149468*_Complex_I, 0.000846072793 + 0.018029554697*_Complex_I, 0.053339414921 + 0.071529172443*_Complex_I, -0.104230849664 + -0.080895763503*_Complex_I, 0.071647820798 + -0.030732758724*_Complex_I, 0.101421268066 + 0.054142700304*_Complex_I, -0.070017141172 + -0.048691110375*_Complex_I, 0.071783266356 + 0.132628048489*_Complex_I, -0.125892768778 + -0.020392469132*_Complex_I, 0.077534371443 + -0.106386873570*_Complex_I, 0.118899511278 + 0.091045477209*_Complex_I, 0.019035177150 + 0.019334344232*_Complex_I, 0.072542950409 + 0.021775500164*_Complex_I, 0.018913391291 + -0.008423771096*_Complex_I, 0.068880105631 + 0.006805725914*_Complex_I, 0.070165826853 + -0.001076549347*_Complex_I, -0.092150026143 + 0.032247576962*_Complex_I, -0.065407227079 + -0.006168603538*_Complex_I, -0.051509544946 + -0.131615847220*_Complex_I, -0.001170276180 + -0.019427264753*_Complex_I, 0.083364051792 + 0.041323212038*_Complex_I, 0.007295606110 + 0.057364049960*_Complex_I, -0.057103564464 + 0.118719947312*_Complex_I, 0.004531748675 + -0.012147464062*_Complex_I, 0.012749373222 + -0.030480391526*_Complex_I, 0.011125930632 + 0.028825825693*_Complex_I, -0.043938238280 + 0.011854121979*_Complex_I, -0.075321232264 + -0.018064459135*_Complex_I, -0.060886977242 + -0.042110048390*_Complex_I, 0.056409867179 + -0.045351450134*_Complex_I, -0.018186918127 + 0.057805159108*_Complex_I, -0.000535255779 + 0.017342658310*_Complex_I, 0.044187556819 + -0.080806819744*_Complex_I, -0.077107500264 + 0.074314966560*_Complex_I, -0.000316037199 + -0.033151523412*_Complex_I, 0.004502285827 + 0.096977958968*_Complex_I, -0.093482268512 + 0.004941127824*_Complex_I, 0.021543628024 + -0.127138737110*_Complex_I, -0.024144738766 + 0.045799607631*_Complex_I, 0.073683578652 + -0.012636723694*_Complex_I, 0.037103315594 + -0.019525859806*_Complex_I, -0.000690801053 + 0.046026880071*_Complex_I, 0.026954746660 + 0.048691313027*_Complex_I, 0.007353638085 + 0.001105524364*_Complex_I, -0.054855624724 + 0.041421970378*_Complex_I, 0.022781842217 + -0.038200366123*_Complex_I, 0.008043522754 + -0.024654798773*_Complex_I, -0.026166674166 + 0.009031999284*_Complex_I, 0.015652619885 + -0.077945632696*_Complex_I, -0.049664412838 + -0.015226397097*_Complex_I, -0.011383210898 + -0.016385255644*_Complex_I, 0.020234061901 + -0.066780782463*_Complex_I, -0.046755003222 + -0.039668549878*_Complex_I, -0.003720962630 + -0.011626088440*_Complex_I, -0.053663894051 + 0.033112538916*_Complex_I, -0.121787017031 + 0.003208574048*_Complex_I, -0.028376450272 + -0.019370775859*_Complex_I, -0.047890954007 + -0.041473896341*_Complex_I, 0.011519092293 + -0.078183218332*_Complex_I, 0.028829438437 + 0.001487290342*_Complex_I, -0.075450909852 + 0.021430470386*_Complex_I, -0.034355836889 + -0.040885483718*_Complex_I, -0.058002545755 + -0.068146319622*_Complex_I, 0.075219933002 + -0.010912041314*_Complex_I, -0.036651133000 + 0.019765597603*_Complex_I, -0.098981225134 + -0.018643142319*_Complex_I, -0.032500295138 + -0.084155976688*_Complex_I, 0.049578122325 + -0.016429877737*_Complex_I, -0.013361520737 + 0.029138302084*_Complex_I, -0.043356913875 + -0.030952278560*_Complex_I, 0.014132503851 + -0.028805299647*_Complex_I, -0.017867267512 + 0.026284047653*_Complex_I, -0.083047255042 + -0.017096821986*_Complex_I, 0.008417904103 + -0.048597238033*_Complex_I, -0.089743880041 + -0.096283355401*_Complex_I, 0.035975823890 + -0.056271631450*_Complex_I, -0.015269531402 + 0.017064247022*_Complex_I, -0.053012454761 + -0.057229106407*_Complex_I, -0.020365053756 + -0.125161538208*_Complex_I, 0.066674345673 + 0.011158699255*_Complex_I, -0.036133831454 + -0.011201495817*_Complex_I, 0.016361003153 + -0.025706876818*_Complex_I, 0.044163879016 + 0.016897283579*_Complex_I, 0.016023914791 + 0.021215167172*_Complex_I, 0.029810334754 + 0.009766734291*_Complex_I, 0.035636470208 + 0.060987445145*_Complex_I, -0.006302550511 + -0.115013574847*_Complex_I, 0.051720848730 + -0.009461663454*_Complex_I, 0.047973920047 + -0.016849009904*_Complex_I, -0.046701499921 + 0.016919642862*_Complex_I, 0.043467132678 + -0.016102822186*_Complex_I, 0.067871787511 + 0.010066831600*_Complex_I, -0.035710415892 + 0.082788003225*_Complex_I, 0.069725504265 + -0.005507023393*_Complex_I, 0.015433685804 + 0.073521250471*_Complex_I, 0.063438026419 + 0.060901474404*_Complex_I, 0.041153827196 + -0.018596637068*_Complex_I, -0.048641595104 + 0.055630921150*_Complex_I, 0.070785738691 + -0.021001547792*_Complex_I, 0.030058519696 + 0.002719657788*_Complex_I, 0.033781571029 + 0.057641496421*_Complex_I, -0.011861512115 + -0.000934312027*_Complex_I, 0.026823353697 + -0.148020696569*_Complex_I, 0.149407622218 + -0.001917493861*_Complex_I, 0.031564264895 + -0.033648864447*_Complex_I, 0.013500408643 + 0.049606336179*_Complex_I, 0.018200592161 + 0.054843460925*_Complex_I, -0.042220409610 + -0.057168354901*_Complex_I, 0.087247514708 + -0.025386591035*_Complex_I, -0.028531902133 + 0.071536103147*_Complex_I, -0.025160173288 + -0.020151250712*_Complex_I, -0.022772795332 + -0.017187718098*_Complex_I, -0.029078837193 + 0.069628451313*_Complex_I, 0.049111894335 + -0.041621311215*_Complex_I, -0.023619794976 + 0.077908526801*_Complex_I, 0.000333911391 + 0.053474867787*_Complex_I, 0.029475675088 + -0.009019730084*_Complex_I, 0.034174066620 + 0.017898879791*_Complex_I, 0.065544425508 + 0.045084590196*_Complex_I, -0.090015977785 + 0.028850540224*_Complex_I, -0.012871094837 + -0.054608369039*_Complex_I, 0.047544364344 + 0.008538257328*_Complex_I, -0.063104697961 + 0.090294378190*_Complex_I, -0.011929275791 + 0.022601352310*_Complex_I, -0.047521622205 + 0.007445085519*_Complex_I, 0.022958962838 + -0.062917965176*_Complex_I, 0.214158563544 + 0.108130217870*_Complex_I, -0.073961792459 + 0.071479678221*_Complex_I, -0.015320084620 + -0.052303661814*_Complex_I, 0.077538995397 + 0.033838920671*_Complex_I, -0.034556396252 + 0.000838447098*_Complex_I, 0.000060541807 + -0.004333615826*_Complex_I, 0.019595150038 + 0.059919909742*_Complex_I, -0.060268723573 + -0.056864079389*_Complex_I, 0.125955282742 + -0.089792980055*_Complex_I, 0.104088003218 + 0.030894546232*_Complex_I, -0.057778045852 + -0.020383254417*_Complex_I, 0.072179136454 + -0.043422298997*_Complex_I, -0.033946126046 + 0.018129630965*_Complex_I, -0.049055572484 + -0.016390359113*_Complex_I, -0.025066786874 + -0.031503746350*_Complex_I, -0.027009840982 + 0.016252291912*_Complex_I, -0.042713013603 + -0.046577467289*_Complex_I, -0.046395432817 + -0.042034197104*_Complex_I, -0.066951975959 + -0.006293309275*_Complex_I, -0.076584206559 + -0.038789936400*_Complex_I, 0.005278362238 + -0.031661049359*_Complex_I, 0.006878243906 + 0.019853143294*_Complex_I, -0.074683265419 + 0.092712646012*_Complex_I, -0.048535905143 + 0.066894323514*_Complex_I, -0.011718308326 + -0.093940704974*_Complex_I, 0.054231403971 + -0.067545703916*_Complex_I, 0.027390269161 + 0.013522266374*_Complex_I, 0.027113327798 + 0.025183265482*_Complex_I, -0.041823544233 + 0.108944472361*_Complex_I, -0.030438012256 + -0.063572748831*_Complex_I, 0.066074070111 + -0.020231915298*_Complex_I, 0.069140337649 + 0.114893641537*_Complex_I, -0.005919906768 + 0.004293077149*_Complex_I, 0.056489424450 + 0.068597409742*_Complex_I, 0.027928885781 + -0.031072362986*_Complex_I, 0.033715956662 + 0.016500309835*_Complex_I, 0.066646875440 + 0.052841945423*_Complex_I, 0.059048505781 + -0.044714082918*_Complex_I, 0.083521538493 + 0.040432491516*_Complex_I, -0.015140885802 + 0.007398722932*_Complex_I, -0.018685866288 + -0.005688072534*_Complex_I, 0.037444281102 + -0.001275030615*_Complex_I, 0.009248759930 + 0.000917465357*_Complex_I, 0.037078087936 + 0.054897922621*_Complex_I, -0.032804989991 + -0.001205514200*_Complex_I, 0.049475279806 + -0.034629284571*_Complex_I, 0.040449266799 + -0.025094164230*_Complex_I, 0.028840625614 + -0.034271290637*_Complex_I, 0.022502076079 + 0.028207110264*_Complex_I, -0.095209370089 + -0.024287776579*_Complex_I, 0.036853780217 + -0.112642535014*_Complex_I, 0.011055463457 + 0.014755419711*_Complex_I, -0.007470671462 + -0.082840060740*_Complex_I, 0.049493876654 + -0.029503227741*_Complex_I, 0.003287878646 + -0.011760309552*_Complex_I, -0.052454911751 + -0.135685038742*_Complex_I, 0.100557451271 + -0.060727168658*_Complex_I, 0.030460767615 + -0.025297334320*_Complex_I, -0.041900949710 + -0.044189282191*_Complex_I, 0.002239369339 + 0.018583017194*_Complex_I, -0.094251314287 + -0.045638715401*_Complex_I, -0.043687223316 + -0.073236757137*_Complex_I, 0.042678054726 + -0.053958008845*_Complex_I, -0.000338320251 + -0.031016295417*_Complex_I, -0.017513369486 + 0.046863199684*_Complex_I, -0.017742806904 + -0.098421945495*_Complex_I, 0.035630421170 + -0.042774040828*_Complex_I, 0.023161832990 + 0.056833847742*_Complex_I, -0.035822048154 + -0.064590977441*_Complex_I, -0.008387640915 + 0.040501176809*_Complex_I, -0.068025770572 + -0.021755292254*_Complex_I, 0.001359162188 + -0.081310455090*_Complex_I, 0.012404768734 + 0.083535778559*_Complex_I, -0.038725035226 + -0.008917515519*_Complex_I, -0.038625918697 + -0.011541140189*_Complex_I, 0.023371955995 + 0.096714602422*_Complex_I, 0.017691840656 + -0.095198285220*_Complex_I, 0.045385440171 + 0.068921408368*_Complex_I, 0.002806803285 + 0.044993613294*_Complex_I, -0.033553704471 + -0.075678324986*_Complex_I, 0.033838944413 + 0.008301990809*_Complex_I, 0.001278998079 + -0.054009422018*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_cccf_data_h23x256.c000066400000000000000000000667171474751757600246430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_cccf_data_h23x256.c: autotest fftfilt data // #include float complex fftfilt_cccf_data_h23x256_h[] = { -0.113265895844 + -0.022710527480*_Complex_I, 0.017113091052 + -0.012686794996*_Complex_I, -0.115593445301 + -0.088176310062*_Complex_I, -0.013192173839 + 0.146348237991*_Complex_I, -0.103383064270 + -0.047336477041*_Complex_I, 0.075577318668 + -0.044972211123*_Complex_I, 0.142312300205 + -0.064133465290*_Complex_I, -0.221127843857 + 0.014621888101*_Complex_I, -0.058339691162 + -0.140489292145*_Complex_I, -0.038768473268 + 0.063463032246*_Complex_I, -0.066909837723 + -0.194865047932*_Complex_I, 0.113466823101 + -0.236079573631*_Complex_I, 0.025802928209 + -0.126112377644*_Complex_I, -0.025553426147 + -0.205878305435*_Complex_I, -0.036806601286 + 0.039826345444*_Complex_I, -0.069977194071 + -0.241963529587*_Complex_I, 0.067285501957 + -0.138619136810*_Complex_I, -0.216540384293 + -0.094396740198*_Complex_I, 0.053344154358 + -0.034197300673*_Complex_I, -0.094768559933 + -0.246735548973*_Complex_I, 0.026606693864 + -0.040954247117*_Complex_I, 0.048448944092 + 0.068329632282*_Complex_I, 0.053360801935 + 0.035232502222*_Complex_I}; float complex fftfilt_cccf_data_h23x256_x[] = { 0.045492258668 + 0.087591451406*_Complex_I, -0.360275936127 + -0.244660735130*_Complex_I, -0.076566338539 + 0.085396862030*_Complex_I, -0.010159610212 + -0.099646502733*_Complex_I, 0.106244933605 + -0.035118606687*_Complex_I, 0.004351182655 + 0.104901087284*_Complex_I, 0.060583090782 + 0.090451103449*_Complex_I, -0.009854796529 + -0.159225010872*_Complex_I, 0.123082661629 + -0.013109473884*_Complex_I, -0.042733341455 + 0.038194873929*_Complex_I, 0.059678620100 + -0.141551160812*_Complex_I, -0.004473050311 + 0.106543672085*_Complex_I, 0.099794340134 + -0.143291473389*_Complex_I, -0.044146090746 + 0.066736018658*_Complex_I, -0.059895306826 + 0.166889667511*_Complex_I, 0.076762962341 + -0.058477646112*_Complex_I, -0.031721797585 + -0.070060622692*_Complex_I, -0.030031725764 + 0.018004868925*_Complex_I, -0.132683742046 + 0.047249066830*_Complex_I, -0.017683801055 + -0.110559308529*_Complex_I, -0.089177983999 + 0.128147161007*_Complex_I, -0.058403855562 + -0.253948712349*_Complex_I, 0.155546200275 + -0.033433157206*_Complex_I, 0.019463591278 + 0.087873625755*_Complex_I, 0.175985527039 + 0.134090995789*_Complex_I, 0.005070775002 + 0.023215842247*_Complex_I, -0.183340942860 + 0.061269021034*_Complex_I, -0.282386708260 + 0.050984662771*_Complex_I, -0.150776374340 + 0.111193597317*_Complex_I, -0.092933952808 + 0.014530903101*_Complex_I, -0.025000396371 + -0.020265173912*_Complex_I, 0.130480492115 + 0.031612247229*_Complex_I, 0.100867581367 + -0.229012298584*_Complex_I, -0.082832515240 + 0.091525465250*_Complex_I, 0.048790007830 + 0.014641028643*_Complex_I, -0.072996783257 + -0.022627115250*_Complex_I, 0.076681035757 + -0.090442115068*_Complex_I, -0.036189466715 + -0.120588958263*_Complex_I, -0.100714707375 + -0.106518495083*_Complex_I, -0.321345973015 + -0.129095542431*_Complex_I, -0.041321143508 + -0.097576838732*_Complex_I, -0.074389326572 + 0.045334511995*_Complex_I, 0.136498391628 + 0.096301412582*_Complex_I, 0.191800594330 + -0.083850991726*_Complex_I, 0.163151848316 + -0.054458898306*_Complex_I, -0.001362276729 + -0.030826401711*_Complex_I, -0.030661305785 + -0.240707612038*_Complex_I, -0.255475115776 + 0.166176271439*_Complex_I, -0.087870460749 + 0.138075506687*_Complex_I, 0.063871967793 + -0.167130613327*_Complex_I, -0.167199540138 + -0.085400974751*_Complex_I, 0.050435560942 + -0.040156632662*_Complex_I, 0.057380825281 + 0.090105038881*_Complex_I, -0.040529885888 + -0.006345084310*_Complex_I, 0.112770903111 + 0.106182515621*_Complex_I, 0.128458249569 + 0.066667920351*_Complex_I, 0.083549374342 + -0.086842793226*_Complex_I, 0.144279420376 + 0.133334076405*_Complex_I, -0.137241375446 + 0.032534021139*_Complex_I, -0.023988795280 + 0.049458268285*_Complex_I, 0.076303368807 + 0.020058257878*_Complex_I, -0.154448091984 + -0.050609207153*_Complex_I, 0.165292298794 + 0.070755618811*_Complex_I, 0.005886135250 + -0.036164498329*_Complex_I, -0.037918183208 + -0.019724342227*_Complex_I, 0.026809751987 + -0.032598829269*_Complex_I, 0.063324218988 + 0.098319518566*_Complex_I, -0.047398203611 + -0.114408671856*_Complex_I, 0.121957802773 + 0.028821185231*_Complex_I, -0.135715365410 + 0.048073148727*_Complex_I, 0.029720014334 + 0.097452402115*_Complex_I, -0.148619377613 + 0.177626144886*_Complex_I, -0.122573924065 + 0.032197031379*_Complex_I, -0.005472518504 + 0.130435466766*_Complex_I, 0.055357205868 + 0.036867898703*_Complex_I, -0.037471351027 + 0.078105151653*_Complex_I, -0.080862498283 + -0.009199683368*_Complex_I, -0.132427692413 + -0.173398303986*_Complex_I, -0.048274517059 + -0.028256762028*_Complex_I, 0.063550901413 + -0.019138570130*_Complex_I, 0.018642249703 + 0.105512928963*_Complex_I, -0.034507310390 + 0.165678203106*_Complex_I, 0.157479083538 + -0.098934185505*_Complex_I, 0.110079026222 + 0.190422582626*_Complex_I, -0.123567688465 + -0.026369869709*_Complex_I, 0.010789130628 + -0.029063615203*_Complex_I, -0.083237224817 + 0.123224353790*_Complex_I, 0.008147761226 + 0.157242572308*_Complex_I, -0.115900576115 + 0.016479349136*_Complex_I, 0.014385309815 + -0.114978981018*_Complex_I, -0.010936866701 + 0.001918938756*_Complex_I, -0.042773860693 + -0.096163535118*_Complex_I, 0.159630239010 + -0.090808361769*_Complex_I, 0.099759966135 + 0.003752164543*_Complex_I, 0.082647228241 + 0.061170494556*_Complex_I, 0.068049144745 + 0.166794586182*_Complex_I, -0.025365993381 + -0.024766857922*_Complex_I, 0.069112539291 + -0.027834153175*_Complex_I, -0.044352179766 + -0.044707950950*_Complex_I, 0.067422634363 + -0.017061285675*_Complex_I, 0.070048046112 + 0.109582054615*_Complex_I, 0.037835836411 + 0.180136477947*_Complex_I, 0.032625645399 + 0.116918706894*_Complex_I, 0.049541047215 + 0.161158871651*_Complex_I, 0.027160745859 + -0.168793261051*_Complex_I, -0.052759623528 + -0.072317802906*_Complex_I, 0.184534084797 + 0.022903186083*_Complex_I, -0.010724669695 + 0.036121314764*_Complex_I, 0.245871329308 + 0.039303827286*_Complex_I, -0.024940526485 + 0.096528834105*_Complex_I, -0.078127902746 + -0.096756339073*_Complex_I, 0.043826240301 + -0.125324332714*_Complex_I, 0.009783142805 + -0.003001630120*_Complex_I, 0.064857578278 + -0.042588630319*_Complex_I, 0.081423562765 + 0.121582865715*_Complex_I, -0.118639636040 + 0.128098034859*_Complex_I, -0.111134576797 + 0.038534373045*_Complex_I, -0.289731216431 + -0.080021494627*_Complex_I, 0.069585120678 + 0.060569906235*_Complex_I, -0.051440721750 + -0.150054514408*_Complex_I, -0.039673271775 + 0.039142814279*_Complex_I, -0.017449636757 + -0.103529226780*_Complex_I, 0.046975213289 + -0.208591985703*_Complex_I, 0.141377413273 + 0.023652508855*_Complex_I, -0.061699587107 + -0.151958966255*_Complex_I, 0.007653100044 + -0.046074271202*_Complex_I, 0.135512828827 + 0.166977787018*_Complex_I, -0.042983511090 + 0.140523970127*_Complex_I, -0.174354147911 + 0.157390367985*_Complex_I, -0.180938804150 + -0.007540450245*_Complex_I, -0.006038622186 + 0.114250767231*_Complex_I, -0.183260941505 + -0.041695398092*_Complex_I, -0.087769675255 + -0.009365759790*_Complex_I, -0.077232390642 + -0.019897325337*_Complex_I, -0.017668469250 + -0.107637941837*_Complex_I, 0.186912357807 + 0.078892260790*_Complex_I, 0.199635422230 + 0.003066605330*_Complex_I, 0.005723394454 + -0.087536334991*_Complex_I, 0.036157646775 + 0.010726630688*_Complex_I, -0.013097931445 + 0.137133157253*_Complex_I, -0.200704836845 + -0.067425280809*_Complex_I, -0.018093538284 + -0.002605117485*_Complex_I, -0.046316248178 + 0.047676995397*_Complex_I, 0.065687131882 + -0.272353625298*_Complex_I, 0.182847750187 + 0.136976885796*_Complex_I, -0.060609722137 + 0.063969159126*_Complex_I, 0.065259736776 + -0.030771258473*_Complex_I, 0.093584728241 + -0.088571476936*_Complex_I, 0.055487519503 + -0.092523062229*_Complex_I, 0.040360233188 + -0.237069821358*_Complex_I, -0.054889243841 + 0.007436647266*_Complex_I, 0.146980488300 + -0.112567687035*_Complex_I, 0.033167552948 + 0.077278125286*_Complex_I, -0.123007047176 + -0.234244012833*_Complex_I, -0.023877808452 + -0.034760150313*_Complex_I, -0.073663645983 + -0.067232269049*_Complex_I, -0.021728573740 + 0.229374289513*_Complex_I, 0.075998270512 + -0.019796457887*_Complex_I, -0.117255151272 + 0.168271052837*_Complex_I, 0.157391369343 + -0.156538987160*_Complex_I, -0.144393324852 + 0.064253067970*_Complex_I, 0.182558035851 + 0.176998484135*_Complex_I, 0.022407060862 + 0.102678549290*_Complex_I, 0.053511500359 + 0.111569952965*_Complex_I, 0.035490038991 + 0.067579591274*_Complex_I, -0.069553595781 + 0.028308334947*_Complex_I, -0.077684468031 + 0.165951395035*_Complex_I, -0.171819615364 + 0.051840746403*_Complex_I, -0.169814157486 + -0.009480411559*_Complex_I, 0.002353400178 + 0.097526848316*_Complex_I, -0.035275432467 + 0.051336318254*_Complex_I, 0.073788845539 + -0.159921205044*_Complex_I, -0.062105762959 + 0.139204311371*_Complex_I, 0.046410915256 + 0.076092356443*_Complex_I, 0.015324105322 + 0.056624919176*_Complex_I, -0.032998785377 + 0.030960384011*_Complex_I, -0.033524742723 + -0.072809416056*_Complex_I, 0.034249174595 + 0.142128837109*_Complex_I, -0.017137683928 + 0.000054139068*_Complex_I, -0.152735805511 + -0.015746916831*_Complex_I, 0.076812589169 + 0.113819742203*_Complex_I, -0.269065928459 + 0.047783342004*_Complex_I, -0.006360206753 + -0.290388703346*_Complex_I, 0.056451249123 + -0.141728675365*_Complex_I, -0.074260264635 + 0.112913572788*_Complex_I, -0.097910881042 + 0.009142446518*_Complex_I, 0.008521752059 + -0.165642762184*_Complex_I, -0.068459671736 + -0.177522385120*_Complex_I, -0.057727193832 + -0.061166942120*_Complex_I, -0.014851769805 + 0.012171116471*_Complex_I, -0.106043231487 + 0.214376616478*_Complex_I, -0.056457644701 + 0.133102154732*_Complex_I, -0.001181100123 + -0.025020095706*_Complex_I, 0.013895004988 + 0.055028027296*_Complex_I, -0.094381314516 + -0.076402390003*_Complex_I, 0.059590637684 + -0.081801712513*_Complex_I, 0.004246252403 + 0.056055116653*_Complex_I, -0.044613176584 + -0.091410827637*_Complex_I, -0.037342968583 + -0.024862080812*_Complex_I, -0.190127372742 + 0.041265439987*_Complex_I, -0.006639320403 + 0.097943222523*_Complex_I, 0.138125526905 + -0.064016056061*_Complex_I, -0.098870986700 + -0.145059263706*_Complex_I, 0.114810085297 + -0.059086716175*_Complex_I, 0.000181899476 + -0.094249367714*_Complex_I, 0.086499345303 + -0.031394767761*_Complex_I, 0.131707870960 + 0.043413007259*_Complex_I, -0.162042534351 + 0.021535064280*_Complex_I, 0.103580415249 + -0.146205651760*_Complex_I, -0.052903598547 + 0.023014034331*_Complex_I, -0.198558521271 + -0.064298307896*_Complex_I, 0.111735153198 + -0.045897883177*_Complex_I, -0.166142654419 + -0.066890668869*_Complex_I, 0.135389423370 + 0.158303833008*_Complex_I, -0.067218714952 + -0.269701981544*_Complex_I, -0.029925772548 + -0.056027936935*_Complex_I, -0.090524566174 + -0.035552933812*_Complex_I, -0.095090520382 + -0.213347554207*_Complex_I, 0.065363866091 + -0.078422772884*_Complex_I, 0.142836868763 + 0.045737281442*_Complex_I, -0.066659629345 + 0.091496753693*_Complex_I, -0.050436902046 + 0.038852605224*_Complex_I, 0.056302917004 + 0.035658785701*_Complex_I, -0.261968922615 + 0.072266608477*_Complex_I, -0.000278761820 + -0.066401851177*_Complex_I, -0.191342055798 + 0.103529000282*_Complex_I, -0.049295476079 + 0.036229848862*_Complex_I, -0.042302805185 + -0.063734227419*_Complex_I, -0.050776159763 + 0.063683301210*_Complex_I, -0.091268771887 + 0.292417860031*_Complex_I, -0.054572415352 + 0.059356063604*_Complex_I, 0.058717763424 + 0.045334947109*_Complex_I, 0.004559407011 + -0.066553068161*_Complex_I, -0.037161919475 + 0.062294793129*_Complex_I, -0.234697723389 + -0.031746768951*_Complex_I, 0.045789924264 + -0.090054887533*_Complex_I, 0.107681131363 + -0.112842118740*_Complex_I, 0.136971771717 + -0.095520716906*_Complex_I, 0.093264913559 + 0.091368728876*_Complex_I, -0.091999745369 + 0.012484084070*_Complex_I, 0.023904198408 + 0.167766880989*_Complex_I, 0.192737889290 + -0.014556410909*_Complex_I, 0.106241250038 + 0.018227040768*_Complex_I, 0.024921812117 + 0.071124422550*_Complex_I, 0.052874428034 + -0.094483900070*_Complex_I, 0.060024052858 + -0.120348191261*_Complex_I, 0.151742827892 + 0.044160097837*_Complex_I, -0.035461589694 + 0.040138626099*_Complex_I, 0.068723130226 + 0.084313547611*_Complex_I, 0.089995771646 + 0.131840264797*_Complex_I, -0.138497865200 + 0.083961331844*_Complex_I, 0.012439595908 + 0.069563353062*_Complex_I, 0.032783246040 + 0.022058516741*_Complex_I, -0.022213153541 + -0.033352825046*_Complex_I, -0.111178684235 + 0.004780802876*_Complex_I, -0.256052374840 + -0.011545106769*_Complex_I}; float complex fftfilt_cccf_data_h23x256_y[] = { -0.003163473368 + -0.010954277402*_Complex_I, 0.037140370260 + 0.036815583414*_Complex_I, 0.003807251283 + -0.021686181791*_Complex_I, 0.005314097986 + 0.079501236423*_Complex_I, 0.042112632196 + -0.063838542514*_Complex_I, 0.017204891832 + 0.033074981292*_Complex_I, -0.018245137527 + -0.013306853145*_Complex_I, -0.071746576920 + 0.012804254640*_Complex_I, 0.038716740288 + 0.025468078675*_Complex_I, -0.021154025874 + 0.034169668261*_Complex_I, 0.077447054430 + -0.009547926751*_Complex_I, -0.016338142895 + 0.132246349074*_Complex_I, -0.116081376657 + 0.043341402708*_Complex_I, 0.006899278182 + 0.004113954837*_Complex_I, -0.096053480940 + 0.077818095714*_Complex_I, 0.036459684176 + -0.026251748476*_Complex_I, 0.009672547486 + 0.040691758623*_Complex_I, -0.055593734133 + 0.042208131016*_Complex_I, 0.040988977939 + 0.032815266125*_Complex_I, 0.003252391576 + -0.027032799374*_Complex_I, -0.056555124191 + 0.108792895823*_Complex_I, 0.027780168593 + -0.058523157109*_Complex_I, -0.023467358131 + -0.032855820386*_Complex_I, -0.160897508497 + -0.123678772528*_Complex_I, 0.089287852799 + -0.007143354758*_Complex_I, -0.016099534679 + 0.002581265491*_Complex_I, -0.000986708318 + 0.015164729493*_Complex_I, -0.064404987562 + -0.057663923465*_Complex_I, 0.132601153086 + -0.001252362087*_Complex_I, -0.048228851544 + 0.135111186832*_Complex_I, 0.134924898703 + -0.062012201527*_Complex_I, -0.074853441754 + 0.026496948899*_Complex_I, -0.129226783274 + -0.004790572963*_Complex_I, 0.103893760072 + 0.022506218947*_Complex_I, -0.035460676841 + 0.047688216908*_Complex_I, 0.178180257360 + -0.013109362819*_Complex_I, 0.018161301104 + 0.109487688153*_Complex_I, 0.094671736324 + 0.013921482693*_Complex_I, -0.048072372913 + 0.137711693833*_Complex_I, 0.062880576088 + 0.175933352879*_Complex_I, -0.009910181192 + 0.111994156930*_Complex_I, 0.044512102038 + 0.006301021902*_Complex_I, 0.066098606944 + -0.028081191959*_Complex_I, 0.087466319032 + 0.008238268753*_Complex_I, -0.001367800660 + 0.038967292120*_Complex_I, -0.067421987215 + 0.145539459508*_Complex_I, 0.075984112068 + 0.175244098743*_Complex_I, -0.027482814927 + 0.090963593261*_Complex_I, -0.061982865075 + -0.001782549283*_Complex_I, -0.051388866943 + 0.091286306431*_Complex_I, -0.125038294673 + 0.006669602361*_Complex_I, -0.266499054163 + 0.031401157713*_Complex_I, -0.005097555860 + 0.090581995126*_Complex_I, -0.055547492377 + 0.112501253551*_Complex_I, 0.012659187846 + 0.026503690407*_Complex_I, -0.054554809518 + -0.047656993760*_Complex_I, -0.092937843107 + 0.022881558123*_Complex_I, -0.072930225245 + 0.008805379158*_Complex_I, 0.001689423379 + 0.180348978422*_Complex_I, -0.127921044291 + -0.059030091461*_Complex_I, 0.022023172094 + 0.056579583536*_Complex_I, -0.121613219261 + -0.108837221417*_Complex_I, -0.067796732417 + -0.119754222994*_Complex_I, 0.022160633596 + 0.172479032134*_Complex_I, -0.021149818992 + -0.088048810494*_Complex_I, 0.061930559225 + 0.033755437249*_Complex_I, 0.009953383045 + 0.044238688316*_Complex_I, 0.122661863617 + -0.104781716997*_Complex_I, 0.038138937124 + -0.063310924046*_Complex_I, -0.085849386817 + 0.029133930890*_Complex_I, 0.062239172444 + -0.126085383157*_Complex_I, 0.056320988469 + -0.024245019681*_Complex_I, 0.008584244317 + -0.122838573365*_Complex_I, 0.076110822106 + -0.085361591999*_Complex_I, 0.020719355889 + -0.055555782582*_Complex_I, 0.000653411740 + -0.069873018399*_Complex_I, 0.066178767484 + -0.026066404349*_Complex_I, 0.028671545965 + 0.078431187056*_Complex_I, 0.065121750679 + -0.050089915985*_Complex_I, 0.057324656071 + -0.014133997391*_Complex_I, 0.030288156492 + 0.026307763098*_Complex_I, 0.111873889736 + -0.050023831315*_Complex_I, 0.004746208895 + 0.091571031089*_Complex_I, 0.010352530872 + -0.069569373081*_Complex_I, 0.103204479415 + 0.119216440805*_Complex_I, 0.100504774459 + -0.026045891638*_Complex_I, 0.137774605021 + 0.123356174384*_Complex_I, -0.002645216707 + -0.014199931832*_Complex_I, 0.171062973870 + 0.005021494304*_Complex_I, 0.017869576969 + 0.051069516929*_Complex_I, 0.012047989391 + -0.064461915154*_Complex_I, 0.127717671510 + 0.063350643190*_Complex_I, 0.004050235012 + 0.103983488965*_Complex_I, 0.032899906611 + -0.046472299982*_Complex_I, 0.065807936567 + -0.000393539350*_Complex_I, 0.028480795150 + -0.035085883796*_Complex_I, 0.020035985982 + 0.094697203202*_Complex_I, -0.032243593542 + -0.034371463214*_Complex_I, 0.130710337771 + -0.076446903504*_Complex_I, -0.000290058651 + 0.063994722962*_Complex_I, 0.029367046198 + -0.059754919406*_Complex_I, -0.013496796316 + 0.021741636806*_Complex_I, -0.030554614083 + -0.122446936946*_Complex_I, 0.076444606322 + -0.050687378688*_Complex_I, -0.098301236592 + -0.042289531263*_Complex_I, 0.110549679961 + -0.093097947505*_Complex_I, -0.006461769800 + 0.063465854253*_Complex_I, 0.009417608596 + -0.044048779916*_Complex_I, -0.064257503698 + -0.070341963349*_Complex_I, -0.059122879906 + -0.064698906559*_Complex_I, -0.042900235147 + -0.196073457626*_Complex_I, 0.040029224882 + -0.029654181156*_Complex_I, 0.032819760175 + -0.111413861187*_Complex_I, 0.113350177210 + -0.032359925542*_Complex_I, 0.126474793881 + -0.075277469455*_Complex_I, -0.036790802258 + -0.012416828849*_Complex_I, -0.013341048450 + -0.171411636672*_Complex_I, 0.071226482453 + -0.028621067255*_Complex_I, 0.025788824745 + -0.122676045849*_Complex_I, 0.138882083097 + -0.112136069734*_Complex_I, 0.079803890033 + -0.056689245330*_Complex_I, -0.083660222940 + 0.021037488864*_Complex_I, 0.038027034035 + -0.045614580284*_Complex_I, -0.173039872932 + -0.036333257565*_Complex_I, 0.109185737875 + -0.018739181874*_Complex_I, -0.011116564421 + -0.012659167774*_Complex_I, 0.027848471825 + 0.042226423184*_Complex_I, 0.009983998202 + 0.009652509701*_Complex_I, 0.034939989540 + 0.049003327190*_Complex_I, -0.003271145352 + 0.117508812071*_Complex_I, -0.089674168530 + 0.022069310635*_Complex_I, 0.075219548196 + 0.009686118261*_Complex_I, -0.009264365949 + 0.096686949696*_Complex_I, -0.015282640313 + -0.022970528637*_Complex_I, 0.056453107756 + 0.038101951682*_Complex_I, -0.075215301245 + -0.009549458275*_Complex_I, 0.016786191325 + 0.119063467526*_Complex_I, -0.063461158126 + -0.044766698681*_Complex_I, 0.013715934436 + 0.023246048562*_Complex_I, -0.007187144049 + 0.139644946690*_Complex_I, 0.001093160636 + 0.038143526761*_Complex_I, 0.089982542957 + 0.104701345525*_Complex_I, 0.006438088218 + 0.016301123978*_Complex_I, 0.024550427000 + 0.007223414838*_Complex_I, 0.001998203885 + 0.128506017977*_Complex_I, 0.027388452832 + -0.021862288446*_Complex_I, 0.121924019581 + -0.034718387256*_Complex_I, 0.065573770757 + 0.084008890431*_Complex_I, -0.010812132830 + 0.041404645847*_Complex_I, -0.001516024489 + -0.046108309651*_Complex_I, 0.021914893505 + 0.163215448624*_Complex_I, -0.168800712098 + 0.059209648111*_Complex_I, 0.043105911919 + -0.060137086361*_Complex_I, -0.189708356977 + 0.061129252073*_Complex_I, -0.012670229735 + -0.164593804221*_Complex_I, -0.027215975709 + 0.001464776717*_Complex_I, -0.032021988907 + -0.005641085087*_Complex_I, 0.084676334643 + 0.050890486174*_Complex_I, -0.025518610180 + -0.026683394670*_Complex_I, -0.196695068885 + -0.118334531757*_Complex_I, 0.005134576502 + 0.041058905955*_Complex_I, -0.234700560083 + -0.074871902832*_Complex_I, -0.003394269991 + -0.025828554844*_Complex_I, -0.095398073839 + -0.137794198564*_Complex_I, -0.115844189635 + -0.016811394953*_Complex_I, -0.086433951444 + -0.096085417783*_Complex_I, -0.135882412437 + 0.086996893482*_Complex_I, 0.086188594393 + -0.052027988864*_Complex_I, -0.032660999389 + 0.079110677785*_Complex_I, 0.048555777064 + -0.071192412508*_Complex_I, 0.002384862118 + -0.024747258783*_Complex_I, 0.103707359507 + -0.071240112258*_Complex_I, 0.066653972959 + 0.034897982205*_Complex_I, 0.104312888231 + -0.035974080403*_Complex_I, 0.138638211048 + -0.049974123076*_Complex_I, 0.194165435108 + -0.049828755020*_Complex_I, 0.053154926316 + -0.036358363591*_Complex_I, 0.220675128214 + -0.030961835182*_Complex_I, -0.023703599067 + 0.107776938666*_Complex_I, 0.144905982977 + 0.004212434062*_Complex_I, 0.095439650368 + 0.010795170803*_Complex_I, 0.121879552506 + -0.015505102444*_Complex_I, 0.116627097083 + 0.007939429200*_Complex_I, 0.121158143520 + 0.140391060505*_Complex_I, 0.023773742208 + -0.003915558406*_Complex_I, 0.249689399352 + 0.106009483142*_Complex_I, 0.042459283114 + 0.116551334180*_Complex_I, -0.032000595442 + 0.043069200952*_Complex_I, 0.083807567711 + -0.048271370782*_Complex_I, 0.106133277971 + 0.107195381079*_Complex_I, -0.032758866155 + 0.055589876920*_Complex_I, 0.083113455874 + 0.056268033253*_Complex_I, 0.062805062701 + 0.052981580201*_Complex_I, -0.072300786192 + -0.022099642616*_Complex_I, -0.023071207539 + 0.069870175640*_Complex_I, -0.028038066616 + 0.115260700432*_Complex_I, 0.064595548137 + 0.179516005676*_Complex_I, -0.096265563941 + 0.042171225905*_Complex_I, -0.009166713003 + 0.047707628475*_Complex_I, -0.074476545197 + 0.078481428604*_Complex_I, 0.020402514454 + 0.097206670167*_Complex_I, 0.009603470518 + 0.137727809796*_Complex_I, -0.061724978115 + 0.088460708343*_Complex_I, -0.018787857770 + 0.022957577259*_Complex_I, 0.060840793373 + 0.153201719382*_Complex_I, -0.090761100879 + 0.063269553381*_Complex_I, 0.048643003688 + 0.073091682104*_Complex_I, 0.042574315610 + -0.003350831677*_Complex_I, -0.040962206275 + -0.040240568604*_Complex_I, 0.091461005901 + 0.091406021898*_Complex_I, -0.072777125035 + 0.062929145258*_Complex_I, 0.050350001022 + 0.069452557434*_Complex_I, -0.053002534268 + 0.128785684713*_Complex_I, -0.138610817453 + -0.082977870570*_Complex_I, 0.003075555607 + 0.064767936471*_Complex_I, -0.086047615737 + 0.023981557378*_Complex_I, -0.050138686326 + -0.027308987428*_Complex_I, 0.076446905787 + 0.037104333404*_Complex_I, -0.133192170848 + 0.118044932479*_Complex_I, 0.031944935119 + -0.022005963244*_Complex_I, -0.145840989397 + -0.032141552759*_Complex_I, -0.094264666257 + 0.034400727372*_Complex_I, -0.108437970582 + 0.098296799443*_Complex_I, -0.077001723208 + -0.045921410112*_Complex_I, 0.064828536127 + 0.008649034614*_Complex_I, -0.049541743659 + 0.128627939884*_Complex_I, -0.054927512176 + -0.017342218621*_Complex_I, -0.045962424214 + 0.135024314150*_Complex_I, -0.103035351086 + -0.015043817667*_Complex_I, -0.037360852174 + 0.060401543729*_Complex_I, -0.015995655894 + -0.111740685081*_Complex_I, 0.032349781494 + 0.177898564863*_Complex_I, -0.021316438598 + -0.060576452528*_Complex_I, 0.017301344278 + 0.053102820051*_Complex_I, -0.014246232246 + 0.154624061894*_Complex_I, 0.059824941825 + 0.104996100396*_Complex_I, 0.011889122729 + 0.118361813218*_Complex_I, 0.043309441161 + -0.055415600686*_Complex_I, 0.074309063231 + 0.029407405713*_Complex_I, 0.062659426432 + 0.086580925759*_Complex_I, 0.141493640931 + 0.127665018203*_Complex_I, 0.091935455312 + 0.098230420374*_Complex_I, 0.153585132414 + 0.041819978162*_Complex_I, -0.036769194301 + -0.001909617998*_Complex_I, 0.081816172969 + 0.145221737468*_Complex_I, -0.074164721966 + 0.103001561704*_Complex_I, -0.001976310011 + -0.051318733615*_Complex_I, -0.009827887129 + -0.043930466173*_Complex_I, 0.054370258297 + -0.141481458488*_Complex_I, -0.015471769405 + 0.047001209676*_Complex_I, -0.056006669211 + -0.098678088820*_Complex_I, 0.009040689393 + -0.031336560460*_Complex_I, -0.039683698505 + -0.042155900675*_Complex_I, 0.017353066695 + -0.086277701489*_Complex_I, -0.002902182702 + -0.059776504802*_Complex_I, -0.044568379057 + -0.090648234378*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_cccf_data_h4x256.c000066400000000000000000000650251474751757600245510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_cccf_data_h4x256.c: autotest fftfilt data // #include float complex fftfilt_cccf_data_h4x256_h[] = { -0.135231339931 + 0.062977480888*_Complex_I, -0.157240438461 + 0.037726294994*_Complex_I, 0.169742667675 + -0.043306457996*_Complex_I, -0.001679791883 + -0.031882059574*_Complex_I}; float complex fftfilt_cccf_data_h4x256_x[] = { -0.145331311226 + 0.109500586987*_Complex_I, 0.008576134592 + -0.169542956352*_Complex_I, 0.047844916582 + 0.149058306217*_Complex_I, 0.177120888233 + 0.170329642296*_Complex_I, -0.004175573960 + 0.072688925266*_Complex_I, -0.027152365446 + 0.035960051417*_Complex_I, 0.094344460964 + -0.033645594120*_Complex_I, -0.010391099006 + -0.035192406178*_Complex_I, -0.180138766766 + -0.031795871258*_Complex_I, -0.203700375557 + -0.138529646397*_Complex_I, -0.019561575353 + -0.144657015800*_Complex_I, -0.118808639050 + -0.027752715349*_Complex_I, 0.056749093533 + -0.025054290891*_Complex_I, 0.116542947292 + -0.007720955461*_Complex_I, -0.074969446659 + 0.100591087341*_Complex_I, 0.001408090629 + -0.042336615920*_Complex_I, 0.240100383759 + -0.161245095730*_Complex_I, -0.085952699184 + 0.084794622660*_Complex_I, -0.015006904304 + 0.035609281063*_Complex_I, 0.000034478516 + -0.187320244312*_Complex_I, 0.052339464426 + -0.004798505455*_Complex_I, 0.093824869394 + -0.070545089245*_Complex_I, 0.149086785316 + 0.108725130558*_Complex_I, -0.156761336327 + 0.005509132892*_Complex_I, -0.125493848324 + -0.043598395586*_Complex_I, -0.121326863766 + 0.007096276432*_Complex_I, 0.003544984013 + 0.166835379601*_Complex_I, -0.037431293726 + -0.020329789817*_Complex_I, -0.085911118984 + -0.079901820421*_Complex_I, 0.122742509842 + 0.014822798967*_Complex_I, 0.110778486729 + -0.071227872372*_Complex_I, -0.007605559379 + -0.128052246571*_Complex_I, -0.066244971752 + -0.047825807333*_Complex_I, -0.030502566695 + -0.254250669479*_Complex_I, 0.157666409016 + -0.093531721830*_Complex_I, 0.043991112709 + 0.067102664709*_Complex_I, -0.063667005301 + 0.055537760258*_Complex_I, 0.035860368609 + -0.217314362526*_Complex_I, -0.154697167873 + -0.051928877831*_Complex_I, -0.154008638859 + 0.137628376484*_Complex_I, -0.021988071501 + -0.136372375488*_Complex_I, 0.118345403671 + -0.299838876724*_Complex_I, 0.066200459003 + 0.107628118992*_Complex_I, -0.022814218700 + 0.042800396681*_Complex_I, 0.039931696653 + 0.066364485025*_Complex_I, -0.038531854749 + -0.120103299618*_Complex_I, 0.017913374305 + 0.016456928849*_Complex_I, 0.001270754635 + 0.030759117007*_Complex_I, 0.235941290855 + 0.024339741468*_Complex_I, 0.074259299040 + 0.054985857010*_Complex_I, -0.117393791676 + -0.024225908518*_Complex_I, 0.195164024830 + -0.100901556015*_Complex_I, -0.074234390259 + -0.041768211126*_Complex_I, 0.042385265231 + -0.228795623779*_Complex_I, -0.089356112480 + 0.027445358038*_Complex_I, -0.273647761345 + -0.094072991610*_Complex_I, 0.067754048109 + -0.066324621439*_Complex_I, -0.071163922548 + 0.011088901013*_Complex_I, 0.002260415070 + -0.033153522015*_Complex_I, -0.163043868542 + 0.147372353077*_Complex_I, 0.130338788033 + 0.113823711872*_Complex_I, -0.018929108977 + -0.134858226776*_Complex_I, 0.005879180133 + 0.110552978516*_Complex_I, -0.177987158298 + -0.145397603512*_Complex_I, 0.112013733387 + -0.243533611298*_Complex_I, -0.065134996176 + -0.161895787716*_Complex_I, -0.100013601780 + -0.185575771332*_Complex_I, -0.039732664824 + -0.033335423470*_Complex_I, -0.004159386829 + -0.118040883541*_Complex_I, 0.101805281639 + 0.084620487690*_Complex_I, -0.150429344177 + -0.084105199575*_Complex_I, 0.062221693993 + 0.047454631329*_Complex_I, 0.138085842133 + -0.076058888435*_Complex_I, 0.254889655113 + -0.163386595249*_Complex_I, -0.025463542342 + -0.060935062170*_Complex_I, 0.061728596687 + -0.006239769980*_Complex_I, -0.083425503969 + 0.069602411985*_Complex_I, 0.039149901271 + -0.118299651146*_Complex_I, 0.103384292126 + -0.022438082099*_Complex_I, -0.008195941895 + 0.049835348129*_Complex_I, -0.049642279744 + -0.038572207093*_Complex_I, 0.112285923958 + 0.046880367398*_Complex_I, -0.052668154240 + 0.054064834118*_Complex_I, -0.009626910090 + -0.040556022525*_Complex_I, 0.002097596042 + -0.216656374931*_Complex_I, 0.057758331299 + -0.002327759005*_Complex_I, -0.008833542466 + -0.014824745059*_Complex_I, 0.040581482649 + 0.045436677337*_Complex_I, 0.194773435593 + 0.044354414940*_Complex_I, -0.028676524758 + -0.018726617098*_Complex_I, -0.019215075672 + -0.038972333074*_Complex_I, 0.200048685074 + 0.008784489334*_Complex_I, -0.116677081585 + -0.295071172714*_Complex_I, -0.077746075392 + -0.031134122610*_Complex_I, 0.078498488665 + 0.007961921394*_Complex_I, -0.081279265881 + 0.114860057831*_Complex_I, -0.014656324685 + -0.145551848412*_Complex_I, 0.129554140568 + 0.086291736364*_Complex_I, 0.123636543751 + -0.061629927158*_Complex_I, 0.040432214737 + 0.095078992844*_Complex_I, 0.021615064144 + 0.087291020155*_Complex_I, -0.036054989696 + 0.058331966400*_Complex_I, 0.031770968437 + 0.150715994835*_Complex_I, 0.036789077520 + 0.006291696429*_Complex_I, 0.207829833031 + -0.195549118519*_Complex_I, -0.069425356388 + 0.034547394514*_Complex_I, 0.121964550018 + -0.175282227993*_Complex_I, -0.076088452339 + 0.189335298538*_Complex_I, -0.238275814056 + 0.164852106571*_Complex_I, -0.105275332928 + 0.048049694300*_Complex_I, 0.025219294429 + 0.148977017403*_Complex_I, -0.116340065002 + 0.047728052735*_Complex_I, -0.001223530248 + 0.002220938914*_Complex_I, -0.095514726639 + 0.177518546581*_Complex_I, -0.024929241836 + 0.051844847202*_Complex_I, 0.003478102759 + -0.047746166587*_Complex_I, -0.179150342941 + -0.217488384247*_Complex_I, -0.004914051294 + -0.154762375355*_Complex_I, 0.097842323780 + -0.024203261733*_Complex_I, -0.103857576847 + -0.032823368907*_Complex_I, -0.092790353298 + 0.061397796869*_Complex_I, 0.047670701146 + 0.110239303112*_Complex_I, 0.073129659891 + 0.008005330712*_Complex_I, 0.215736103058 + -0.160301959515*_Complex_I, 0.012318083644 + 0.165701925755*_Complex_I, -0.092335480452 + 0.060041588545*_Complex_I, 0.057762295008 + 0.212985706329*_Complex_I, -0.116756439209 + 0.080165004730*_Complex_I, -0.016070105135 + 0.102566015720*_Complex_I, -0.031425985694 + 0.048826861382*_Complex_I, -0.138180553913 + -0.015630686283*_Complex_I, -0.040541607141 + 0.086674833298*_Complex_I, -0.017452953756 + -0.181320679188*_Complex_I, 0.011673089117 + 0.072657525539*_Complex_I, -0.015449254215 + 0.112104630470*_Complex_I, 0.071193879843 + -0.032887244225*_Complex_I, 0.016030588746 + -0.007359164953*_Complex_I, 0.007357457280 + 0.054825830460*_Complex_I, -0.068202400208 + -0.091296017170*_Complex_I, 0.030967503786 + -0.193203377724*_Complex_I, 0.036832565069 + -0.081849122047*_Complex_I, -0.046027070284 + -0.027470356226*_Complex_I, -0.125437974930 + 0.032441046834*_Complex_I, 0.011070625484 + -0.092022657394*_Complex_I, 0.137458860874 + 0.151134181023*_Complex_I, -0.117661428452 + -0.008656930178*_Complex_I, 0.163053572178 + -0.070776551962*_Complex_I, -0.119681096077 + -0.012249100208*_Complex_I, 0.127253675461 + 0.107909095287*_Complex_I, -0.051333457232 + -0.116273534298*_Complex_I, -0.071138489246 + 0.072735458612*_Complex_I, 0.037040272355 + -0.050955241919*_Complex_I, -0.200804090500 + -0.217231678963*_Complex_I, -0.109212982655 + 0.012372082472*_Complex_I, -0.029450660944 + 0.118574059010*_Complex_I, 0.099285334349 + -0.000237483322*_Complex_I, 0.276025676727 + -0.017251548171*_Complex_I, 0.088983309269 + 0.013136875629*_Complex_I, 0.163659727573 + -0.066418147087*_Complex_I, 0.104050731659 + 0.028489127755*_Complex_I, 0.016449892521 + -0.020746667683*_Complex_I, -0.126559376717 + -0.070659190416*_Complex_I, -0.237141442299 + 0.089611142874*_Complex_I, 0.068004012108 + 0.173722803593*_Complex_I, -0.047145104408 + -0.175941777229*_Complex_I, -0.123525714874 + -0.166570901871*_Complex_I, 0.001423638687 + 0.157464015484*_Complex_I, 0.079405152798 + -0.025422385335*_Complex_I, 0.081756842136 + 0.121069538593*_Complex_I, -0.128136157990 + 0.139459896088*_Complex_I, 0.007735489309 + -0.027935725451*_Complex_I, -0.092589050531 + -0.109762561321*_Complex_I, -0.016260780394 + -0.015316626430*_Complex_I, -0.158776199818 + 0.127178168297*_Complex_I, -0.026575049758 + 0.238629913330*_Complex_I, 0.152634930611 + -0.165786969662*_Complex_I, 0.108250701427 + -0.051711326838*_Complex_I, 0.076149952412 + -0.090032291412*_Complex_I, 0.074367189407 + -0.029565215111*_Complex_I, 0.061409753561 + -0.112582445145*_Complex_I, -0.097367572784 + -0.113927245140*_Complex_I, 0.026321750879 + 0.138302946091*_Complex_I, -0.001476241183 + -0.069936299324*_Complex_I, -0.114703190327 + 0.070511698723*_Complex_I, -0.006401912868 + -0.010170778632*_Complex_I, 0.082021260262 + -0.036617666483*_Complex_I, 0.381905221939 + 0.054933649302*_Complex_I, -0.047172623873 + -0.016221418977*_Complex_I, 0.075080448389 + 0.044649630785*_Complex_I, 0.006743746251 + -0.057219368219*_Complex_I, 0.072658914328 + -0.113842511177*_Complex_I, 0.063461345434 + 0.108319532871*_Complex_I, -0.085157209635 + 0.127499580383*_Complex_I, -0.110658645630 + 0.026664611697*_Complex_I, 0.087542557716 + -0.198326361179*_Complex_I, -0.187630629539 + -0.076032394171*_Complex_I, 0.158300364017 + -0.183700358868*_Complex_I, -0.117931878567 + -0.157972729206*_Complex_I, 0.048598474264 + -0.121435344219*_Complex_I, 0.090523117781 + -0.092027544975*_Complex_I, -0.126598548889 + -0.115896356106*_Complex_I, -0.050347799063 + 0.063965880871*_Complex_I, 0.009061803669 + -0.003273813799*_Complex_I, -0.138404893875 + -0.058004939556*_Complex_I, -0.027039816976 + 0.123541855812*_Complex_I, -0.260724592209 + 0.070059484243*_Complex_I, -0.071726894379 + 0.118393385410*_Complex_I, -0.103354132175 + -0.048656904697*_Complex_I, -0.079942697287 + -0.007439111173*_Complex_I, 0.010002358258 + 0.217011165619*_Complex_I, -0.107096755505 + -0.032441377640*_Complex_I, -0.038857096434 + -0.075556772947*_Complex_I, 0.103407859802 + -0.010233432055*_Complex_I, -0.017742788792 + -0.016240037978*_Complex_I, -0.061273831129 + 0.003164015338*_Complex_I, -0.120957195759 + 0.053525984287*_Complex_I, -0.102713096142 + -0.067174482346*_Complex_I, 0.033584815264 + 0.006909974664*_Complex_I, -0.067435938120 + -0.001113843173*_Complex_I, 0.151518130302 + -0.022716298699*_Complex_I, -0.092082822323 + -0.080135297775*_Complex_I, 0.027139824629 + 0.071895372868*_Complex_I, -0.115053045750 + 0.071924138069*_Complex_I, 0.011123746634 + -0.015718665719*_Complex_I, 0.101550316811 + 0.003213942051*_Complex_I, 0.087435191870 + -0.074827837944*_Complex_I, 0.098427033424 + 0.153796470165*_Complex_I, -0.030665528774 + 0.086529731750*_Complex_I, -0.015693670511 + -0.002731614932*_Complex_I, 0.133912920952 + 0.264183211327*_Complex_I, -0.000968740415 + 0.156215214729*_Complex_I, -0.018345800042 + -0.029062193632*_Complex_I, -0.049218568206 + -0.058449655771*_Complex_I, 0.045136275887 + 0.035753569007*_Complex_I, 0.011435703933 + 0.002002427541*_Complex_I, 0.021104848385 + -0.311103820801*_Complex_I, 0.005841723830 + -0.030350989103*_Complex_I, -0.064211606979 + 0.203191661835*_Complex_I, -0.071606880426 + 0.014993095398*_Complex_I, 0.072429609299 + 0.168000137806*_Complex_I, -0.038637900352 + -0.050586193800*_Complex_I, 0.168560516834 + 0.112749493122*_Complex_I, 0.140708494186 + -0.139942800999*_Complex_I, 0.044472098351 + 0.057332044840*_Complex_I, -0.113584566116 + 0.036734291911*_Complex_I, -0.115594518185 + 0.096241426468*_Complex_I, -0.132571578026 + 0.076662874222*_Complex_I, -0.088810175657 + 0.180961203575*_Complex_I, -0.134494102001 + 0.108674275875*_Complex_I, -0.066532063484 + 0.080732357502*_Complex_I, -0.001597549021 + 0.199119567871*_Complex_I, -0.171998977661 + 0.006639727950*_Complex_I, 0.157607150078 + -0.054489070177*_Complex_I, -0.109499049187 + -0.023027896881*_Complex_I, -0.172086226940 + 0.121059966087*_Complex_I, 0.119662201405 + -0.004805976152*_Complex_I}; float complex fftfilt_cccf_data_h4x256_y[] = { 0.012757276827 + -0.023960510977*_Complex_I, 0.028238533774 + 0.000766892287*_Complex_I, -0.030736578281 + 0.034719058493*_Complex_I, -0.049977138490 + -0.058212812777*_Complex_I, -0.029132843102 + -0.006952447936*_Complex_I, 0.041434724419 + 0.001305867219*_Complex_I, -0.000154542372 + 0.010398927205*_Complex_I, -0.010671035217 + 0.020245277403*_Complex_I, 0.045073710539 + -0.010894785162*_Complex_I, 0.061276520757 + -0.004366387666*_Complex_I, 0.015952866275 + 0.035222286704*_Complex_I, -0.014939304199 + 0.009382470283*_Complex_I, -0.000027323374 + -0.010136557087*_Complex_I, -0.049199930734 + 0.015765195506*_Complex_I, -0.006368245652 + -0.015589575903*_Complex_I, 0.029022969544 + -0.020956220654*_Complex_I, -0.029749689836 + 0.060255058887*_Complex_I, -0.023648414328 + 0.012506271275*_Complex_I, 0.042523255991 + -0.060078254361*_Complex_I, -0.003653249612 + 0.029899901014*_Complex_I, 0.002128348980 + 0.042692956028*_Complex_I, -0.023239979421 + -0.013201242246*_Complex_I, -0.036395878395 + 0.006550682393*_Complex_I, 0.005937946446 + -0.039787300481*_Complex_I, 0.071765960434 + 0.000338344221*_Complex_I, 0.014183242345 + -0.003691402540*_Complex_I, -0.014927275586 + -0.025008346274*_Complex_I, -0.021975526648 + -0.015174616793*_Complex_I, 0.031559403980 + 0.039201077146*_Complex_I, -0.002930033110 + 0.012825110045*_Complex_I, -0.048982592713 + 0.010293962046*_Complex_I, 0.013434665977 + 0.032290621601*_Complex_I, 0.033982791965 + 0.001317652206*_Complex_I, 0.023064195315 + 0.012663899061*_Complex_I, -0.018428432947 + 0.056613928236*_Complex_I, -0.049039654309 + -0.025292660627*_Complex_I, 0.010320821686 + -0.041716388907*_Complex_I, 0.023878576192 + 0.025126876135*_Complex_I, 0.020413632469 + 0.043472532575*_Complex_I, 0.036996565632 + -0.062485539135*_Complex_I, -0.004910190919 + -0.013287275246*_Complex_I, -0.010096052144 + 0.103664702556*_Complex_I, -0.028018937736 + 0.023708913702*_Complex_I, -0.011287655176 + -0.076741200437*_Complex_I, -0.001467109023 + -0.001917661318*_Complex_I, 0.005293144320 + 0.010848041931*_Complex_I, 0.018185964149 + 0.026525130926*_Complex_I, -0.015239532128 + -0.026094016726*_Complex_I, -0.034810813866 + 0.010226757752*_Complex_I, -0.049480455827 + 0.006882194797*_Complex_I, 0.045731930549 + -0.016140007390*_Complex_I, 0.014701121326 + 0.023870809774*_Complex_I, -0.033559313643 + 0.022713731523*_Complex_I, 0.050108362232 + 0.015581007741*_Complex_I, -0.005632120264 + 0.018308311284*_Complex_I, 0.052024517749 + -0.050433653230*_Complex_I, 0.020247348485 + 0.025265853477*_Complex_I, -0.048724807310 + 0.005688999390*_Complex_I, 0.018642648578 + -0.005112453077*_Complex_I, -0.000164879106 + -0.021983711442*_Complex_I, -0.005295938220 + -0.039983291504*_Complex_I, -0.036089961107 + 0.036124313440*_Complex_I, 0.032332494429 + 0.024537918792*_Complex_I, 0.022487700299 + -0.035126580906*_Complex_I, 0.035179302371 + 0.075476289976*_Complex_I, -0.022415275427 + 0.042965211229*_Complex_I, 0.045691989716 + 0.001526190095*_Complex_I, 0.004179917382 + -0.000409395803*_Complex_I, -0.014563762228 + -0.005376713067*_Complex_I, -0.027925684190 + 0.012934585830*_Complex_I, -0.000374846557 + -0.026098719210*_Complex_I, 0.032612571524 + 0.015336583912*_Complex_I, -0.052107302856 + 0.002717865097*_Complex_I, -0.032834640384 + 0.065614047849*_Complex_I, -0.005080334534 + 0.020989805546*_Complex_I, 0.031881162655 + -0.029694607868*_Complex_I, -0.015170864143 + -0.028448915975*_Complex_I, 0.020955734615 + 0.001553519861*_Complex_I, -0.025709904149 + 0.043093492818*_Complex_I, -0.013558366662 + -0.019060063112*_Complex_I, 0.021290614364 + -0.015390877095*_Complex_I, -0.008998068093 + 0.010479790493*_Complex_I, -0.024201210119 + -0.017983452805*_Complex_I, 0.030041436100 + -0.000867601449*_Complex_I, 0.011111929170 + 0.043244016918*_Complex_I, -0.001398590030 + 0.033219709577*_Complex_I, -0.017169337706 + -0.032498137528*_Complex_I, -0.003608831698 + -0.004190317460*_Complex_I, -0.039540681605 + -0.003316647474*_Complex_I, -0.018843962328 + 0.007361859229*_Complex_I, 0.046631096565 + 0.003646629910*_Complex_I, -0.027706090091 + 0.008592625414*_Complex_I, -0.002924156406 + 0.033883252714*_Complex_I, 0.075079733805 + 0.034815167989*_Complex_I, -0.030357014457 + -0.045596609600*_Complex_I, -0.032642221938 + -0.016644239862*_Complex_I, 0.032402948921 + -0.001883868205*_Complex_I, -0.023858913130 + 0.039323855789*_Complex_I, -0.041457486487 + -0.014233573157*_Complex_I, -0.007459151809 + 0.013792354132*_Complex_I, 0.002485997247 + -0.043959018212*_Complex_I, 0.003318269056 + -0.012519460724*_Complex_I, 0.000093169055 + -0.016480871965*_Complex_I, -0.016900119114 + -0.010406925321*_Complex_I, -0.007971836056 + 0.065190143824*_Complex_I, -0.006820219290 + 0.027753423502*_Complex_I, 0.031106376763 + -0.020043621536*_Complex_I, -0.031071266484 + 0.004339971697*_Complex_I, 0.040991447377 + -0.102820217268*_Complex_I, 0.031948560681 + -0.016199124342*_Complex_I, -0.025194033136 + 0.010324013232*_Complex_I, -0.006991588793 + -0.016219922197*_Complex_I, 0.028959571857 + 0.015200024042*_Complex_I, -0.011128094874 + -0.018331258759*_Complex_I, 0.010033408771 + -0.036038577315*_Complex_I, -0.003951805923 + 0.031887379901*_Complex_I, 0.043011761476 + 0.038394544247*_Complex_I, 0.047003249222 + 0.040511060053*_Complex_I, -0.046451986806 + 0.004395040215*_Complex_I, -0.012529114947 + -0.014584931709*_Complex_I, 0.036884371074 + -0.020832501744*_Complex_I, -0.021101612528 + -0.029213061508*_Complex_I, -0.036011838357 + 0.005793889985*_Complex_I, -0.015900637518 + 0.056267590724*_Complex_I, -0.023781635996 + 0.008199383119*_Complex_I, 0.030327057536 + -0.078422708418*_Complex_I, -0.005177131563 + -0.017104662921*_Complex_I, -0.014188045903 + -0.035985384502*_Complex_I, 0.032146074117 + 0.004602106645*_Complex_I, -0.009821272669 + -0.008851465116*_Complex_I, 0.027236042210 + 0.006241896038*_Complex_I, 0.022418389996 + -0.007040618186*_Complex_I, -0.005638389798 + 0.012513644070*_Complex_I, 0.000036227705 + 0.039661942810*_Complex_I, -0.017530818413 + -0.055992409201*_Complex_I, -0.009980130825 + 0.003409352124*_Complex_I, -0.007128899287 + 0.029065621717*_Complex_I, 0.007569712793 + -0.013550165086*_Complex_I, 0.012981701430 + -0.004450356742*_Complex_I, 0.025509754347 + 0.048348739912*_Complex_I, -0.011201724949 + 0.032065969619*_Complex_I, -0.000655974814 + -0.016732426150*_Complex_I, 0.019689483222 + -0.025854936465*_Complex_I, 0.011124510152 + -0.000398237810*_Complex_I, -0.047061637319 + 0.015558558157*_Complex_I, -0.011720140733 + -0.036972797597*_Complex_I, 0.028160356014 + 0.036264888172*_Complex_I, -0.021771924689 + 0.010389295245*_Complex_I, 0.019810005650 + -0.024476888982*_Complex_I, -0.033191779573 + -0.001651714148*_Complex_I, 0.043581774082 + 0.018672171512*_Complex_I, -0.003880433403 + -0.026649182116*_Complex_I, 0.024387701876 + 0.043399010529*_Complex_I, 0.060278802711 + 0.009923457700*_Complex_I, -0.031958233338 + -0.053227946939*_Complex_I, -0.037844853987 + 0.000125803799*_Complex_I, -0.051129681909 + 0.048362994750*_Complex_I, -0.034939691771 + 0.013353255240*_Complex_I, 0.013495424238 + 0.002533014678*_Complex_I, -0.024433814805 + 0.008923172086*_Complex_I, 0.006819321217 + -0.017933176852*_Complex_I, 0.036263988877 + 0.000691266276*_Complex_I, 0.051618724746 + -0.028316128600*_Complex_I, -0.011460974644 + -0.049249657052*_Complex_I, -0.038203479805 + 0.025707308664*_Complex_I, 0.063567349796 + 0.074586008729*_Complex_I, 0.005400590167 + -0.029955963800*_Complex_I, -0.049012787288 + -0.037393461959*_Complex_I, -0.028249615420 + 0.026654301221*_Complex_I, 0.008517579272 + -0.050945600372*_Complex_I, 0.033776936755 + -0.007976718780*_Complex_I, 0.007283043274 + 0.040108239951*_Complex_I, 0.026628003403 + 0.013587396181*_Complex_I, -0.004776533268 + -0.040224248409*_Complex_I, 0.001966163699 + -0.058690841656*_Complex_I, -0.036928601088 + 0.022515059406*_Complex_I, -0.018983384206 + 0.092142143476*_Complex_I, 0.006683303356 + -0.005118852801*_Complex_I, -0.006178795549 + 0.007657773084*_Complex_I, -0.004596093747 + 0.004602055322*_Complex_I, 0.023277809619 + 0.018778205222*_Complex_I, 0.011819463018 + -0.026895362189*_Complex_I, -0.029906188199 + -0.028279608383*_Complex_I, 0.020930036213 + 0.019813673820*_Complex_I, 0.017967997243 + -0.027321140175*_Complex_I, -0.026039058237 + 0.028575862467*_Complex_I, -0.065707150276 + 0.027564172049*_Complex_I, -0.042699371771 + -0.004553530531*_Complex_I, 0.060963634866 + -0.010306512109*_Complex_I, -0.018398404569 + -0.009004454205*_Complex_I, 0.012682078281 + 0.035081253992*_Complex_I, -0.022569581502 + -0.002483099277*_Complex_I, -0.005011260632 + -0.059832394695*_Complex_I, 0.033576764841 + -0.020322773572*_Complex_I, 0.011459245426 + 0.047090396734*_Complex_I, 0.010458010526 + 0.044772209285*_Complex_I, 0.029840259776 + 0.005715793160*_Complex_I, -0.033675797644 + 0.041554808951*_Complex_I, 0.042385066649 + 0.007945594638*_Complex_I, -0.042488207826 + 0.012628049489*_Complex_I, 0.011808820611 + 0.006893400628*_Complex_I, 0.034485946031 + -0.019260139612*_Complex_I, -0.025110072757 + -0.027865545511*_Complex_I, 0.011809921801 + 0.017253366676*_Complex_I, 0.023347768774 + -0.013960810328*_Complex_I, 0.004312140053 + -0.050475400734*_Complex_I, 0.039740495297 + -0.014728639995*_Complex_I, -0.013385038021 + 0.002586440528*_Complex_I, 0.024990035834 + 0.031120474272*_Complex_I, -0.017924227058 + -0.032258326607*_Complex_I, -0.008503405616 + -0.030526995261*_Complex_I, 0.039069831028 + 0.047795375707*_Complex_I, -0.017060972790 + 0.016758758851*_Complex_I, -0.023173891050 + -0.001084414363*_Complex_I, 0.026255359508 + -0.007252038830*_Complex_I, 0.018286656103 + -0.022933031391*_Complex_I, 0.024368811798 + -0.006580655348*_Complex_I, -0.004301769439 + 0.024140294549*_Complex_I, -0.014786161819 + -0.007103599240*_Complex_I, -0.004382808422 + 0.013351241103*_Complex_I, -0.016799676739 + 0.015974782469*_Complex_I, 0.034117502850 + -0.007152515247*_Complex_I, -0.016030168590 + -0.041660273222*_Complex_I, 0.020183324735 + 0.001275076977*_Complex_I, -0.029259335107 + 0.025057117273*_Complex_I, -0.019506766368 + 0.019348724623*_Complex_I, -0.017064727586 + -0.003715333530*_Complex_I, -0.011048527087 + -0.053833523722*_Complex_I, 0.024686830410 + 0.003799560503*_Complex_I, -0.028896024708 + -0.014835494620*_Complex_I, -0.040702141102 + -0.056626153309*_Complex_I, 0.032680942933 + 0.017723655112*_Complex_I, 0.029116465637 + 0.030527344293*_Complex_I, 0.002198173782 + 0.000971254919*_Complex_I, -0.021900155002 + -0.010625879853*_Complex_I, 0.022293892586 + 0.049298267413*_Complex_I, 0.012631626403 + 0.052532172470*_Complex_I, -0.013732381568 + -0.080618502666*_Complex_I, 0.000893373321 + -0.046464687935*_Complex_I, -0.012758518468 + 0.013919376550*_Complex_I, -0.014235454439 + -0.011924506441*_Complex_I, -0.001743292107 + 0.029502693438*_Complex_I, -0.044487788769 + 0.006911727783*_Complex_I, 0.005476613431 + 0.035516199946*_Complex_I, 0.025026369628 + -0.054869348705*_Complex_I, 0.031378831930 + -0.026801186271*_Complex_I, 0.011708942324 + -0.028570090261*_Complex_I, 0.004475361885 + -0.022218736038*_Complex_I, 0.002560834562 + -0.032693273555*_Complex_I, 0.016389708983 + 0.001391247264*_Complex_I, -0.017112703198 + -0.015433616304*_Complex_I, 0.011474238974 + -0.022409486851*_Complex_I, 0.019950525436 + 0.045615249829*_Complex_I, -0.029025601300 + 0.019024103552*_Complex_I, 0.058627375247 + -0.038320734588*_Complex_I, -0.014973530138 + -0.021441866237*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_cccf_data_h7x256.c000066400000000000000000000652531474751757600245570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_cccf_data_h7x256.c: autotest fftfilt data // #include float complex fftfilt_cccf_data_h7x256_h[] = { -0.007281364501 + 0.082790547609*_Complex_I, 0.009967260063 + -0.094733065367*_Complex_I, 0.081317949295 + -0.022636219859*_Complex_I, -0.065424275398 + -0.051597696543*_Complex_I, 0.014696654677 + -0.083596301079*_Complex_I, -0.061433798075 + 0.010713580251*_Complex_I, -0.225753474236 + 0.128715121746*_Complex_I}; float complex fftfilt_cccf_data_h7x256_x[] = { -0.224034833908 + -0.008699086308*_Complex_I, -0.049732953310 + -0.031826138496*_Complex_I, 0.076697158813 + 0.011335625499*_Complex_I, -0.036047935486 + 0.081799823046*_Complex_I, -0.034496423602 + 0.116949427128*_Complex_I, 0.041598823667 + 0.101615536213*_Complex_I, 0.210013437271 + -0.035565614700*_Complex_I, -0.012152856588 + -0.011570352316*_Complex_I, -0.028147217631 + 0.166729998589*_Complex_I, -0.167404901981 + 0.187454140186*_Complex_I, -0.026512432098 + 0.261313009262*_Complex_I, 0.102972781658 + -0.004534423724*_Complex_I, 0.059284800291 + 0.183526933193*_Complex_I, 0.030326950550 + -0.089217764139*_Complex_I, -0.018447282910 + -0.049126222730*_Complex_I, 0.113261175156 + 0.002915558405*_Complex_I, -0.135392773151 + 0.014876940846*_Complex_I, 0.004361338913 + 0.021383246779*_Complex_I, -0.202443695068 + -0.054077798128*_Complex_I, -0.004843016341 + 0.108202099800*_Complex_I, 0.001668977737 + 0.194661521912*_Complex_I, -0.010195496678 + 0.196535933018*_Complex_I, 0.034973055124 + -0.061964601278*_Complex_I, -0.102277493477 + 0.223646140099*_Complex_I, -0.023419928551 + 0.070746564865*_Complex_I, -0.159975051880 + -0.097339767218*_Complex_I, 0.106308436394 + -0.067826884985*_Complex_I, 0.009907814115 + -0.101035916805*_Complex_I, 0.091246986389 + -0.126393759251*_Complex_I, 0.155365455151 + 0.032811716199*_Complex_I, -0.050400662422 + 0.005999959260*_Complex_I, 0.098249650002 + 0.119454848766*_Complex_I, 0.043273428082 + 0.037401539087*_Complex_I, -0.023780041933 + -0.059200626612*_Complex_I, -0.123366844654 + 0.054930090904*_Complex_I, 0.036521813273 + -0.093353188038*_Complex_I, -0.127803146839 + -0.129888510704*_Complex_I, 0.010239485651 + -0.006050923839*_Complex_I, 0.073504078388 + 0.019415560365*_Complex_I, -0.071594107151 + 0.259088206291*_Complex_I, -0.164907193184 + -0.230266833305*_Complex_I, -0.047658449411 + -0.051974463463*_Complex_I, 0.126409828663 + 0.080523037910*_Complex_I, -0.015694612265 + -0.041679582000*_Complex_I, 0.247366762161 + 0.014814090729*_Complex_I, -0.128671801090 + 0.043787026405*_Complex_I, 0.059505617619 + -0.051679652929*_Complex_I, -0.031817299128 + -0.116028845310*_Complex_I, -0.059748482704 + 0.052395486832*_Complex_I, 0.057849615812 + 0.112650203705*_Complex_I, 0.024142844975 + -0.127626419067*_Complex_I, -0.021054366231 + -0.034706163406*_Complex_I, 0.115030443668 + -0.228685379028*_Complex_I, 0.046825522184 + -0.056672191620*_Complex_I, 0.033698257804 + 0.121798670292*_Complex_I, 0.054840600491 + -0.057236319780*_Complex_I, 0.099697828293 + 0.019323211908*_Complex_I, -0.155612981319 + -0.004370240867*_Complex_I, -0.004620010406 + -0.084638983011*_Complex_I, 0.070532739162 + 0.011928464472*_Complex_I, -0.109211897850 + -0.102859199047*_Complex_I, -0.081594198942 + -0.078812837601*_Complex_I, 0.043022164702 + -0.170342290401*_Complex_I, -0.121134638786 + 0.000720720459*_Complex_I, -0.113152539730 + 0.049016854167*_Complex_I, -0.044530594349 + -0.051119738817*_Complex_I, 0.072675555944 + 0.022612531483*_Complex_I, 0.079078042507 + -0.004720374569*_Complex_I, 0.139414632320 + -0.062684261799*_Complex_I, 0.047556161880 + 0.004797710106*_Complex_I, 0.099456727505 + -0.072699415684*_Complex_I, 0.042401811481 + 0.080890959501*_Complex_I, 0.153871464729 + -0.013893789053*_Complex_I, 0.071284359694 + 0.021137169003*_Complex_I, -0.167169976234 + -0.071725249290*_Complex_I, -0.107850408554 + -0.217037105560*_Complex_I, -0.074640941620 + -0.056393194199*_Complex_I, -0.088496351242 + -0.011706933379*_Complex_I, -0.055197536945 + 0.114396464825*_Complex_I, -0.016207906604 + 0.147190082073*_Complex_I, 0.027984252572 + -0.018767827749*_Complex_I, -0.159589684010 + -0.021223792434*_Complex_I, 0.258048582077 + -0.011464864016*_Complex_I, -0.028931617737 + 0.055535191298*_Complex_I, 0.090275204182 + -0.104534256458*_Complex_I, 0.007160897553 + -0.012574975193*_Complex_I, 0.074187409878 + -0.067596536875*_Complex_I, -0.129586255550 + -0.095341777802*_Complex_I, 0.025683063269 + 0.037984248996*_Complex_I, -0.097140216827 + 0.072665137053*_Complex_I, -0.060703277588 + -0.020677544177*_Complex_I, -0.111789143085 + 0.069817501307*_Complex_I, 0.058083856106 + 0.050827920437*_Complex_I, 0.050110381842 + -0.096382743120*_Complex_I, -0.003128097579 + 0.086557382345*_Complex_I, -0.162541246414 + -0.290272450447*_Complex_I, 0.149705743790 + -0.195581960678*_Complex_I, -0.037328532338 + -0.068566280603*_Complex_I, -0.028459328413 + -0.020298738778*_Complex_I, 0.030010712147 + -0.021110333502*_Complex_I, 0.040339571238 + 0.037839868665*_Complex_I, 0.014134916663 + -0.117352914810*_Complex_I, -0.077330631018 + -0.119114518166*_Complex_I, -0.022596450150 + 0.134884607792*_Complex_I, 0.031885313988 + -0.092574226856*_Complex_I, 0.050890713930 + -0.056063300371*_Complex_I, -0.065839445591 + 0.059127074480*_Complex_I, 0.234607529640 + -0.133058774471*_Complex_I, 0.102069032192 + -0.076372599602*_Complex_I, -0.075891935825 + -0.020809832215*_Complex_I, -0.090930736065 + -0.085748946667*_Complex_I, 0.017342594266 + 0.031213536859*_Complex_I, 0.038657885790 + 0.025738736987*_Complex_I, 0.060605341196 + -0.119861590862*_Complex_I, 0.073895943165 + -0.044689002633*_Complex_I, 0.105450510979 + -0.160455989838*_Complex_I, -0.124542450905 + 0.046032539010*_Complex_I, 0.045331561565 + 0.000319873891*_Complex_I, 0.024264129996 + 0.026674240828*_Complex_I, -0.105825412273 + -0.020621740818*_Complex_I, 0.088798046112 + -0.188584482670*_Complex_I, -0.106230950356 + 0.102003884315*_Complex_I, 0.094149869680 + 0.040696659684*_Complex_I, -0.034001356363 + 0.107437086105*_Complex_I, -0.018224966526 + 0.112718844414*_Complex_I, 0.017100249231 + -0.115852773190*_Complex_I, -0.033193737268 + -0.000597832398*_Complex_I, 0.000483878236 + -0.106654667854*_Complex_I, -0.058922708035 + 0.047018918395*_Complex_I, -0.062014073133 + -0.023304754496*_Complex_I, 0.044369766116 + -0.168211150169*_Complex_I, 0.130730128288 + -0.172116661072*_Complex_I, 0.145810830593 + -0.078202575445*_Complex_I, 0.064167177677 + -0.028775659204*_Complex_I, -0.080559664965 + 0.030702465773*_Complex_I, 0.099988013506 + 0.068486881256*_Complex_I, 0.037929025292 + -0.016449454427*_Complex_I, 0.170670747757 + -0.075250750780*_Complex_I, 0.063665509224 + 0.095736193657*_Complex_I, -0.004959807545 + 0.029583230615*_Complex_I, 0.001406790875 + 0.107474470139*_Complex_I, -0.118572568893 + -0.044207367301*_Complex_I, 0.006175531074 + 0.128024518490*_Complex_I, -0.140851879120 + -0.023605427146*_Complex_I, -0.107514488697 + 0.124532020092*_Complex_I, 0.002869207598 + -0.137480175495*_Complex_I, 0.107076263428 + 0.171094465256*_Complex_I, -0.154599738121 + 0.276871156693*_Complex_I, 0.101584804058 + 0.051078712940*_Complex_I, 0.080567914248 + 0.072715389729*_Complex_I, -0.118250894547 + 0.203802919388*_Complex_I, -0.204971146584 + -0.016665045917*_Complex_I, -0.066708135605 + -0.131536126137*_Complex_I, -0.121210551262 + 0.006252479553*_Complex_I, 0.061139965057 + 0.027922019362*_Complex_I, -0.019852848351 + 0.013758929074*_Complex_I, 0.124678170681 + 0.068077403307*_Complex_I, 0.114459848404 + -0.033342263103*_Complex_I, 0.177140033245 + -0.072824108601*_Complex_I, 0.044942480326 + -0.185283625126*_Complex_I, 0.130411398411 + 0.241176652908*_Complex_I, 0.184130918980 + -0.040936833620*_Complex_I, -0.000141406199 + 0.054715901613*_Complex_I, -0.069603371620 + 0.036669918895*_Complex_I, -0.061578559875 + 0.032855123281*_Complex_I, 0.056589269638 + -0.058769983053*_Complex_I, 0.182259237766 + 0.049186679721*_Complex_I, 0.065936774015 + 0.027898868918*_Complex_I, -0.065557408333 + -0.070153760910*_Complex_I, 0.054138237238 + -0.027161026001*_Complex_I, -0.018398490548 + -0.110003650188*_Complex_I, 0.002755430155 + 0.078435707092*_Complex_I, 0.013758489490 + -0.113180506229*_Complex_I, -0.051234912872 + -0.005474814028*_Complex_I, -0.104593336582 + 0.080550593138*_Complex_I, 0.007267350703 + -0.125861871243*_Complex_I, 0.107477843761 + 0.046790626645*_Complex_I, 0.039212217927 + -0.116215384007*_Complex_I, 0.124826478958 + -0.081632637978*_Complex_I, 0.125280117989 + 0.320632147789*_Complex_I, -0.007471156120 + 0.104660058022*_Complex_I, -0.115239381790 + -0.076022726297*_Complex_I, -0.094622492790 + -0.057151579857*_Complex_I, -0.168905770779 + -0.250946950912*_Complex_I, -0.108807468414 + 0.001907045953*_Complex_I, 0.070568650961 + 0.086386668682*_Complex_I, -0.001869313978 + 0.037941047549*_Complex_I, -0.025408759713 + 0.082414060831*_Complex_I, 0.144938981533 + 0.203817605972*_Complex_I, 0.069982367754 + 0.049768888950*_Complex_I, 0.016490152478 + 0.074179810286*_Complex_I, 0.105687451363 + -0.110984444618*_Complex_I, 0.113551545143 + 0.109880757332*_Complex_I, -0.057247632742 + 0.134226346016*_Complex_I, -0.147579395771 + 0.089595174789*_Complex_I, -0.066095471382 + -0.101449275017*_Complex_I, -0.099719625711 + 0.069632160664*_Complex_I, -0.010588133335 + 0.072132295370*_Complex_I, 0.121390247345 + 0.038519486785*_Complex_I, -0.018545143306 + -0.181026077271*_Complex_I, 0.063769525290 + -0.064973735809*_Complex_I, -0.069635564089 + -0.033288177848*_Complex_I, -0.191137075424 + -0.041628292203*_Complex_I, 0.078501302004 + 0.084461838007*_Complex_I, 0.057879024744 + -0.055903303623*_Complex_I, -0.024872413278 + -0.012924948335*_Complex_I, 0.030974438787 + 0.053028428555*_Complex_I, 0.108443212509 + 0.096264117956*_Complex_I, 0.020256328583 + 0.141622221470*_Complex_I, -0.014323671162 + 0.037487837672*_Complex_I, -0.054792886972 + -0.018909129500*_Complex_I, 0.112955272198 + -0.105722856522*_Complex_I, 0.076327735186 + -0.023400066793*_Complex_I, 0.050041192770 + -0.111338639259*_Complex_I, -0.152574229240 + 0.112567448616*_Complex_I, -0.100790119171 + 0.151508641243*_Complex_I, -0.132981181145 + -0.022067332268*_Complex_I, -0.039436492324 + -0.142156898975*_Complex_I, 0.272883749008 + -0.021410278976*_Complex_I, 0.016576641798 + 0.044247716665*_Complex_I, -0.043560856581 + 0.035046094656*_Complex_I, 0.048125803471 + 0.009931682050*_Complex_I, 0.067209833860 + 0.107492733002*_Complex_I, -0.046075564623 + 0.075197333097*_Complex_I, -0.102803206444 + 0.086919504404*_Complex_I, 0.082356423140 + 0.014404250681*_Complex_I, -0.008545895666 + 0.062289041281*_Complex_I, -0.137773501873 + -0.077222770452*_Complex_I, 0.011148673296 + 0.004276630655*_Complex_I, -0.013848714530 + 0.030436140299*_Complex_I, -0.032711941004 + -0.004091787338*_Complex_I, -0.068230164051 + -0.041420990229*_Complex_I, -0.153997719288 + -0.011947461963*_Complex_I, 0.104870522022 + 0.007879497856*_Complex_I, -0.012260202318 + 0.097705692053*_Complex_I, 0.105240559578 + 0.005197756737*_Complex_I, -0.052444481850 + 0.019592680037*_Complex_I, -0.111304521561 + -0.082899254560*_Complex_I, 0.143180394173 + 0.084308052063*_Complex_I, -0.081846255064 + 0.013113263249*_Complex_I, -0.046875402331 + 0.172497475147*_Complex_I, -0.101886129379 + 0.027100220323*_Complex_I, -0.120501518250 + -0.011151956767*_Complex_I, -0.069285804033 + -0.066505169868*_Complex_I, 0.135213494301 + -0.155834245682*_Complex_I, 0.120262145996 + -0.073802947998*_Complex_I, 0.083161532879 + 0.151243543625*_Complex_I, 0.032715103030 + 0.113134217262*_Complex_I, 0.029656037688 + 0.049728840590*_Complex_I, -0.002572274208 + -0.116174411774*_Complex_I, -0.028744161129 + 0.043948829174*_Complex_I, -0.039567849040 + 0.071218341589*_Complex_I, -0.008260916919 + -0.064960545301*_Complex_I, 0.065007799864 + -0.006339413673*_Complex_I, -0.060093468428 + 0.035650527477*_Complex_I, 0.056396996975 + 0.005192263052*_Complex_I}; float complex fftfilt_cccf_data_h7x256_y[] = { 0.002351481406 + -0.018484625365*_Complex_I, -0.000060077369 + 0.017251119786*_Complex_I, -0.023422599244 + 0.015025306572*_Complex_I, 0.004772403706 + -0.000066271937*_Complex_I, 0.002043987108 + 0.022957322244*_Complex_I, 0.006971825136 + 0.011730423896*_Complex_I, 0.075044907061 + -0.010178051817*_Complex_I, 0.030543599209 + -0.014597024085*_Complex_I, -0.004187564049 + -0.012444862513*_Complex_I, -0.008030018509 + -0.052716125275*_Complex_I, -0.014464683212 + -0.025509129789*_Complex_I, -0.010946291967 + 0.010946463449*_Complex_I, -0.019083957948 + 0.052439959673*_Complex_I, 0.066017066062 + -0.011801681075*_Complex_I, 0.012681132555 + -0.044881829563*_Complex_I, 0.013761162913 + -0.101272173584*_Complex_I, -0.025754029961 + -0.084604999250*_Complex_I, -0.029077685715 + 0.014810788777*_Complex_I, -0.052203914324 + -0.045501878664*_Complex_I, 0.002605824684 + 0.042542814124*_Complex_I, -0.020042313554 + 0.020106358559*_Complex_I, -0.001164073801 + 0.033904434250*_Complex_I, 0.054491738690 + 0.009310176063*_Complex_I, 0.008515506861 + -0.011753395733*_Complex_I, 0.094828569883 + -0.026525642698*_Complex_I, 0.008210310591 + -0.020111342169*_Complex_I, -0.019624361168 + -0.039339738841*_Complex_I, -0.014390113878 + -0.046568094370*_Complex_I, 0.022417994509 + 0.019882474081*_Complex_I, -0.042352866908 + -0.063076024765*_Complex_I, 0.006168688437 + -0.049455732212*_Complex_I, 0.024885397093 + 0.019187383987*_Complex_I, -0.027570701811 + 0.012482396648*_Complex_I, 0.034892258750 + 0.024754673210*_Complex_I, -0.019859377031 + 0.024455238102*_Complex_I, -0.017573930231 + 0.012206492330*_Complex_I, -0.000030036343 + -0.018861530511*_Complex_I, -0.047303454990 + -0.008979343421*_Complex_I, -0.032862144074 + 0.013096445775*_Complex_I, -0.003290051529 + 0.000967363362*_Complex_I, 0.056330016511 + -0.016207422066*_Complex_I, -0.009913108504 + 0.058827181838*_Complex_I, 0.034154084481 + -0.006877816529*_Complex_I, 0.020659033034 + 0.020329190951*_Complex_I, -0.033737500188 + 0.029784749533*_Complex_I, -0.014787869426 + -0.101188110643*_Complex_I, 0.104978906788 + 0.041126486668*_Complex_I, -0.014250954609 + -0.012495039834*_Complex_I, -0.033482494554 + -0.025221829498*_Complex_I, -0.021831072247 + 0.022276580945*_Complex_I, -0.039699732339 + 0.032109615994*_Complex_I, 0.015186398989 + -0.019223783117*_Complex_I, 0.015617783227 + 0.023435548030*_Complex_I, 0.008665069769 + 0.010930457080*_Complex_I, -0.019797730380 + -0.050654536825*_Complex_I, -0.031473081271 + -0.002299268225*_Complex_I, -0.012475915927 + 0.033630086770*_Complex_I, 0.012117088154 + -0.022047521436*_Complex_I, 0.018953771446 + 0.084550384232*_Complex_I, -0.038474316372 + 0.008379280035*_Complex_I, -0.004152321333 + -0.040424140749*_Complex_I, -0.015770397680 + 0.041094196479*_Complex_I, -0.032229291824 + 0.007648330888*_Complex_I, 0.017449905676 + -0.027618778546*_Complex_I, -0.006186370902 + 0.022452120667*_Complex_I, -0.030800615243 + 0.036816080788*_Complex_I, 0.022326504033 + 0.029342855626*_Complex_I, 0.033861836665 + 0.027757022091*_Complex_I, 0.033294890809 + 0.063126561257*_Complex_I, 0.026195622962 + -0.034339699352*_Complex_I, 0.036201082469 + -0.036428336260*_Complex_I, -0.008587770526 + -0.012485601384*_Complex_I, -0.015622310942 + -0.008490102192*_Complex_I, -0.031068211782 + 0.008958937995*_Complex_I, -0.007527617323 + -0.009025029679*_Complex_I, -0.003515003755 + 0.009061780897*_Complex_I, -0.050680655889 + 0.006806632206*_Complex_I, -0.037393296454 + -0.018572129400*_Complex_I, -0.068556095005 + 0.055060185831*_Complex_I, -0.034772327965 + 0.025392795717*_Complex_I, 0.068529963519 + 0.033603853922*_Complex_I, 0.068141793595 + 0.036809357702*_Complex_I, 0.044397919943 + 0.034591392907*_Complex_I, 0.016558611126 + -0.038538049919*_Complex_I, 0.039037787845 + -0.030382584037*_Complex_I, -0.047508232653 + -0.037136167083*_Complex_I, 0.022633104346 + -0.021161468084*_Complex_I, 0.019417536232 + -0.025786181928*_Complex_I, -0.073279279420 + 0.029450944763*_Complex_I, -0.028480466565 + -0.024506456063*_Complex_I, 0.002785948604 + 0.049355785551*_Complex_I, -0.027211045311 + 0.018218457773*_Complex_I, 0.010057004283 + 0.043364801389*_Complex_I, 0.052591845448 + 0.024521644529*_Complex_I, -0.007103268409 + -0.008581702223*_Complex_I, 0.054820608058 + -0.043395183529*_Complex_I, 0.007024973331 + 0.024411987870*_Complex_I, -0.021388284266 + -0.082405595490*_Complex_I, -0.016087426094 + 0.012722301935*_Complex_I, -0.051447296267 + 0.037652130140*_Complex_I, -0.020486080157 + -0.013825054104*_Complex_I, 0.077051270037 + 0.059321440673*_Complex_I, -0.007177045570 + 0.063268745704*_Complex_I, -0.007356525502 + -0.002336907547*_Complex_I, 0.015196504414 + 0.005533310901*_Complex_I, -0.020595977716 + 0.027771059823*_Complex_I, -0.024966648066 + -0.018445080957*_Complex_I, 0.039144080425 + 0.064591816908*_Complex_I, 0.010537647232 + -0.002822061917*_Complex_I, 0.002315709356 + -0.065572625222*_Complex_I, -0.004442911821 + 0.023522751103*_Complex_I, -0.037537461559 + 0.002025051546*_Complex_I, -0.015345245866 + -0.018745889894*_Complex_I, -0.028196845561 + 0.086992050424*_Complex_I, -0.020218420272 + 0.034974063899*_Complex_I, 0.039213934957 + -0.014112442962*_Complex_I, 0.010679269036 + -0.019758241192*_Complex_I, -0.019147387264 + -0.013125586740*_Complex_I, -0.043295632029 + 0.009486453379*_Complex_I, 0.005284847258 + 0.018994059412*_Complex_I, -0.002085765180 + 0.059479538243*_Complex_I, -0.029236803469 + 0.019741499311*_Complex_I, 0.035349982194 + -0.019550030169*_Complex_I, -0.041053561980 + 0.019272334294*_Complex_I, 0.004781302105 + -0.011012070475*_Complex_I, 0.045646671834 + 0.021045605276*_Complex_I, 0.012770406300 + 0.038111716908*_Complex_I, 0.027329675786 + -0.046058315366*_Complex_I, -0.039771978581 + 0.000217202102*_Complex_I, -0.009660565931 + -0.044728920362*_Complex_I, -0.009225975226 + 0.004924878144*_Complex_I, 0.002703841656 + 0.032097754317*_Complex_I, 0.004813881897 + -0.003380733447*_Complex_I, 0.004987905899 + 0.008151460089*_Complex_I, -0.013488990428 + -0.042016257678*_Complex_I, -0.009691719041 + 0.004147526727*_Complex_I, -0.001915632244 + 0.039683487703*_Complex_I, 0.003401771653 + 0.072636903863*_Complex_I, -0.039215694844 + 0.021883077630*_Complex_I, 0.017168617098 + -0.011912327212*_Complex_I, -0.007318874653 + -0.021289530606*_Complex_I, -0.021564667106 + -0.032135038803*_Complex_I, -0.018800999207 + 0.028531206788*_Complex_I, -0.021400100758 + 0.015792926127*_Complex_I, -0.021993149924 + 0.008754610031*_Complex_I, 0.006936290706 + 0.000597376601*_Complex_I, -0.021466822342 + 0.006078512969*_Complex_I, 0.032723812926 + -0.038751398566*_Complex_I, 0.024881623268 + 0.028431503514*_Complex_I, 0.023419199688 + -0.017541455668*_Complex_I, 0.050912833475 + -0.066376947294*_Complex_I, 0.054697680345 + 0.030926451912*_Complex_I, -0.032668768209 + -0.026228308942*_Complex_I, -0.011814848889 + -0.099139861759*_Complex_I, -0.019161603567 + 0.029704427790*_Complex_I, -0.036750148181 + 0.005099535581*_Complex_I, 0.009675516891 + -0.040182618193*_Complex_I, 0.058423255788 + -0.009856816276*_Complex_I, 0.059012388904 + 0.021583146036*_Complex_I, 0.037149929970 + -0.044837871667*_Complex_I, -0.043274833420 + -0.019633669057*_Complex_I, 0.003526349344 + -0.033434222301*_Complex_I, -0.050076212918 + -0.003722989863*_Complex_I, -0.025867292105 + -0.013323971651*_Complex_I, -0.021737697568 + 0.042999651371*_Complex_I, 0.007346070802 + 0.030458687290*_Complex_I, -0.075005823056 + -0.018314546864*_Complex_I, -0.022152256082 + 0.019384502494*_Complex_I, 0.017499070564 + -0.019824208197*_Complex_I, 0.001505234864 + -0.027164808784*_Complex_I, 0.011030624309 + -0.041209715189*_Complex_I, -0.026294492121 + 0.019222017912*_Complex_I, -0.050856019432 + 0.008735996115*_Complex_I, -0.027403486053 + 0.008700019502*_Complex_I, 0.006815542339 + -0.009666401504*_Complex_I, 0.006105705172 + 0.040222173395*_Complex_I, -0.012075903008 + 0.033397015302*_Complex_I, 0.012019759958 + -0.021944616302*_Complex_I, 0.017925084955 + 0.052323963578*_Complex_I, -0.030587094207 + -0.037431463625*_Complex_I, 0.042390892393 + -0.046071078594*_Complex_I, 0.020356789621 + 0.037541180532*_Complex_I, -0.029260492422 + -0.016824122043*_Complex_I, 0.038403000345 + 0.018077265958*_Complex_I, -0.050358282861 + 0.031195025615*_Complex_I, -0.103007313184 + -0.046673399500*_Complex_I, -0.015001996713 + 0.007412936952*_Complex_I, 0.030614255358 + 0.024026842526*_Complex_I, 0.030514848064 + 0.031032426681*_Complex_I, 0.103356759873 + 0.027622431036*_Complex_I, 0.043667006406 + -0.014369006727*_Complex_I, 0.002636002600 + -0.019049360571*_Complex_I, -0.002989929744 + -0.026987627040*_Complex_I, -0.001094610254 + -0.070463253033*_Complex_I, -0.052461850294 + -0.027889438408*_Complex_I, -0.019216539397 + -0.007771079643*_Complex_I, -0.022329844508 + -0.013265024739*_Complex_I, -0.001032810892 + 0.043621747952*_Complex_I, -0.037166418731 + 0.024063055407*_Complex_I, 0.025171222560 + -0.045359590807*_Complex_I, 0.034025739768 + -0.022421529929*_Complex_I, 0.025417150018 + -0.024301770390*_Complex_I, 0.015009353323 + -0.045864470900*_Complex_I, -0.057523653826 + 0.003583092215*_Complex_I, -0.034434260403 + 0.016881949843*_Complex_I, 0.035644457860 + 0.058158734255*_Complex_I, -0.011112332655 + 0.028514917481*_Complex_I, 0.027994412412 + -0.000205339299*_Complex_I, 0.041965151118 + -0.028140201223*_Complex_I, -0.010670315886 + -0.004680002358*_Complex_I, 0.008782107185 + 0.015284218025*_Complex_I, 0.025707610980 + -0.002674567128*_Complex_I, -0.018895101407 + -0.019624170860*_Complex_I, -0.019911769609 + -0.024108802516*_Complex_I, -0.050134730896 + -0.049361961836*_Complex_I, -0.012519484934 + -0.027194287781*_Complex_I, 0.005428457404 + 0.015715697375*_Complex_I, -0.005238127738 + 0.060099693736*_Complex_I, -0.019908892893 + 0.058463294088*_Complex_I, 0.020429924866 + 0.006302169131*_Complex_I, 0.039448100593 + -0.046219948910*_Complex_I, -0.015700342290 + -0.047106832460*_Complex_I, 0.029509140574 + -0.026543641019*_Complex_I, 0.028367751154 + 0.020535031374*_Complex_I, -0.052572208167 + 0.041630709393*_Complex_I, -0.001077487262 + -0.000376269684*_Complex_I, 0.009826813537 + -0.019618490100*_Complex_I, 0.019631481777 + -0.007463103449*_Complex_I, -0.034282389268 + 0.002382911984*_Complex_I, -0.002559574060 + -0.045197738751*_Complex_I, 0.021242907296 + -0.020034144666*_Complex_I, -0.026802493199 + 0.013457289582*_Complex_I, 0.000954596220 + -0.020243773142*_Complex_I, 0.034013053731 + 0.024387771984*_Complex_I, -0.020040092793 + -0.001711964654*_Complex_I, 0.022898948260 + 0.014147183418*_Complex_I, 0.004346236707 + -0.000881433760*_Complex_I, 0.056049489865 + -0.020165330024*_Complex_I, 0.010340548926 + 0.003943868642*_Complex_I, -0.020562812005 + -0.025528198571*_Complex_I, -0.012419521606 + -0.000626407753*_Complex_I, -0.026985254984 + 0.006236327937*_Complex_I, 0.035672449990 + 0.000476818088*_Complex_I, 0.034040270392 + 0.009473149874*_Complex_I, -0.021617320834 + 0.027702717665*_Complex_I, 0.010577232861 + -0.016439967770*_Complex_I, -0.018705783473 + -0.051973816043*_Complex_I, 0.017231348174 + -0.025014597024*_Complex_I, 0.027788678270 + -0.014081809821*_Complex_I, 0.035390113297 + -0.001427819683*_Complex_I, -0.010424664995 + 0.044346140061*_Complex_I, -0.018385369373 + 0.007862320395*_Complex_I, -0.032248235088 + -0.015582515953*_Complex_I, -0.037693834890 + -0.014701063462*_Complex_I, -0.006787010773 + -0.016420585935*_Complex_I, 0.026470441729 + 0.040610897283*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_crcf_data_h13x256.c000066400000000000000000000651151474751757600246500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_crcf_data_h13x256.c: autotest fftfilt data // #include float fftfilt_crcf_data_h13x256_h[] = { 0.078415364027, -0.038823145628, -0.051182097197, -0.126747608185, -0.044354891777, 0.008586834371, 0.093218648434, 0.013351599872, 0.104246592522, -0.147247779369, -0.015137273073, -0.079225271940, 0.060841810703}; float complex fftfilt_crcf_data_h13x256_x[] = { 0.085537636280 + -0.046111658216*_Complex_I, 0.225455975533 + -0.212855386734*_Complex_I, -0.057062256336 + 0.128235316277*_Complex_I, -0.133161616325 + 0.161920166016*_Complex_I, -0.111347568035 + 0.016286674142*_Complex_I, -0.123166453838 + -0.175749886036*_Complex_I, -0.127994334698 + -0.038678660989*_Complex_I, 0.001753777266 + 0.177034842968*_Complex_I, -0.060360968113 + 0.043074116111*_Complex_I, -0.019538708031 + 0.103789019585*_Complex_I, -0.014221027493 + -0.063071894646*_Complex_I, 0.068899226189 + -0.026364141703*_Complex_I, 0.115704405308 + -0.004594086856*_Complex_I, 0.007105919719 + -0.147161698341*_Complex_I, -0.108864045143 + 0.057467007637*_Complex_I, -0.068811172247 + -0.147289085388*_Complex_I, -0.230341863632 + -0.117713248730*_Complex_I, 0.212086534500 + 0.075316011906*_Complex_I, 0.111719250679 + -0.054894649982*_Complex_I, -0.058907771111 + 0.011760091782*_Complex_I, 0.040262156725 + 0.204210424423*_Complex_I, 0.056027442217 + -0.155560147762*_Complex_I, 0.086805480719 + -0.004523682222*_Complex_I, 0.036359512806 + 0.141219484806*_Complex_I, -0.220814013481 + -0.062183243036*_Complex_I, 0.153262519836 + -0.046371394396*_Complex_I, 0.026782101393 + -0.145832955837*_Complex_I, 0.065809303522 + 0.160269105434*_Complex_I, -0.350135111809 + -0.025641095638*_Complex_I, -0.014225926995 + -0.006095404923*_Complex_I, 0.025032842159 + 0.079940289259*_Complex_I, -0.153848528862 + 0.047698283195*_Complex_I, -0.074249881506 + -0.036540001631*_Complex_I, -0.058573323488 + -0.038949799538*_Complex_I, -0.004152575880 + 0.284297037125*_Complex_I, -0.135746490955 + 0.021615330875*_Complex_I, 0.016607114673 + -0.020308291912*_Complex_I, 0.152347302437 + 0.127957522869*_Complex_I, -0.010453918576 + 0.027730533481*_Complex_I, 0.014759464562 + 0.026369267702*_Complex_I, 0.082868421078 + 0.018653041124*_Complex_I, 0.036655226350 + 0.110286545753*_Complex_I, -0.089152860641 + -0.036632573605*_Complex_I, 0.039231717587 + 0.077600806952*_Complex_I, -0.081070268154 + -0.003452447802*_Complex_I, 0.000562082976 + 0.017119739950*_Complex_I, 0.144655835629 + 0.104714202881*_Complex_I, 0.014049226046 + 0.166446399689*_Complex_I, 0.088486814499 + -0.014644494653*_Complex_I, 0.057762199640 + -0.093236494064*_Complex_I, 0.047099858522 + -0.028719729185*_Complex_I, 0.106528282166 + 0.020991277695*_Complex_I, 0.138301646709 + -0.257377123833*_Complex_I, 0.080518740416 + 0.154109323025*_Complex_I, -0.024190089107 + -0.061511921883*_Complex_I, 0.000458766706 + 0.001026612055*_Complex_I, 0.099718827009 + -0.065688782930*_Complex_I, -0.029233866930 + -0.195329236984*_Complex_I, -0.066604834795 + 0.089790678024*_Complex_I, -0.068512433767 + 0.076835018396*_Complex_I, 0.050179117918 + 0.095668357611*_Complex_I, -0.025827249885 + 0.161506593227*_Complex_I, -0.044248852134 + -0.043011960387*_Complex_I, -0.065869921446 + -0.124157130718*_Complex_I, -0.022857676446 + 0.034576061368*_Complex_I, -0.092982125282 + 0.081510609388*_Complex_I, 0.197520732880 + 0.040147519112*_Complex_I, 0.064278131723 + -0.020518574119*_Complex_I, -0.044479858875 + -0.093625146151*_Complex_I, 0.006783248484 + 0.080368715525*_Complex_I, 0.015499952435 + 0.014531745017*_Complex_I, 0.097499859333 + 0.031322878599*_Complex_I, 0.075692665577 + 0.103051352501*_Complex_I, -0.127897429466 + 0.147205972672*_Complex_I, -0.227601456642 + -0.086447989941*_Complex_I, 0.079460048676 + 0.009285532683*_Complex_I, -0.104196500778 + -0.062360990047*_Complex_I, -0.003569463268 + -0.159094834328*_Complex_I, -0.015271052718 + 0.053798562288*_Complex_I, 0.038455364108 + 0.154173243046*_Complex_I, 0.055872535706 + -0.233663058281*_Complex_I, -0.008917537332 + 0.091611146927*_Complex_I, 0.086029797792 + -0.039757794142*_Complex_I, 0.049558714032 + -0.151712751389*_Complex_I, 0.080167847872 + 0.034949752688*_Complex_I, -0.050086444616 + 0.050132060051*_Complex_I, 0.083901208639 + 0.046979528666*_Complex_I, -0.132237958908 + 0.095516347885*_Complex_I, 0.091105806828 + 0.120565533638*_Complex_I, 0.043457311392 + -0.141374385357*_Complex_I, -0.013054405153 + -0.100194096565*_Complex_I, -0.159590744972 + 0.033074292541*_Complex_I, 0.000640281662 + -0.032389008999*_Complex_I, 0.003084850125 + 0.021032336354*_Complex_I, -0.185569190979 + 0.124299430847*_Complex_I, -0.011914233118 + -0.237578940392*_Complex_I, -0.171687960625 + -0.104329741001*_Complex_I, -0.069582682848 + -0.225686883926*_Complex_I, -0.113897264004 + 0.090501463413*_Complex_I, 0.093735665083 + 0.154317796230*_Complex_I, 0.014358232915 + -0.103527617455*_Complex_I, -0.008946143836 + 0.126785087585*_Complex_I, -0.137021541595 + -0.133091437817*_Complex_I, -0.093204009533 + -0.052661812305*_Complex_I, -0.017306408286 + 0.105603075027*_Complex_I, -0.070221811533 + -0.083750408888*_Complex_I, 0.026400086284 + -0.231271290779*_Complex_I, -0.067720073462 + 0.057201570272*_Complex_I, -0.048747465014 + -0.065235435963*_Complex_I, 0.043681365252 + -0.104784011841*_Complex_I, -0.090612548590 + -0.275935935974*_Complex_I, -0.003840988874 + 0.110235190392*_Complex_I, 0.175717639923 + 0.039627754688*_Complex_I, -0.095855474472 + -0.109507787228*_Complex_I, -0.103805732727 + 0.047046291828*_Complex_I, 0.102693021297 + -0.121691584587*_Complex_I, 0.205679154396 + 0.105767965317*_Complex_I, -0.076863563061 + -0.109635329247*_Complex_I, 0.008887568116 + -0.008115684241*_Complex_I, 0.115569293499 + -0.002244588919*_Complex_I, 0.114743447304 + 0.110550260544*_Complex_I, -0.207589817047 + 0.076551246643*_Complex_I, 0.001820044219 + 0.039755198359*_Complex_I, 0.120840430260 + 0.207095527649*_Complex_I, 0.060907727480 + 0.108076405525*_Complex_I, -0.068012183905 + -0.004220475256*_Complex_I, -0.075779396296 + 0.192010104656*_Complex_I, 0.176728832722 + -0.014139008522*_Complex_I, 0.003537797555 + -0.008619928360*_Complex_I, 0.105585181713 + -0.044047874212*_Complex_I, -0.042796334624 + 0.104850161076*_Complex_I, -0.051997685432 + 0.156431221962*_Complex_I, 0.020244561136 + 0.167572557926*_Complex_I, 0.145088231564 + 0.027772811055*_Complex_I, 0.037466460466 + 0.109766936302*_Complex_I, -0.098527204990 + -0.032260373235*_Complex_I, 0.009477450699 + -0.035027536750*_Complex_I, -0.016112615168 + 0.085437601805*_Complex_I, 0.143263375759 + 0.075950628519*_Complex_I, 0.106226658821 + 0.103723526001*_Complex_I, 0.000303745759 + -0.010642482340*_Complex_I, 0.108046162128 + -0.032960096002*_Complex_I, -0.003579319268 + 0.113042652607*_Complex_I, 0.004739668965 + -0.090823930502*_Complex_I, -0.075828909874 + -0.005588034540*_Complex_I, -0.085471099615 + -0.016970762610*_Complex_I, 0.011292902380 + -0.025727859139*_Complex_I, -0.003472129628 + -0.066497987509*_Complex_I, 0.052674955130 + 0.053410953283*_Complex_I, 0.171188580990 + 0.164189565182*_Complex_I, -0.031832432747 + -0.106380403042*_Complex_I, 0.104630780220 + -0.005379130691*_Complex_I, 0.146008169651 + -0.016912537813*_Complex_I, 0.001029302273 + 0.191088676453*_Complex_I, -0.189716017246 + -0.017046442628*_Complex_I, -0.098682647943 + 0.001545182616*_Complex_I, 0.017514893413 + -0.091537868977*_Complex_I, 0.046101492643 + -0.087318551540*_Complex_I, 0.006703664362 + -0.168205010891*_Complex_I, -0.017618760467 + 0.027586823702*_Complex_I, -0.131682169437 + 0.043349444866*_Complex_I, 0.050538945198 + 0.176133990288*_Complex_I, -0.053573626280 + -0.126223480701*_Complex_I, 0.196893954277 + -0.158274137974*_Complex_I, -0.148222410679 + 0.046666064858*_Complex_I, 0.095723485947 + 0.036118236184*_Complex_I, -0.072401177883 + -0.081512874365*_Complex_I, 0.057588219643 + 0.215086269379*_Complex_I, 0.082906532288 + 0.065297931433*_Complex_I, -0.031125253439 + 0.089076888561*_Complex_I, -0.022213415802 + -0.206439447403*_Complex_I, -0.128299164772 + 0.021574760973*_Complex_I, 0.044257754087 + 0.042379784584*_Complex_I, 0.201319956779 + -0.054105019569*_Complex_I, 0.028415796161 + -0.068978685141*_Complex_I, -0.011957987398 + 0.176460993290*_Complex_I, 0.090524059534 + -0.115864157677*_Complex_I, -0.107446074486 + -0.129327297211*_Complex_I, 0.089880418777 + 0.060228496790*_Complex_I, -0.030561709404 + 0.026375296712*_Complex_I, 0.098281121254 + -0.215652251244*_Complex_I, -0.007009872049 + -0.074216008186*_Complex_I, -0.004887212813 + 0.159088206291*_Complex_I, 0.056175363064 + 0.101569080353*_Complex_I, -0.062076961994 + -0.057750892639*_Complex_I, -0.126010406017 + 0.065122300386*_Complex_I, -0.049417442083 + 0.079578405619*_Complex_I, 0.104471850395 + -0.222810673714*_Complex_I, 0.008511145413 + 0.109938132763*_Complex_I, 0.037150239944 + 0.084586590528*_Complex_I, 0.050007992983 + -0.057158488035*_Complex_I, -0.035429692268 + 0.058791869879*_Complex_I, -0.155366706848 + 0.118630039692*_Complex_I, 0.047825142741 + -0.105882799625*_Complex_I, -0.109545922279 + -0.002970626391*_Complex_I, 0.130073928833 + 0.085777258873*_Complex_I, -0.039974737167 + 0.114924871922*_Complex_I, 0.082493311167 + -0.066850924492*_Complex_I, 0.094225972891 + -0.016298688948*_Complex_I, -0.196156990528 + -0.039484533668*_Complex_I, 0.221052432060 + 0.012097968161*_Complex_I, 0.011275211722 + -0.101457715034*_Complex_I, 0.009068550915 + 0.102877616882*_Complex_I, 0.233158087730 + 0.028579771519*_Complex_I, 0.103334558010 + 0.013103367388*_Complex_I, 0.113383591175 + 0.299872016907*_Complex_I, 0.003663517535 + -0.053204262257*_Complex_I, 0.016009953618 + -0.204974889755*_Complex_I, -0.129484927654 + -0.081961399317*_Complex_I, 0.043841245770 + -0.172690594196*_Complex_I, 0.016576626897 + 0.178835308552*_Complex_I, 0.021964907646 + -0.018969631195*_Complex_I, 0.040968599916 + 0.013126873970*_Complex_I, -0.139588427544 + 0.084010922909*_Complex_I, -0.119654500484 + 0.023274496198*_Complex_I, -0.069549763203 + 0.014241448045*_Complex_I, 0.061426883936 + 0.037087076902*_Complex_I, -0.101361310482 + -0.062185329199*_Complex_I, -0.112329518795 + -0.115670502186*_Complex_I, 0.134469640255 + 0.146243238449*_Complex_I, 0.069860440493 + -0.059987205267*_Complex_I, 0.002678702772 + 0.026742336154*_Complex_I, -0.100598180294 + 0.019916568696*_Complex_I, 0.112527644634 + 0.158179092407*_Complex_I, -0.044148188829 + 0.048926886916*_Complex_I, -0.036606773734 + -0.143591856956*_Complex_I, 0.058808875084 + 0.019581055641*_Complex_I, 0.036360570788 + 0.014478833973*_Complex_I, 0.175481355190 + 0.010096323490*_Complex_I, 0.108694136143 + -0.070673483610*_Complex_I, 0.090956181288 + -0.025260141492*_Complex_I, -0.051956391335 + -0.102067518234*_Complex_I, -0.136262392998 + -0.047263675928*_Complex_I, -0.003427351639 + -0.120171773434*_Complex_I, -0.056164652109 + 0.211695027351*_Complex_I, 0.122092783451 + 0.066175770760*_Complex_I, 0.058047491312 + 0.006997314841*_Complex_I, -0.052954304218 + -0.022754417360*_Complex_I, 0.142856597900 + 0.108723735809*_Complex_I, -0.034428742528 + -0.054634892941*_Complex_I, -0.060924202204 + 0.031046575308*_Complex_I, -0.200955986977 + -0.117396569252*_Complex_I, -0.088245415688 + 0.019958937168*_Complex_I, -0.020239216089 + 0.041008698940*_Complex_I, 0.016120427847 + -0.252910399437*_Complex_I, -0.005489441007 + -0.005252978206*_Complex_I, 0.146177339554 + -0.124855351448*_Complex_I, 0.008751311898 + 0.021546928585*_Complex_I, -0.045790722966 + -0.055281382799*_Complex_I, 0.020690375566 + 0.076892906427*_Complex_I, 0.021331049502 + -0.009237347543*_Complex_I, 0.055180394650 + -0.023450747132*_Complex_I, -0.200542330742 + -0.096801882982*_Complex_I, 0.010742266476 + 0.088201242685*_Complex_I, 0.072365719080 + 0.038520815969*_Complex_I, 0.174543678761 + -0.139873552322*_Complex_I}; float complex fftfilt_crcf_data_h13x256_y[] = { 0.006707464887 + -0.003615862465*_Complex_I, 0.014358372283 + -0.014900933014*_Complex_I, -0.017605463388 + 0.020679426057*_Complex_I, -0.030607580793 + 0.024457457884*_Complex_I, -0.033011059558 + 0.017451711642*_Complex_I, -0.000552862047 + -0.029909500040*_Complex_I, 0.029762551415 + -0.029380501742*_Complex_I, 0.053098771667 + -0.004223742190*_Complex_I, 0.027764068736 + 0.025733123329*_Complex_I, 0.019184165051 + 0.011649528617*_Complex_I, -0.045468748657 + 0.015676561918*_Complex_I, -0.015208315362 + -0.029868068751*_Complex_I, -0.005074731196 + -0.025633738248*_Complex_I, 0.016953787198 + -0.036545469115*_Complex_I, -0.015051143400 + 0.040438104378*_Complex_I, -0.000389921114 + 0.040583727841*_Complex_I, -0.018476482937 + 0.001605043113*_Complex_I, 0.059276110787 + 0.008087486852*_Complex_I, 0.032014951529 + -0.026016763072*_Complex_I, 0.028169341465 + 0.019691597843*_Complex_I, -0.027575406956 + 0.014924607884*_Complex_I, -0.044969293038 + -0.034038723353*_Complex_I, -0.035957879305 + 0.009864897267*_Complex_I, 0.015551833890 + -0.025044401657*_Complex_I, -0.025072135741 + 0.016447641694*_Complex_I, 0.067713809538 + 0.015047662589*_Complex_I, -0.014827314512 + -0.006159133526*_Complex_I, 0.017417617315 + 0.018940542198*_Complex_I, -0.051497901101 + 0.013839514218*_Complex_I, 0.006425931128 + -0.012107460374*_Complex_I, 0.003778314165 + 0.004734451148*_Complex_I, 0.024107174779 + -0.007035831300*_Complex_I, -0.010365520171 + -0.022195343173*_Complex_I, 0.051580386373 + -0.008087616648*_Complex_I, -0.021776665000 + -0.003115102667*_Complex_I, 0.023266451034 + 0.047344342773*_Complex_I, -0.053848275959 + -0.026819242730*_Complex_I, 0.063009256294 + -0.009944000506*_Complex_I, 0.006746963810 + -0.032158195839*_Complex_I, 0.003429372021 + -0.000544080428*_Complex_I, -0.021562011789 + -0.003250402475*_Complex_I, -0.014790441461 + -0.003085695467*_Complex_I, 0.010008967449 + 0.023823269718*_Complex_I, -0.008293948136 + -0.022998494726*_Complex_I, 0.011452965518 + -0.020435253906*_Complex_I, 0.025061888640 + -0.008646415119*_Complex_I, 0.009417229303 + 0.002491707097*_Complex_I, -0.001052856194 + 0.014974027706*_Complex_I, -0.009405958690 + -0.029993691331*_Complex_I, -0.014721142637 + -0.008638802539*_Complex_I, -0.036054668791 + -0.043505364136*_Complex_I, 0.002937162197 + 0.016396266668*_Complex_I, -0.004075444532 + -0.014475666608*_Complex_I, 0.011656769213 + 0.056296896866*_Complex_I, -0.011068622206 + 0.001107236820*_Complex_I, -0.029464500491 + 0.023806584861*_Complex_I, -0.001234548257 + -0.043088390782*_Complex_I, -0.013592614491 + -0.029832033410*_Complex_I, 0.009582371751 + 0.002336669503*_Complex_I, -0.007665271794 + 0.050333730164*_Complex_I, 0.006935919041 + 0.000935532598*_Complex_I, -0.003952523598 + 0.051259768228*_Complex_I, -0.006392118058 + -0.064666858821*_Complex_I, -0.009497007771 + -0.021680677945*_Complex_I, 0.009619420930 + -0.042495568141*_Complex_I, -0.014045975317 + 0.022418973657*_Complex_I, 0.028464744316 + 0.062481882056*_Complex_I, 0.001067687053 + 0.012760185564*_Complex_I, 0.016381591820 + -0.014605527050*_Complex_I, -0.034415502412 + -0.026979376550*_Complex_I, -0.017681907434 + -0.024441169492*_Complex_I, -0.005897651761 + 0.007001263045*_Complex_I, 0.033278467741 + 0.020304401627*_Complex_I, -0.015372239067 + 0.016871371540*_Complex_I, 0.004123217473 + -0.031815284855*_Complex_I, -0.015306721649 + -0.031111950511*_Complex_I, 0.004503865148 + -0.033058697462*_Complex_I, 0.029142795487 + 0.022150281542*_Complex_I, 0.019772837268 + 0.022699222634*_Complex_I, 0.015820827834 + 0.046069967481*_Complex_I, -0.023442270401 + -0.016297278519*_Complex_I, -0.026038769435 + 0.011214015864*_Complex_I, -0.021468228990 + -0.057542563457*_Complex_I, 0.034028743864 + -0.002254875536*_Complex_I, -0.006908951528 + 0.001680565517*_Complex_I, 0.007793730477 + 0.032660744962*_Complex_I, -0.019663600279 + 0.025988218786*_Complex_I, -0.003368100468 + 0.026542388675*_Complex_I, 0.013438824633 + -0.047413054472*_Complex_I, -0.004063114270 + -0.015525778855*_Complex_I, 0.018830244631 + -0.044104705319*_Complex_I, -0.032245213510 + 0.016288658540*_Complex_I, 0.007245432060 + 0.024854569789*_Complex_I, -0.027446572547 + 0.041850280938*_Complex_I, 0.029419010658 + 0.028727610740*_Complex_I, -0.010452476889 + -0.044041749123*_Complex_I, 0.030615778213 + -0.021544600594*_Complex_I, -0.006420674173 + -0.051315896975*_Complex_I, 0.016696184929 + 0.047238754510*_Complex_I, 0.005689845758 + 0.063096109099*_Complex_I, 0.028255169043 + 0.036125238544*_Complex_I, 0.012724807027 + -0.010983186848*_Complex_I, -0.042681639075 + -0.046834116871*_Complex_I, -0.000989952691 + -0.059638193499*_Complex_I, -0.014509988842 + 0.030996292286*_Complex_I, 0.058136967808 + 0.004841843998*_Complex_I, 0.016711224472 + 0.056418115581*_Complex_I, 0.042240824058 + 0.015983263464*_Complex_I, -0.022083897958 + -0.024086928202*_Complex_I, -0.001789727311 + 0.023860817657*_Complex_I, -0.029894590649 + -0.040496551187*_Complex_I, 0.018773801669 + 0.051847548401*_Complex_I, 0.031709831384 + 0.011373889090*_Complex_I, -0.004023229281 + 0.020313196377*_Complex_I, -0.001577893158 + -0.019338873041*_Complex_I, -0.016653147805 + 0.001029965867*_Complex_I, 0.022914141726 + -0.002104645021*_Complex_I, 0.004474041805 + 0.010394883929*_Complex_I, -0.007920863082 + -0.015181966976*_Complex_I, -0.013430955196 + 0.050824400632*_Complex_I, 0.008429368466 + 0.016663178667*_Complex_I, -0.040384189162 + -0.005524017450*_Complex_I, 0.002595592227 + -0.002667437393*_Complex_I, 0.009304373200 + -0.026400357126*_Complex_I, 0.048184754654 + 0.020873671678*_Complex_I, -0.030489638011 + -0.058480052355*_Complex_I, -0.016679991101 + 0.018809245099*_Complex_I, -0.008746544102 + -0.035440693217*_Complex_I, 0.015062452407 + 0.019391877795*_Complex_I, -0.022136074513 + -0.020072882619*_Complex_I, 0.000436956008 + 0.007335145893*_Complex_I, -0.008872275506 + 0.020549897080*_Complex_I, -0.002241620183 + 0.006218861440*_Complex_I, -0.001175415969 + -0.040479462629*_Complex_I, 0.000083899519 + -0.021882526156*_Complex_I, 0.025794092443 + -0.065356864610*_Complex_I, -0.035076022000 + -0.002349257653*_Complex_I, -0.003341037071 + -0.006590144581*_Complex_I, -0.014034503634 + 0.051948837186*_Complex_I, 0.030633439581 + 0.013809324577*_Complex_I, -0.002962173263 + -0.011885141436*_Complex_I, -0.000277152583 + -0.057872949989*_Complex_I, -0.041128587589 + -0.009986479197*_Complex_I, -0.032666587947 + -0.028631352014*_Complex_I, -0.000937363608 + 0.018495486941*_Complex_I, 0.007753441209 + 0.008806508191*_Complex_I, 0.037266455064 + 0.010636476395*_Complex_I, 0.006587066115 + -0.001705926814*_Complex_I, 0.003108159036 + -0.006628853141*_Complex_I, 0.010939472752 + 0.006955405461*_Complex_I, -0.035625089431 + 0.003442599966*_Complex_I, -0.008902105887 + -0.028853630235*_Complex_I, -0.032226114328 + -0.009004482236*_Complex_I, -0.005180831436 + 0.005500644217*_Complex_I, -0.013588249735 + 0.016986170136*_Complex_I, -0.001619772072 + 0.000519931731*_Complex_I, 0.016514152427 + -0.020852436461*_Complex_I, 0.046615752684 + -0.000490623097*_Complex_I, 0.005417795160 + -0.036933916369*_Complex_I, 0.007190900949 + 0.046477922845*_Complex_I, -0.045185383594 + 0.017921427684*_Complex_I, -0.014537612941 + 0.075949416617*_Complex_I, -0.029141623074 + -0.059957316195*_Complex_I, 0.049424271568 + -0.033258736817*_Complex_I, 0.012029563939 + -0.050271746506*_Complex_I, 0.023861869121 + 0.035334845394*_Complex_I, -0.046542548410 + 0.016947426572*_Complex_I, 0.004060617093 + 0.071512899954*_Complex_I, -0.014037223962 + -0.012127913597*_Complex_I, 0.039889046850 + 0.005706366222*_Complex_I, -0.028460519816 + -0.096256824265*_Complex_I, 0.022664509438 + -0.011714722989*_Complex_I, -0.050769105818 + 0.012359859521*_Complex_I, 0.066087653016 + 0.054750882096*_Complex_I, -0.020633352616 + 0.001005601365*_Complex_I, 0.024688652114 + 0.040909798080*_Complex_I, -0.040302384002 + -0.048949559759*_Complex_I, -0.040499641156 + 0.001157352899*_Complex_I, 0.003027817515 + -0.057483585836*_Complex_I, -0.004425501836 + 0.047349196316*_Complex_I, 0.050482303632 + -0.003841475384*_Complex_I, 0.006892893469 + 0.023406378381*_Complex_I, -0.016436659880 + -0.003310696286*_Complex_I, -0.033973819400 + 0.045991336264*_Complex_I, -0.006077224480 + -0.023680985792*_Complex_I, -0.024572808359 + -0.010230339465*_Complex_I, 0.032481213736 + -0.024751506834*_Complex_I, -0.000140080804 + -0.013756951783*_Complex_I, 0.045204061251 + -0.001863065274*_Complex_I, -0.014671178560 + 0.022868286772*_Complex_I, -0.008200142546 + 0.040201740584*_Complex_I, -0.028297364362 + 0.011407262105*_Complex_I, -0.031979428685 + -0.029902785287*_Complex_I, 0.007876129419 + -0.034552491520*_Complex_I, 0.011879957596 + 0.002102523326*_Complex_I, 0.065685674192 + -0.021696600034*_Complex_I, -0.004436318677 + 0.044689761692*_Complex_I, 0.006444035464 + -0.009625205044*_Complex_I, -0.031610428157 + -0.001954799840*_Complex_I, -0.028459000697 + -0.034725990869*_Complex_I, -0.011174251949 + 0.010299896743*_Complex_I, 0.023757183405 + -0.012151501352*_Complex_I, -0.001899448573 + 0.033748924229*_Complex_I, 0.045121542184 + 0.003981235350*_Complex_I, -0.039350108228 + 0.019225662049*_Complex_I, 0.000272360769 + -0.022187283938*_Complex_I, -0.039963184290 + -0.025512380416*_Complex_I, -0.048539833099 + -0.045287358543*_Complex_I, 0.014614456311 + -0.006244097705*_Complex_I, -0.005955795663 + -0.016811959796*_Complex_I, 0.034965200850 + 0.085058210904*_Complex_I, 0.019869783149 + 0.033565877203*_Complex_I, -0.007450313153 + 0.019794672596*_Complex_I, -0.024234527340 + -0.013904685967*_Complex_I, -0.056857838231 + -0.065401336188*_Complex_I, 0.008081702581 + -0.037938012149*_Complex_I, 0.013228639879 + 0.003618896346*_Complex_I, 0.047207180558 + 0.006639688435*_Complex_I, 0.005206139690 + 0.048614164213*_Complex_I, 0.012317627070 + -0.009658873466*_Complex_I, -0.008051197208 + 0.015338520918*_Complex_I, -0.017767221557 + -0.001246156194*_Complex_I, -0.012973491018 + -0.004457537375*_Complex_I, -0.001247711756 + -0.000324872382*_Complex_I, 0.015217577217 + -0.018849976281*_Complex_I, -0.000220920310 + -0.022284388072*_Complex_I, 0.007337925412 + -0.022911190749*_Complex_I, 0.026359365671 + 0.027517236286*_Complex_I, 0.008511664801 + -0.000024345933*_Complex_I, -0.006523939632 + 0.027431135887*_Complex_I, -0.045640085613 + -0.016594833325*_Complex_I, -0.011370492419 + 0.008910655275*_Complex_I, -0.045188661133 + -0.014169350102*_Complex_I, 0.006126649841 + -0.018848731487*_Complex_I, 0.020184591301 + 0.049393686574*_Complex_I, 0.050790767045 + 0.013516083838*_Complex_I, 0.030911878104 + 0.013274684518*_Complex_I, -0.032128201429 + -0.056563309721*_Complex_I, -0.024604150985 + -0.007862317966*_Complex_I, -0.053074476432 + -0.026948064488*_Complex_I, -0.016714258122 + 0.036960212668*_Complex_I, 0.003641941365 + -0.017652191591*_Complex_I, 0.014976615622 + 0.055005028639*_Complex_I, 0.047122774118 + -0.019075872589*_Complex_I, 0.027958265929 + -0.005155130760*_Complex_I, 0.006577988759 + -0.021876641490*_Complex_I, 0.018186494518 + 0.020647216102*_Complex_I, -0.047150707407 + 0.008796453305*_Complex_I, -0.018231362190 + 0.025611832961*_Complex_I, -0.044254892960 + -0.000932158388*_Complex_I, 0.029538101318 + 0.008693714282*_Complex_I, 0.025472319724 + -0.006973878349*_Complex_I, 0.012287778194 + -0.046541397503*_Complex_I, -0.003318140133 + 0.036850102200*_Complex_I, 0.015644777552 + -0.006720827246*_Complex_I, 0.011761450619 + 0.045924263037*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_crcf_data_h23x256.c000066400000000000000000000654251474751757600246550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_crcf_data_h23x256.c: autotest fftfilt data // #include float fftfilt_crcf_data_h23x256_h[] = { 0.175772392750, 0.016595666111, -0.074416112900, 0.010717856884, -0.091077792645, 0.152976071835, -0.025270926952, 0.021845243871, -0.001858575456, -0.090402913094, -0.054905104637, 0.135398101807, -0.000730551640, 0.029069179296, -0.117681956291, 0.088986778259, -0.005193765089, 0.047553667426, -0.093419462442, 0.060808116198, 0.138476681709, 0.104599690437, 0.007943090051}; float complex fftfilt_crcf_data_h23x256_x[] = { 0.155103063583 + -0.039989483356*_Complex_I, 0.089731889963 + 0.007783630490*_Complex_I, 0.031814819574 + -0.092475223541*_Complex_I, -0.052295821905 + 0.059911632538*_Complex_I, -0.128601908684 + -0.137423527241*_Complex_I, -0.005442334712 + 0.136688292027*_Complex_I, -0.110040140152 + 0.129731595516*_Complex_I, 0.070668441057 + 0.014537031949*_Complex_I, -0.043719315529 + -0.018183282018*_Complex_I, -0.023593281209 + -0.088085335493*_Complex_I, 0.079267203808 + -0.050603461266*_Complex_I, 0.091274780035 + -0.041612377763*_Complex_I, -0.063425219059 + 0.028925007582*_Complex_I, 0.029070848227 + -0.047291010618*_Complex_I, -0.016231997311 + -0.220043921471*_Complex_I, 0.001723764278 + -0.110049223900*_Complex_I, 0.044714280963 + -0.016450446844*_Complex_I, -0.050305968523 + 0.038971278071*_Complex_I, -0.118738901615 + -0.027668058872*_Complex_I, -0.065542882681 + -0.056009286642*_Complex_I, 0.087729597092 + -0.011164753139*_Complex_I, 0.078783208132 + -0.036137032509*_Complex_I, -0.024815648794 + -0.187882483006*_Complex_I, 0.157861471176 + -0.075281244516*_Complex_I, 0.002852580696 + -0.062035644054*_Complex_I, 0.010516438633 + 0.137531483173*_Complex_I, 0.028980562091 + -0.067520070076*_Complex_I, 0.022702263296 + 0.036881408095*_Complex_I, -0.072563153505 + -0.135415744781*_Complex_I, -0.130733311176 + -0.031472635269*_Complex_I, -0.132395064831 + -0.013236595690*_Complex_I, -0.050313913822 + -0.001110552903*_Complex_I, -0.182336819172 + 0.011559166759*_Complex_I, 0.034110882878 + -0.085457748175*_Complex_I, 0.010640498996 + 0.024029432237*_Complex_I, -0.031135216355 + -0.075218772888*_Complex_I, -0.113621425629 + -0.020260357857*_Complex_I, 0.035748475790 + -0.047527408600*_Complex_I, 0.158889925480 + -0.108263909817*_Complex_I, 0.058575540781 + 0.029335317016*_Complex_I, -0.012806682289 + 0.062627220154*_Complex_I, 0.017389293015 + 0.082187730074*_Complex_I, -0.155518913269 + -0.130875742435*_Complex_I, -0.110213851929 + 0.189839553833*_Complex_I, 0.052800035477 + 0.166894078255*_Complex_I, -0.017228771746 + 0.002264509723*_Complex_I, 0.126624763012 + 0.014616450667*_Complex_I, 0.074029338360 + 0.130479073524*_Complex_I, 0.039149993658 + -0.081848907471*_Complex_I, -0.174016666412 + -0.002245875075*_Complex_I, -0.060786378384 + 0.087645614147*_Complex_I, 0.057222455740 + -0.064347177744*_Complex_I, -0.158683681488 + 0.064550727606*_Complex_I, 0.058903807402 + -0.197414779663*_Complex_I, 0.022170741856 + 0.005642867088*_Complex_I, -0.019022856653 + 0.026909428835*_Complex_I, 0.054943174124 + -0.010510860384*_Complex_I, -0.130231952667 + -0.085019159317*_Complex_I, 0.057500022650 + -0.036732053757*_Complex_I, 0.105791926384 + 0.016274939477*_Complex_I, 0.116283416748 + -0.056632959843*_Complex_I, 0.009825258702 + 0.019144052267*_Complex_I, 0.196307218075 + -0.048692828417*_Complex_I, 0.010651530325 + 0.008062589169*_Complex_I, 0.064581054449 + -0.010377624631*_Complex_I, 0.089088356495 + 0.044110041857*_Complex_I, -0.000476853596 + -0.038994494081*_Complex_I, 0.105319905281 + -0.132293283939*_Complex_I, 0.009918146580 + -0.041363826394*_Complex_I, 0.036220628023 + -0.030043822527*_Complex_I, 0.025852039456 + 0.067388910055*_Complex_I, -0.083622449636 + -0.035971945524*_Complex_I, -0.100427985191 + 0.044513091445*_Complex_I, -0.185684227943 + -0.040250685811*_Complex_I, -0.117641401291 + -0.084515213966*_Complex_I, 0.041368806362 + 0.039818888903*_Complex_I, -0.237114048004 + 0.125617718697*_Complex_I, -0.054697531462 + 0.033353772759*_Complex_I, -0.074546104670 + -0.125889337063*_Complex_I, 0.033940449357 + 0.015348845720*_Complex_I, -0.045566964149 + 0.039473927021*_Complex_I, -0.015814815462 + -0.096754157543*_Complex_I, 0.140625333786 + 0.088005954027*_Complex_I, -0.109252071381 + -0.058004480600*_Complex_I, 0.006840997189 + 0.123340046406*_Complex_I, -0.043643641472 + 0.077158600092*_Complex_I, -0.073954302073 + 0.095201927423*_Complex_I, -0.024249210954 + 0.057317435741*_Complex_I, 0.018241013587 + 0.081239950657*_Complex_I, -0.091524779797 + -0.259817528725*_Complex_I, -0.026682430506 + -0.034324991703*_Complex_I, 0.088583648205 + -0.007783739269*_Complex_I, 0.183037674427 + 0.111340200901*_Complex_I, -0.076495563984 + -0.089935213327*_Complex_I, 0.016016796231 + 0.185418581963*_Complex_I, 0.090234714746 + -0.036095014215*_Complex_I, 0.016144131124 + 0.097066044807*_Complex_I, 0.012245001644 + 0.095291149616*_Complex_I, -0.161877584457 + -0.052310425043*_Complex_I, -0.033721217513 + -0.012814992666*_Complex_I, 0.091250944138 + 0.131859993935*_Complex_I, -0.128745031357 + -0.084740310907*_Complex_I, -0.061492395401 + -0.099420046806*_Complex_I, 0.012414894253 + -0.015323466063*_Complex_I, 0.012217399478 + 0.012398956716*_Complex_I, 0.050523018837 + -0.087095749378*_Complex_I, -0.015820150077 + -0.054119426012*_Complex_I, -0.055258476734 + 0.020015104115*_Complex_I, 0.063105708361 + 0.042238712311*_Complex_I, 0.017720183730 + 0.017351190746*_Complex_I, -0.141501569748 + -0.117573750019*_Complex_I, -0.006765382737 + 0.056032115221*_Complex_I, -0.004831269756 + -0.002968831547*_Complex_I, -0.032051759958 + -0.190994548798*_Complex_I, 0.036215576530 + 0.173437201977*_Complex_I, -0.189757418633 + -0.055692046881*_Complex_I, -0.059237557650 + 0.126770603657*_Complex_I, 0.038132804632 + -0.074801898003*_Complex_I, 0.088674974442 + -0.053153961897*_Complex_I, -0.078639388084 + 0.046550104022*_Complex_I, -0.018440252542 + 0.040226161480*_Complex_I, -0.001557452139 + 0.011683121324*_Complex_I, -0.251441335678 + 0.073139393330*_Complex_I, -0.205929875374 + 0.018797023594*_Complex_I, -0.004785243422 + 0.018977609277*_Complex_I, -0.008223478496 + 0.016689766943*_Complex_I, -0.013542374969 + 0.098333865404*_Complex_I, 0.174354946613 + -0.053679537773*_Complex_I, 0.070709151030 + 0.105750656128*_Complex_I, -0.004860538989 + -0.093827313185*_Complex_I, 0.008115487546 + 0.105573391914*_Complex_I, -0.086253505945 + -0.016359496117*_Complex_I, 0.260078501701 + 0.011332800239*_Complex_I, -0.106663954258 + -0.106564879417*_Complex_I, 0.103312873840 + -0.263231492043*_Complex_I, -0.054847794771 + 0.040892100334*_Complex_I, 0.110823535919 + -0.184762966633*_Complex_I, -0.071165961027 + -0.055934780836*_Complex_I, -0.178788268566 + -0.044872501493*_Complex_I, -0.046904963255 + -0.092374777794*_Complex_I, 0.162701845169 + 0.020701634884*_Complex_I, -0.101515638828 + 0.074363875389*_Complex_I, 0.057615011930 + -0.117078483105*_Complex_I, 0.020440319180 + 0.002894190140*_Complex_I, -0.066558498144 + 0.002631408162*_Complex_I, 0.016302645206 + 0.071249717474*_Complex_I, -0.062377142906 + 0.063173556328*_Complex_I, 0.115204286575 + 0.057497209311*_Complex_I, 0.094178062677 + 0.013675969839*_Complex_I, 0.039668846130 + -0.104888665676*_Complex_I, -0.077536809444 + 0.030107039213*_Complex_I, 0.019500632584 + -0.077639460564*_Complex_I, -0.036470189691 + 0.141290163994*_Complex_I, -0.202891373634 + -0.006020304561*_Complex_I, 0.142597723007 + 0.001829937287*_Complex_I, 0.042515522242 + -0.033903941512*_Complex_I, -0.160332143307 + 0.167697465420*_Complex_I, 0.065906691551 + -0.046222153306*_Complex_I, -0.014665135741 + 0.029732593894*_Complex_I, -0.161926984787 + -0.039980190992*_Complex_I, 0.216635417938 + -0.084111690521*_Complex_I, 0.111900138855 + -0.088012528419*_Complex_I, 0.131331551075 + -0.075983870029*_Complex_I, -0.110518038273 + 0.217655158043*_Complex_I, -0.019964502752 + 0.029798141122*_Complex_I, -0.077271521091 + 0.017983873188*_Complex_I, 0.192190217972 + -0.034995573759*_Complex_I, 0.121502757072 + -0.071480178833*_Complex_I, 0.082723850012 + -0.001845339499*_Complex_I, -0.072242385149 + -0.005906258896*_Complex_I, -0.176676702499 + 0.110248458385*_Complex_I, 0.080035436153 + 0.107154047489*_Complex_I, 0.023038166761 + -0.114933979511*_Complex_I, -0.139963030815 + -0.063580548763*_Complex_I, -0.024152973294 + -0.165445506573*_Complex_I, 0.175627219677 + 0.068415731192*_Complex_I, 0.062092590332 + -0.063827121258*_Complex_I, 0.058578062057 + 0.007875456661*_Complex_I, 0.076061081886 + -0.132551908493*_Complex_I, 0.104943084717 + -0.084286916256*_Complex_I, 0.019696915150 + 0.003201137111*_Complex_I, 0.079270011187 + 0.105154144764*_Complex_I, 0.067746007442 + 0.087236845493*_Complex_I, -0.095283645391 + -0.162002611160*_Complex_I, -0.049992722273 + 0.118607068062*_Complex_I, 0.107323861122 + -0.174439251423*_Complex_I, -0.132320475578 + 0.017735700309*_Complex_I, 0.010226617008 + -0.197343289852*_Complex_I, -0.065331441164 + -0.169277667999*_Complex_I, -0.067106610537 + 0.003877854347*_Complex_I, 0.149599671364 + -0.130133831501*_Complex_I, -0.082966232300 + -0.140549242496*_Complex_I, -0.121567571163 + 0.111494851112*_Complex_I, -0.040895500779 + 0.242881941795*_Complex_I, 0.046610686183 + 0.190598750114*_Complex_I, -0.241175961494 + 0.038187211752*_Complex_I, 0.091600197554 + 0.075727856159*_Complex_I, 0.138635289669 + 0.048851582408*_Complex_I, 0.142762672901 + 0.008544234186*_Complex_I, 0.129457914829 + 0.013422895968*_Complex_I, -0.118289554119 + 0.265937256813*_Complex_I, 0.010878042877 + -0.077647930384*_Complex_I, -0.070324224234 + 0.039972990751*_Complex_I, -0.041980904341 + 0.067246806622*_Complex_I, -0.150996875763 + 0.028954780102*_Complex_I, 0.023831695318 + -0.059671503305*_Complex_I, -0.060499125719 + 0.022479967773*_Complex_I, 0.042781451344 + -0.012739011645*_Complex_I, -0.058961522579 + 0.108779168129*_Complex_I, -0.123040950298 + -0.084437525272*_Complex_I, -0.031985121965 + 0.144360256195*_Complex_I, 0.009733268619 + -0.105923128128*_Complex_I, -0.133637535572 + -0.006438682973*_Complex_I, 0.049610015750 + -0.120102596283*_Complex_I, 0.112718105316 + 0.129998087883*_Complex_I, -0.142268264294 + -0.013222855330*_Complex_I, 0.119939064980 + 0.084782326221*_Complex_I, -0.002139478363 + 0.143925952911*_Complex_I, -0.017734520137 + 0.060474181175*_Complex_I, -0.115593242645 + 0.266750621796*_Complex_I, -0.122079384327 + 0.060140782595*_Complex_I, -0.116746783257 + 0.058306437731*_Complex_I, -0.035461139679 + -0.199710798264*_Complex_I, -0.012796324492 + -0.006662363559*_Complex_I, -0.168765580654 + -0.080484443903*_Complex_I, 0.109565150738 + -0.066066616774*_Complex_I, 0.167375874519 + -0.095793098211*_Complex_I, 0.063125562668 + -0.015197466314*_Complex_I, -0.131772887707 + 0.043374121189*_Complex_I, 0.108676636219 + 0.016854281723*_Complex_I, -0.158170187473 + 0.066611725092*_Complex_I, 0.186592674255 + -0.119178080559*_Complex_I, 0.258357715607 + 0.035161945224*_Complex_I, -0.267501235008 + 0.113799548149*_Complex_I, -0.121099197865 + -0.008966898173*_Complex_I, -0.080716609955 + 0.092299455404*_Complex_I, 0.052158069611 + 0.009480424225*_Complex_I, 0.042302635312 + -0.107537162304*_Complex_I, -0.149109280109 + 0.086092722416*_Complex_I, -0.047981733084 + 0.051883894205*_Complex_I, 0.129582881927 + 0.080048167706*_Complex_I, 0.020590978861 + 0.052324140072*_Complex_I, -0.127634072304 + 0.003840797022*_Complex_I, -0.015030093491 + 0.081028074026*_Complex_I, -0.151265537739 + 0.073973071575*_Complex_I, 0.065107202530 + -0.102953696251*_Complex_I, 0.020201592147 + -0.043066096306*_Complex_I, -0.041327267885 + -0.084052354097*_Complex_I, 0.039087793231 + -0.027260744572*_Complex_I, 0.149368381500 + 0.085757601261*_Complex_I, -0.045472341776 + -0.007366366684*_Complex_I, -0.014300452173 + 0.070052427053*_Complex_I, -0.030928212404 + 0.008410415053*_Complex_I, 0.102823138237 + 0.089631778002*_Complex_I, -0.046347615123 + 0.012207016349*_Complex_I, -0.022019737959 + 0.008490467072*_Complex_I}; float complex fftfilt_crcf_data_h23x256_y[] = { 0.027262836609 + -0.007029047174*_Complex_I, 0.018346427661 + 0.000704495242*_Complex_I, -0.004460839644 + -0.013149554871*_Complex_I, -0.013679299641 + 0.007988293987*_Complex_I, -0.039004795515 + -0.012553764367*_Complex_I, 0.016696266867 + 0.009469516192*_Complex_I, -0.003513172567 + 0.046564035001*_Complex_I, 0.020372582455 + -0.027609901195*_Complex_I, 0.006199293336 + 0.013118588352*_Complex_I, -0.042660178683 + -0.048881324868*_Complex_I, 0.012162311731 + 0.006692219554*_Complex_I, 0.005999545171 + 0.012678334008*_Complex_I, 0.016925234916 + 0.011802413052*_Complex_I, 0.012643874018 + -0.002379618949*_Complex_I, -0.019843625969 + -0.042091077177*_Complex_I, -0.002447170334 + -0.066361916522*_Complex_I, 0.027635184820 + 0.025233499033*_Complex_I, -0.023950232537 + 0.018344717328*_Complex_I, -0.001523383406 + 0.047987234347*_Complex_I, -0.037208867735 + -0.060587103130*_Complex_I, 0.040881005070 + -0.012194712051*_Complex_I, 0.051353615432 + -0.030052114039*_Complex_I, 0.039843962567 + -0.018530512464*_Complex_I, -0.011241859913 + 0.003314208877*_Complex_I, -0.023931715066 + -0.008536051326*_Complex_I, -0.046474201238 + 0.019213392371*_Complex_I, 0.026420531301 + 0.008903961274*_Complex_I, -0.003321242652 + -0.005089987861*_Complex_I, 0.018094294321 + 0.009055610544*_Complex_I, -0.065634402614 + -0.053749750040*_Complex_I, -0.023600007069 + 0.001972776975*_Complex_I, 0.029460287631 + -0.022729601752*_Complex_I, -0.005045917714 + 0.054578580699*_Complex_I, -0.007148429271 + -0.055204501924*_Complex_I, 0.010660749874 + -0.059471864271*_Complex_I, -0.028011323273 + -0.066785744888*_Complex_I, 0.011622802421 + 0.013720590963*_Complex_I, -0.036631828451 + 0.003833520561*_Complex_I, 0.047864856646 + -0.017738859345*_Complex_I, -0.007990385588 + -0.035672288313*_Complex_I, 0.004986325822 + 0.029278794046*_Complex_I, -0.016889528458 + -0.015755301985*_Complex_I, -0.010143232206 + -0.021096571154*_Complex_I, -0.009806462106 + -0.047616138372*_Complex_I, 0.051880472016 + 0.035421818987*_Complex_I, 0.004878725946 + -0.006588080806*_Complex_I, 0.059514317675 + 0.025245817016*_Complex_I, -0.041213052806 + 0.001434752292*_Complex_I, -0.031520998781 + -0.026425494383*_Complex_I, -0.042062234079 + -0.023223262575*_Complex_I, -0.031771373601 + -0.001999239137*_Complex_I, 0.003008538314 + 0.007873584524*_Complex_I, -0.044522016963 + 0.031453229897*_Complex_I, -0.004123811253 + -0.100618757520*_Complex_I, 0.000868379196 + -0.007049767471*_Complex_I, -0.035358534934 + 0.039935982082*_Complex_I, 0.001096892916 + -0.008139914684*_Complex_I, -0.045888282337 + -0.028654012806*_Complex_I, 0.054241028654 + -0.040641857373*_Complex_I, 0.076384681516 + -0.009290596232*_Complex_I, -0.014394459295 + 0.031937206347*_Complex_I, 0.029290098261 + 0.000294924311*_Complex_I, -0.024684029149 + 0.000989628106*_Complex_I, -0.016171486419 + 0.031195541518*_Complex_I, -0.014868511208 + 0.014303327420*_Complex_I, 0.021852231291 + 0.016723227953*_Complex_I, 0.020272353403 + 0.015401209854*_Complex_I, 0.071528405043 + 0.017807463305*_Complex_I, -0.020235058791 + -0.039855986142*_Complex_I, -0.034484804762 + 0.000496010405*_Complex_I, 0.007189500129 + 0.020495810669*_Complex_I, -0.021931884508 + 0.027723824179*_Complex_I, -0.045456425035 + -0.019096529483*_Complex_I, -0.017800090999 + -0.040386165849*_Complex_I, -0.031040929546 + -0.045937861114*_Complex_I, 0.065367936599 + 0.021960412702*_Complex_I, -0.060220212620 + 0.045242058344*_Complex_I, -0.015791818114 + -0.002107138847*_Complex_I, -0.016776877211 + -0.047286567469*_Complex_I, 0.014399266122 + -0.042073854865*_Complex_I, 0.056679887935 + 0.012644277043*_Complex_I, -0.008511751801 + 0.004971041195*_Complex_I, 0.081952669986 + 0.012577593191*_Complex_I, -0.012764140374 + -0.011967000266*_Complex_I, -0.003336654686 + -0.001262645566*_Complex_I, 0.016350375874 + 0.032350783323*_Complex_I, 0.010862760597 + -0.035926563231*_Complex_I, 0.029863051593 + 0.043664156677*_Complex_I, -0.012277218714 + -0.028013771036*_Complex_I, -0.021453932268 + -0.061946366678*_Complex_I, 0.031514206628 + -0.020671975000*_Complex_I, -0.023541686556 + 0.038816659613*_Complex_I, 0.015568416177 + 0.034767821284*_Complex_I, -0.053493562550 + 0.010727696220*_Complex_I, -0.041010374462 + -0.065258809696*_Complex_I, 0.005288272932 + 0.024477688872*_Complex_I, -0.046902277134 + -0.000092205057*_Complex_I, 0.001627461508 + 0.080137549979*_Complex_I, -0.065128047455 + -0.060262053915*_Complex_I, 0.006596006298 + 0.065336899466*_Complex_I, 0.000058721241 + -0.040094018767*_Complex_I, -0.036305854351 + -0.003934363665*_Complex_I, 0.008450440041 + -0.033595118529*_Complex_I, 0.029549628861 + 0.041310102659*_Complex_I, -0.031905285980 + -0.031000918152*_Complex_I, 0.011726181555 + 0.060113189533*_Complex_I, -0.047367175488 + -0.048891971737*_Complex_I, 0.019495535591 + 0.085142512409*_Complex_I, 0.018357043313 + -0.001756917795*_Complex_I, -0.044850116879 + -0.007540707159*_Complex_I, -0.040509844673 + -0.092704738011*_Complex_I, 0.045015777649 + 0.044308907043*_Complex_I, 0.033412972066 + 0.006857384940*_Complex_I, -0.013027623910 + -0.030790116518*_Complex_I, -0.000975157484 + 0.037733658737*_Complex_I, -0.022753324517 + 0.023070309941*_Complex_I, 0.021078444893 + 0.032118433292*_Complex_I, 0.010443833730 + 0.016807510307*_Complex_I, -0.038157141667 + -0.083720289418*_Complex_I, 0.015884591663 + 0.080444457603*_Complex_I, -0.014224915913 + 0.005135806833*_Complex_I, -0.025232136903 + 0.004144801774*_Complex_I, -0.077288630878 + -0.005906892810*_Complex_I, -0.034553210182 + -0.017846341663*_Complex_I, 0.035746673427 + -0.012259253660*_Complex_I, 0.036525883688 + -0.010525857333*_Complex_I, -0.014488296110 + -0.014305379613*_Complex_I, -0.015958243599 + 0.045987466851*_Complex_I, 0.003179382534 + -0.018266667088*_Complex_I, 0.029305351113 + 0.000580102615*_Complex_I, -0.043259878864 + -0.037454506754*_Complex_I, -0.028365132804 + 0.065377160248*_Complex_I, 0.070378428765 + -0.056958149428*_Complex_I, 0.004867726670 + 0.005962596169*_Complex_I, -0.037918405464 + -0.091858574411*_Complex_I, -0.019631672181 + 0.051212141219*_Complex_I, -0.057622870703 + -0.011592712757*_Complex_I, 0.039759648837 + 0.003839054841*_Complex_I, -0.059496690769 + -0.007464198304*_Complex_I, 0.020562373454 + -0.038245564570*_Complex_I, 0.032578387575 + 0.008176063763*_Complex_I, -0.022640669374 + 0.032133098133*_Complex_I, -0.059754420752 + -0.022200850890*_Complex_I, -0.021917765961 + 0.061715182774*_Complex_I, -0.070723789096 + -0.036769285459*_Complex_I, 0.040897570713 + 0.020449142350*_Complex_I, -0.078688142274 + 0.044106118254*_Complex_I, 0.132511709017 + -0.002283572710*_Complex_I, 0.031006482035 + 0.023633310053*_Complex_I, 0.000719650304 + -0.060425994891*_Complex_I, -0.068488182320 + 0.011823413272*_Complex_I, 0.033571377809 + 0.001638620807*_Complex_I, 0.013415095820 + 0.063237008575*_Complex_I, 0.003843590843 + -0.032020775100*_Complex_I, 0.005708962317 + -0.073909950927*_Complex_I, 0.043060259091 + -0.039410177301*_Complex_I, -0.031531087064 + -0.004760009337*_Complex_I, -0.001506462543 + -0.004643974469*_Complex_I, -0.069117792716 + -0.013243456525*_Complex_I, -0.008999132078 + -0.025213996567*_Complex_I, 0.076230704310 + -0.038893791301*_Complex_I, -0.016693801234 + 0.016189526184*_Complex_I, 0.053793442954 + -0.046315507571*_Complex_I, -0.022323859813 + 0.074471398757*_Complex_I, -0.077019541390 + 0.000776612640*_Complex_I, 0.028852092849 + -0.003754892925*_Complex_I, 0.030634254859 + -0.031119630463*_Complex_I, 0.070978930378 + 0.018366156735*_Complex_I, 0.011314850738 + 0.020679865086*_Complex_I, -0.009529937549 + 0.025881841685*_Complex_I, -0.099579012075 + -0.013132370673*_Complex_I, 0.044640476208 + 0.044583555144*_Complex_I, 0.016522002764 + -0.063707510591*_Complex_I, 0.003035671136 + -0.013751873371*_Complex_I, -0.026798937752 + -0.022117369500*_Complex_I, 0.007823238214 + 0.038428718991*_Complex_I, -0.033760635042 + 0.056366436739*_Complex_I, 0.061213467638 + -0.037917433069*_Complex_I, -0.019400770671 + 0.002314675027*_Complex_I, 0.030275097259 + -0.065680749303*_Complex_I, -0.012116792287 + 0.011848118163*_Complex_I, 0.036218177449 + -0.012568718012*_Complex_I, 0.060643006355 + 0.043892825588*_Complex_I, 0.017806428565 + -0.022264383863*_Complex_I, -0.048473906401 + 0.014501335500*_Complex_I, -0.031370768130 + -0.040223039246*_Complex_I, 0.019781480670 + 0.021758320109*_Complex_I, 0.063634947558 + -0.007457977030*_Complex_I, 0.020848525728 + -0.052882085833*_Complex_I, -0.063823888094 + 0.004319709113*_Complex_I, 0.038427723737 + -0.024772513569*_Complex_I, -0.035206635151 + -0.007553598958*_Complex_I, 0.005557463302 + 0.057023731153*_Complex_I, -0.026365483732 + 0.001677431571*_Complex_I, -0.027214665101 + 0.003259544495*_Complex_I, 0.006634141929 + -0.021760848241*_Complex_I, 0.046788459295 + -0.032219612690*_Complex_I, 0.049439176247 + 0.058001544517*_Complex_I, 0.045244742233 + -0.058913353130*_Complex_I, 0.024261567778 + 0.012176684918*_Complex_I, -0.050667381589 + 0.023733558523*_Complex_I, 0.045349821935 + 0.040847998957*_Complex_I, 0.026718102874 + -0.059402465947*_Complex_I, -0.038454788567 + -0.000221349180*_Complex_I, -0.000891207880 + -0.009195003923*_Complex_I, 0.012516609339 + 0.056222305600*_Complex_I, -0.035084845543 + -0.052719626538*_Complex_I, -0.021230335164 + -0.038700055773*_Complex_I, -0.042702491469 + -0.012596339115*_Complex_I, 0.001037928882 + -0.021134005956*_Complex_I, 0.021394370180 + -0.031996808591*_Complex_I, -0.018110589131 + -0.004361916553*_Complex_I, -0.042616962178 + -0.045478200889*_Complex_I, 0.015593771645 + 0.075086774578*_Complex_I, 0.027412734674 + 0.021799498978*_Complex_I, -0.092513052262 + 0.111578027869*_Complex_I, 0.023261460083 + -0.018008166583*_Complex_I, -0.005433496503 + 0.062765792378*_Complex_I, 0.077096470007 + -0.046336297254*_Complex_I, 0.013100162132 + 0.106964173517*_Complex_I, -0.057225839702 + 0.011100170701*_Complex_I, -0.011950150953 + 0.042976543657*_Complex_I, 0.009438239329 + -0.043586074813*_Complex_I, -0.035007068103 + 0.014223415436*_Complex_I, -0.044707188095 + -0.007302556287*_Complex_I, -0.006824766721 + 0.022952180881*_Complex_I, 0.017261515635 + -0.031023982394*_Complex_I, 0.009883747796 + 0.006683863273*_Complex_I, -0.030856485749 + -0.017782855219*_Complex_I, -0.009108501465 + 0.015353290050*_Complex_I, -0.038083572506 + 0.029801645641*_Complex_I, 0.028040003683 + -0.001971697544*_Complex_I, 0.034858486128 + -0.004199899994*_Complex_I, -0.047963189034 + -0.015741737165*_Complex_I, -0.009310592393 + 0.022863663510*_Complex_I, -0.082864799372 + 0.027670042319*_Complex_I, 0.018363359405 + 0.035364489440*_Complex_I, 0.108637353728 + -0.051587108396*_Complex_I, -0.037281254062 + 0.067821136010*_Complex_I, -0.061231969683 + 0.036908299475*_Complex_I, -0.020972301615 + 0.096608850141*_Complex_I, -0.079111323581 + 0.024466271096*_Complex_I, 0.045843637768 + -0.077335246433*_Complex_I, -0.011031555894 + 0.001143494701*_Complex_I, -0.050696885867 + -0.000991623122*_Complex_I, -0.025631881174 + -0.020905755095*_Complex_I, 0.042787270331 + -0.022375533820*_Complex_I, 0.040540034730 + -0.032482851465*_Complex_I, 0.045207009532 + -0.015041815894*_Complex_I, -0.041989439384 + 0.052327580958*_Complex_I, -0.060932225937 + -0.002610819103*_Complex_I, 0.056802692214 + 0.015432577360*_Complex_I, 0.066574027053 + -0.021238051145*_Complex_I, -0.000873772321 + 0.003555393272*_Complex_I, -0.047364452139 + 0.039519457621*_Complex_I, -0.075184690098 + 0.032775776752*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_crcf_data_h4x256.c000066400000000000000000000646251474751757600245750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_crcf_data_h4x256.c: autotest fftfilt data // #include float fftfilt_crcf_data_h4x256_h[] = { 0.155624401569, 0.118511450291, -0.168462336063, 0.090250796080}; float complex fftfilt_crcf_data_h4x256_x[] = { 0.038939061761 + 0.066255682707*_Complex_I, 0.119283056259 + 0.056196963787*_Complex_I, -0.040920588374 + -0.079775565863*_Complex_I, -0.227900600433 + -0.102529621124*_Complex_I, -0.174213981628 + -0.108522331715*_Complex_I, 0.153431594372 + -0.030162647367*_Complex_I, 0.014127536118 + 0.246407699585*_Complex_I, -0.018383954465 + 0.021154025197*_Complex_I, -0.191331315041 + -0.127723705769*_Complex_I, 0.010609115660 + 0.052530884743*_Complex_I, -0.112432408333 + 0.010107874870*_Complex_I, 0.025136622787 + -0.032320749760*_Complex_I, 0.018991956115 + 0.133092260361*_Complex_I, -0.039405971766 + -0.013498529792*_Complex_I, -0.019806520641 + -0.002817103267*_Complex_I, -0.078604698181 + 0.026840734482*_Complex_I, 0.028549847007 + -0.017006455362*_Complex_I, 0.020842596889 + -0.121898579597*_Complex_I, -0.055000007153 + -0.101676058769*_Complex_I, 0.036740297079 + -0.151041173935*_Complex_I, 0.067903089523 + -0.193994557858*_Complex_I, 0.197223436832 + 0.051035022736*_Complex_I, -0.015651342273 + 0.007457277179*_Complex_I, -0.125625634193 + 0.145215332508*_Complex_I, 0.255927467346 + -0.039666593075*_Complex_I, -0.014654898643 + -0.154769206047*_Complex_I, -0.142057240009 + 0.149415183067*_Complex_I, -0.015665143728 + -0.008279455453*_Complex_I, -0.024408347905 + -0.026021143794*_Complex_I, -0.062624055147 + -0.200754070282*_Complex_I, -0.056015121937 + 0.040550091863*_Complex_I, 0.070212632418 + 0.062178546190*_Complex_I, -0.109208559990 + -0.118423628807*_Complex_I, 0.086101102829 + 0.087447303534*_Complex_I, 0.121767687798 + 0.103217923641*_Complex_I, -0.083848309517 + -0.039586529136*_Complex_I, 0.051707124710 + 0.150204086304*_Complex_I, -0.014533403516 + -0.031855377555*_Complex_I, 0.009939355403 + 0.151125979424*_Complex_I, -0.118441712856 + 0.029392868280*_Complex_I, 0.068562531471 + 0.169217157364*_Complex_I, -0.035535854101 + -0.091208106279*_Complex_I, 0.110526537895 + 0.046102252603*_Complex_I, -0.004789924249 + 0.014031916857*_Complex_I, 0.207642221451 + 0.005212478340*_Complex_I, -0.079558753967 + 0.078763872385*_Complex_I, 0.019427961111 + 0.118139207363*_Complex_I, 0.027059462667 + 0.004347201437*_Complex_I, -0.150222861767 + -0.019229063392*_Complex_I, 0.060692095757 + 0.119515848160*_Complex_I, -0.025792115927 + -0.000083122792*_Complex_I, 0.113421833515 + 0.125912785530*_Complex_I, -0.001560413372 + -0.150379800797*_Complex_I, 0.152954483032 + -0.063023918867*_Complex_I, -0.028765177727 + -0.036037924886*_Complex_I, -0.061254453659 + 0.052871614695*_Complex_I, 0.022947111726 + 0.146198511124*_Complex_I, -0.103656053543 + 0.085682183504*_Complex_I, 0.153891849518 + -0.088169473410*_Complex_I, -0.321221590042 + 0.123748040199*_Complex_I, -0.049486947060 + 0.162590062618*_Complex_I, 0.006993473321 + 0.179711341858*_Complex_I, 0.009347584099 + 0.202764987946*_Complex_I, 0.095177561045 + 0.070498406887*_Complex_I, -0.122608697414 + 0.114908039570*_Complex_I, 0.143189716339 + -0.046278029680*_Complex_I, 0.037571176887 + 0.071948003769*_Complex_I, -0.095956790447 + -0.205198740959*_Complex_I, 0.072236007452 + -0.040830844641*_Complex_I, 0.122828471661 + -0.117571306229*_Complex_I, 0.157875216007 + -0.039508357644*_Complex_I, -0.007820869237 + 0.116631805897*_Complex_I, -0.002049682848 + -0.058560395241*_Complex_I, -0.101921010017 + -0.107374680042*_Complex_I, -0.195360040665 + -0.201392173767*_Complex_I, 0.173241472244 + -0.001343925763*_Complex_I, 0.028210636973 + -0.149001765251*_Complex_I, -0.095708668232 + 0.070712405443*_Complex_I, 0.155656027794 + -0.047673809528*_Complex_I, -0.113691759109 + -0.093889063597*_Complex_I, 0.001799738780 + -0.111104428768*_Complex_I, 0.115965354443 + -0.018809084594*_Complex_I, -0.019960752130 + -0.186925411224*_Complex_I, 0.149933063984 + 0.044130250812*_Complex_I, 0.010008703917 + -0.031899172068*_Complex_I, 0.085326123238 + -0.005660134554*_Complex_I, -0.209100413322 + 0.130333411694*_Complex_I, -0.102446043491 + -0.034337127209*_Complex_I, -0.010648646951 + 0.011874027550*_Complex_I, 0.037817972898 + -0.044123852253*_Complex_I, 0.101257121563 + 0.028343737125*_Complex_I, 0.007420848310 + 0.154019880295*_Complex_I, 0.141882646084 + 0.096156585217*_Complex_I, -0.017362400889 + 0.036749580503*_Complex_I, 0.023864392936 + -0.022486045957*_Complex_I, 0.149045646191 + -0.053199940920*_Complex_I, 0.084901583195 + 0.083841896057*_Complex_I, -0.027361977100 + -0.115613818169*_Complex_I, -0.133944833279 + 0.016144460440*_Complex_I, 0.111774182320 + -0.136482322216*_Complex_I, -0.044260403514 + 0.111417186260*_Complex_I, 0.001404425409 + -0.104211735725*_Complex_I, 0.095043230057 + 0.095729255676*_Complex_I, -0.143477213383 + -0.080443674326*_Complex_I, 0.184766137600 + 0.017212320864*_Complex_I, -0.045734372735 + -0.227365469933*_Complex_I, 0.031908345222 + 0.080422180891*_Complex_I, 0.089475703239 + 0.117917668819*_Complex_I, -0.143735373020 + 0.151164078712*_Complex_I, -0.158408689499 + -0.105965197086*_Complex_I, 0.041039618850 + -0.014203602076*_Complex_I, -0.084943604469 + -0.084828513861*_Complex_I, -0.032031357288 + -0.010720796138*_Complex_I, -0.019809050858 + -0.082033938169*_Complex_I, -0.297199916840 + 0.071534729004*_Complex_I, 0.041559013724 + -0.176234781742*_Complex_I, 0.077450340986 + 0.043274927139*_Complex_I, 0.188104069233 + 0.034578007460*_Complex_I, 0.091451799870 + -0.117644202709*_Complex_I, -0.116885960102 + 0.047494077682*_Complex_I, 0.021910847723 + -0.104368901253*_Complex_I, -0.170243906975 + -0.038744941354*_Complex_I, -0.006665949523 + -0.076677244902*_Complex_I, -0.123132240772 + -0.028003439307*_Complex_I, -0.008512797952 + 0.119553911686*_Complex_I, 0.007796970755 + -0.034775868058*_Complex_I, -0.020194862783 + 0.033565041423*_Complex_I, 0.000060333178 + 0.190958213806*_Complex_I, -0.126177227497 + -0.069941896200*_Complex_I, -0.031391653419 + -0.108642828465*_Complex_I, 0.049086883664 + 0.125198578835*_Complex_I, -0.098606723547 + 0.157826316357*_Complex_I, -0.037816497684 + -0.075405150652*_Complex_I, 0.154469418526 + -0.071843087673*_Complex_I, -0.180931842327 + 0.056550979614*_Complex_I, 0.049642735720 + 0.229578256607*_Complex_I, -0.013776327670 + 0.000968252402*_Complex_I, -0.131162738800 + 0.062030094862*_Complex_I, 0.115592253208 + -0.122473180294*_Complex_I, -0.143930578232 + 0.208317732811*_Complex_I, 0.025780442357 + 0.038679277897*_Complex_I, -0.186121022701 + 0.000732171116*_Complex_I, 0.001518380083 + -0.024754013121*_Complex_I, -0.026928266883 + -0.122094595432*_Complex_I, 0.102070283890 + 0.129774129391*_Complex_I, -0.046998295188 + 0.174012136459*_Complex_I, 0.114306473732 + -0.074029159546*_Complex_I, -0.041995987296 + 0.163119518757*_Complex_I, 0.167517042160 + -0.009892838448*_Complex_I, 0.114438354969 + 0.017925891280*_Complex_I, -0.095674896240 + 0.076540869474*_Complex_I, -0.062672561407 + -0.038445192575*_Complex_I, -0.217370772362 + -0.030016162992*_Complex_I, 0.005625271797 + -0.027812755108*_Complex_I, -0.152692675591 + -0.136305415630*_Complex_I, 0.084204858541 + 0.203144884109*_Complex_I, -0.056856244802 + -0.032040473819*_Complex_I, -0.015420150757 + 0.110550451279*_Complex_I, 0.011531084776 + 0.136303079128*_Complex_I, 0.059582346678 + -0.063924384117*_Complex_I, -0.066680252552 + 0.154493486881*_Complex_I, 0.034608376026 + 0.051702314615*_Complex_I, 0.113737416267 + 0.039248380065*_Complex_I, 0.158740794659 + 0.019757434726*_Complex_I, -0.039499655366 + -0.000118957297*_Complex_I, -0.054218810797 + 0.061152768135*_Complex_I, 0.020386171341 + -0.226112961769*_Complex_I, 0.027872058749 + -0.079996037483*_Complex_I, -0.139904499054 + 0.015143483877*_Complex_I, 0.013777624071 + -0.018682165444*_Complex_I, 0.005936894938 + -0.001314791571*_Complex_I, 0.157291007042 + -0.008614261448*_Complex_I, -0.079033893347 + -0.041999083757*_Complex_I, 0.084690928459 + 0.051340937614*_Complex_I, 0.001056097262 + 0.008219049126*_Complex_I, -0.028290018439 + 0.131245112419*_Complex_I, 0.102844524384 + -0.111723649502*_Complex_I, 0.123529279232 + -0.021718944609*_Complex_I, -0.029516366124 + -0.034146314859*_Complex_I, 0.048669779301 + 0.046512207389*_Complex_I, 0.038022220135 + 0.079673200846*_Complex_I, 0.175985097885 + 0.215863847733*_Complex_I, 0.106522679329 + 0.155265355110*_Complex_I, 0.033522182703 + 0.035048177838*_Complex_I, 0.014340730011 + -0.097587269545*_Complex_I, -0.051011729240 + 0.074478018284*_Complex_I, 0.048653256893 + 0.180682408810*_Complex_I, -0.143753635883 + -0.177901697159*_Complex_I, 0.077370518446 + -0.033802193403*_Complex_I, 0.080779671669 + 0.048105204105*_Complex_I, 0.062754058838 + 0.065103608370*_Complex_I, 0.195216703415 + -0.269327521324*_Complex_I, 0.035685497522 + 0.128597819805*_Complex_I, -0.152576267719 + 0.002838765644*_Complex_I, 0.037064149976 + 0.005790404975*_Complex_I, 0.028551298380 + -0.260332655907*_Complex_I, -0.112396037579 + -0.135177958012*_Complex_I, -0.015914693475 + 0.063825702667*_Complex_I, 0.158389151096 + 0.117301619053*_Complex_I, -0.063320201635 + 0.147249364853*_Complex_I, 0.257527685165 + -0.037165626884*_Complex_I, 0.047737368941 + -0.188134491444*_Complex_I, 0.014590293169 + -0.009723882377*_Complex_I, 0.026365819573 + -0.025334075093*_Complex_I, -0.102777397633 + 0.233691811562*_Complex_I, 0.072789901495 + -0.054794228077*_Complex_I, -0.129656755924 + -0.084271728992*_Complex_I, -0.022544041276 + -0.037263685465*_Complex_I, 0.004222166538 + -0.032020455599*_Complex_I, -0.040505915880 + 0.015989097953*_Complex_I, 0.076600146294 + 0.028494662046*_Complex_I, 0.165050017834 + 0.060545289516*_Complex_I, -0.201356935501 + -0.007056738436*_Complex_I, -0.144541025162 + -0.020850527287*_Complex_I, -0.060554254055 + -0.035383135080*_Complex_I, -0.083671200275 + 0.002356898040*_Complex_I, 0.009340242296 + -0.031346979737*_Complex_I, 0.099454361200 + -0.127831709385*_Complex_I, -0.167506957054 + 0.087425726652*_Complex_I, -0.039634212852 + -0.083207929134*_Complex_I, -0.225357127190 + 0.072750198841*_Complex_I, -0.006095945090 + -0.048631900549*_Complex_I, -0.011678160727 + -0.136811399460*_Complex_I, 0.182721781731 + -0.034160619974*_Complex_I, -0.137553799152 + 0.036647570133*_Complex_I, -0.020456752181 + -0.038014954329*_Complex_I, 0.128560674191 + -0.011797984689*_Complex_I, 0.093237119913 + 0.134914875031*_Complex_I, 0.109499740601 + 0.181737196445*_Complex_I, 0.177813911438 + 0.024316579103*_Complex_I, 0.149165189266 + -0.090540468693*_Complex_I, 0.132123124599 + -0.023848700523*_Complex_I, -0.173898208141 + 0.013859193027*_Complex_I, -0.238600111008 + 0.217159080505*_Complex_I, -0.000013622420 + -0.006076892465*_Complex_I, -0.008374422789 + -0.236851501465*_Complex_I, -0.283055114746 + 0.141181695461*_Complex_I, -0.089649707079 + 0.020758484304*_Complex_I, 0.095366454124 + 0.158369851112*_Complex_I, 0.015813191235 + -0.056471478939*_Complex_I, 0.127879250050 + 0.081945985556*_Complex_I, 0.035356411338 + -0.067337626219*_Complex_I, -0.245302104950 + -0.055383253098*_Complex_I, -0.136766076088 + -0.014186948538*_Complex_I, -0.141382408142 + -0.000181592884*_Complex_I, -0.047739619017 + -0.041759270430*_Complex_I, -0.023178872466 + 0.034544199705*_Complex_I, 0.061150830984 + 0.075226747990*_Complex_I, -0.058196645975 + 0.033970293403*_Complex_I, -0.145030462742 + 0.039564606547*_Complex_I, -0.199735391140 + 0.212692308426*_Complex_I, -0.083191102743 + 0.161805856228*_Complex_I, 0.098720330000 + -0.211091256142*_Complex_I, 0.051044720411 + -0.086010062695*_Complex_I, -0.118900668621 + -0.002717586420*_Complex_I, -0.069598269463 + -0.110835444927*_Complex_I}; float complex fftfilt_crcf_data_h4x256_y[] = { 0.006059868184 + 0.010311000972*_Complex_I, 0.023178078930 + 0.016597675907*_Complex_I, 0.001208400606 + -0.016916628103*_Complex_I, -0.056896873822 + -0.028897872629*_Complex_I, -0.036461808619 + -0.010528658122*_Complex_I, 0.037930900295 + -0.007482611703*_Complex_I, 0.029162273827 + 0.043800977293*_Complex_I, -0.042757112462 + 0.027781259560*_Complex_I, -0.020487164712 + -0.061602550704*_Complex_I, -0.016651889059 + 0.011713200441*_Complex_I, 0.014333029188 + 0.031224344773*_Complex_I, -0.028467695798 + -0.024208640112*_Complex_I, 0.025832696718 + 0.019920182397*_Complex_I, -0.018263455064 + 0.020029328938*_Complex_I, -0.008683265862 + -0.027376146840*_Complex_I, -0.006227647384 + 0.018128890559*_Complex_I, -0.005092271511 + -0.000209362331*_Complex_I, 0.018081477268 + -0.025761751836*_Complex_I, -0.017992967322 + -0.024982308404*_Complex_I, -0.001734990008 + -0.016554996144*_Complex_I, 0.026068014213 + -0.041963253019*_Complex_I, 0.027586922248 + 0.001220122229*_Complex_I, 0.012814232728 + 0.026257959070*_Complex_I, -0.048501690424 + -0.002622820479*_Complex_I, 0.045376716710 + 0.014386270946*_Complex_I, 0.047800317199 + -0.052577099490*_Complex_I, -0.078296298763 + 0.024698851676*_Complex_I, 0.006293167971 + 0.038911765139*_Complex_I, 0.016953644799 + -0.044169610042*_Complex_I, -0.022820292108 + -0.019446419914*_Complex_I, -0.013440891814 + -0.013844717016*_Complex_I, 0.012635287358 + 0.045953219949*_Complex_I, -0.004889948433 + -0.036010114541*_Complex_I, -0.016426625652 + -0.007240686790*_Complex_I, 0.053888265216 + 0.051988318810*_Complex_I, -0.022978930110 + -0.019347527890*_Complex_I, -0.014632670495 + 0.009187820283*_Complex_I, 0.028981046972 + 0.028827768992*_Complex_I, -0.016453648195 + -0.009132783918*_Complex_I, -0.010139552985 + 0.041406876217*_Complex_I, -0.006352754502 + 0.001483701581*_Complex_I, 0.023445201384 + 0.014547612472*_Complex_I, -0.009250442382 + -0.029488557351*_Complex_I, 0.024527507249 + 0.038284467295*_Complex_I, 0.009919837691 + -0.013523965732*_Complex_I, 0.023008727191 + 0.014672234378*_Complex_I, -0.041817346662 + 0.028108049584*_Complex_I, 0.038656077865 + 0.001879063803*_Complex_I, -0.030624607394 + -0.015270823004*_Complex_I, -0.011163069470 + 0.026250535961*_Complex_I, 0.030927857953 + 0.017782771893*_Complex_I, -0.009187521194 + -0.002284106361*_Complex_I, 0.023021457646 + 0.002319743817*_Complex_I, 0.002183457008 + -0.048848851834*_Complex_I, 0.024149575692 + 0.023619625148*_Complex_I, -0.038849588696 + 0.001002466517*_Complex_I, 0.014961889285 + 0.029401021704*_Complex_I, -0.005688927643 + 0.018501108984*_Complex_I, 0.002270910497 + -0.023424239102*_Complex_I, -0.012218835419 + 0.007569433759*_Complex_I, -0.081049834844 + 0.062554661642*_Complex_I, 0.063226186616 + 0.018432005055*_Complex_I, -0.018370298666 + 0.036631089037*_Complex_I, 0.010275373508 + 0.019400535292*_Complex_I, -0.008744823687 + 0.008298191463*_Complex_I, -0.007436928001 + 0.012839303011*_Complex_I, 0.052061411111 + -0.007282750818*_Complex_I, -0.045668210091 + -0.005240621957*_Complex_I, 0.006463364693 + -0.046969833961*_Complex_I, 0.047231835108 + 0.017925737087*_Complex_I, 0.018296593037 + -0.031722900784*_Complex_I, 0.003320288626 + 0.029589882902*_Complex_I, -0.016756503569 + 0.000753544241*_Complex_I, -0.000538421251 + -0.046863924905*_Complex_I, -0.042842141445 + -0.023675331266*_Complex_I, 0.020793064630 + -0.011272959088*_Complex_I, 0.048633718156 + 0.000888764564*_Complex_I, -0.058367383027 + -0.024603242648*_Complex_I, 0.023764054076 + 0.025940916726*_Complex_I, 0.019423147902 + -0.045621226585*_Complex_I, -0.048053653552 + -0.014004397126*_Complex_I, 0.051461188295 + -0.004580127799*_Complex_I, 0.000072882267 + -0.021075898269*_Complex_I, 0.001594299020 + -0.022143698521*_Complex_I, 0.033154983906 + 0.030058007048*_Complex_I, -0.012594575098 + -0.028965724511*_Complex_I, -0.010583515338 + 0.028968867756*_Complex_I, -0.054194842002 + 0.008176900584*_Complex_I, 0.029128076149 + -0.024688556963*_Complex_I, 0.003010233851 + 0.012087666948*_Complex_I, 0.012788000724 + -0.005917484080*_Complex_I, 0.005823040482 + 0.035833156760*_Complex_I, 0.009314948304 + 0.024460365458*_Complex_I, 0.022001107298 + -0.006273716153*_Complex_I, -0.021575905979 + -0.001442477527*_Complex_I, 0.041753275685 + -0.008456774704*_Complex_I, 0.025289151882 + 0.013847773473*_Complex_I, -0.017151178833 + -0.001123303791*_Complex_I, -0.024939022931 + -0.030114627959*_Complex_I, 0.013792691837 + 0.007716695455*_Complex_I, 0.026453740944 + -0.011989457656*_Complex_I, -0.035945169446 + 0.021435504561*_Complex_I, 0.032501406199 + -0.028539713517*_Complex_I, -0.015295973874 + 0.026437256451*_Complex_I, -0.004134027099 + -0.032386805528*_Complex_I, 0.047527752256 + -0.011152387256*_Complex_I, -0.044529397603 + -0.024589491243*_Complex_I, 0.042085917317 + 0.067737759803*_Complex_I, -0.021267753978 + 0.003431390108*_Complex_I, -0.053880077452 + -0.011182616288*_Complex_I, 0.019902772754 + -0.029591806606*_Complex_I, 0.005358033182 + 0.016609146898*_Complex_I, -0.036261790964 + -0.018892239095*_Complex_I, 0.011134802022 + -0.001028496419*_Complex_I, -0.050869309200 + -0.004439202137*_Complex_I, -0.028307773042 + -0.006096679489*_Complex_I, 0.065257591616 + -0.033605740720*_Complex_I, 0.004628677817 + 0.046654745363*_Complex_I, 0.027227886379 + -0.037405943501*_Complex_I, -0.032050718154 + -0.008470442952*_Complex_I, -0.008872103935 + 0.012325554139*_Complex_I, 0.004047059830 + -0.037017014389*_Complex_I, -0.035453440267 + 0.005344037694*_Complex_I, 0.010704785090 + -0.016337463075*_Complex_I, -0.030159066222 + 0.024707243754*_Complex_I, 0.020346072551 + 0.006553876216*_Complex_I, -0.011897480047 + -0.021565463012*_Complex_I, -0.004465715862 + 0.050343859162*_Complex_I, -0.015523348770 + 0.002953074058*_Complex_I, -0.021671519813 + -0.054336385799*_Complex_I, 0.025180402141 + 0.035625240780*_Complex_I, -0.015627538530 + 0.051389004055*_Complex_I, -0.028673608441 + -0.023927002620*_Complex_I, 0.040599172161 + -0.035405429827*_Complex_I, -0.012379694629 + 0.027233362371*_Complex_I, -0.043152122115 + 0.047727396912*_Complex_I, 0.048160488676 + 0.011347729858*_Complex_I, -0.046736949340 + -0.023803373100*_Complex_I, 0.009245777592 + 0.008847967472*_Complex_I, 0.012152552309 + 0.007542499150*_Complex_I, -0.044355838252 + 0.056937859612*_Complex_I, 0.008769479148 + -0.041449112921*_Complex_I, -0.039154058148 + 0.008519281894*_Complex_I, 0.029670337728 + -0.018567039979*_Complex_I, -0.004360041436 + 0.009962611552*_Complex_I, 0.009455849568 + 0.060794526263*_Complex_I, -0.007406255544 + -0.023779500426*_Complex_I, 0.024140392564 + -0.000990198094*_Complex_I, -0.002405235069 + 0.045967822672*_Complex_I, 0.055053080500 + -0.032543394298*_Complex_I, -0.033337576595 + 0.030424287480*_Complex_I, -0.025251956775 + -0.000824714706*_Complex_I, -0.014809843352 + -0.020503870649*_Complex_I, -0.022962265375 + 0.005498838976*_Complex_I, 0.007866492401 + -0.022921694981*_Complex_I, -0.025557031391 + 0.017436967625*_Complex_I, 0.027361670922 + 0.039540920716*_Complex_I, -0.037103850469 + -0.033116749204*_Complex_I, 0.017144745074 + 0.058045180011*_Complex_I, 0.008105425889 + -0.015309983982*_Complex_I, -0.006650118444 + 0.003482516084*_Complex_I, -0.011513157356 + 0.049425701442*_Complex_I, 0.038412271512 + -0.019560238313*_Complex_I, 0.026334973579 + 0.012959388879*_Complex_I, -0.003371545788 + 0.000377270846*_Complex_I, -0.029595884162 + 0.009716579081*_Complex_I, 0.017727723120 + -0.026138227085*_Complex_I, 0.012322519379 + -0.049558984658*_Complex_I, -0.026796988722 + 0.036486852957*_Complex_I, -0.017291674519 + -0.008043280034*_Complex_I, 0.028640846159 + -0.012189476909*_Complex_I, 0.010234405721 + 0.003017545570*_Complex_I, 0.006584481357 + -0.009021558338*_Complex_I, -0.022148247256 + 0.004345047986*_Complex_I, 0.037711072166 + 0.013661393387*_Complex_I, -0.025677561015 + 0.008959528481*_Complex_I, 0.020117937550 + 0.001416082797*_Complex_I, 0.036273540108 + -0.037988612000*_Complex_I, -0.009832458294 + 0.022778259426*_Complex_I, -0.007452052832 + -0.003232619018*_Complex_I, 0.027806123164 + 0.021703539285*_Complex_I, 0.021030743738 + 0.032118581494*_Complex_I, 0.035420951705 + 0.040521245842*_Complex_I, -0.008374298228 + -0.005319284142*_Complex_I, 0.004142265794 + -0.017707830367*_Complex_I, -0.002272597722 + 0.008133912171*_Complex_I, 0.002135690771 + 0.056547995055*_Complex_I, -0.006717788148 + -0.027626980558*_Complex_I, -0.017795801727 + -0.050060314493*_Complex_I, 0.050348648898 + 0.049756863364*_Complex_I, -0.006668519461 + 0.005471354270*_Complex_I, 0.031191975857 + -0.045353001209*_Complex_I, 0.025407683165 + -0.018531409391*_Complex_I, -0.046738508420 + 0.066929291225*_Complex_I, -0.000707147993 + -0.044733357800*_Complex_I, 0.037759803940 + -0.028700053973*_Complex_I, -0.034121953222 + -0.052608653720*_Complex_I, -0.017261681450 + 0.038291536957*_Complex_I, 0.044274419912 + 0.025096236007*_Complex_I, 0.001453954093 + 0.013865033987*_Complex_I, 0.004454502807 + -0.002333726953*_Complex_I, 0.062910894997 + -0.047902277474*_Complex_I, -0.041170383580 + -0.004258984080*_Complex_I, 0.021032411606 + 0.023244356831*_Complex_I, -0.011019598807 + 0.018024590663*_Complex_I, -0.003977275574 + 0.022558085902*_Complex_I, 0.008142338448 + -0.061263169770*_Complex_I, -0.040412311920 + 0.014535332123*_Complex_I, 0.026396971660 + -0.000147948023*_Complex_I, -0.013707137421 + -0.002634559956*_Complex_I, 0.004374543380 + 0.008360519390*_Complex_I, 0.041968579789 + 0.007215835772*_Complex_I, -0.028335666347 + 0.002719860858*_Complex_I, -0.067248700384 + -0.011709090114*_Complex_I, 0.022263469171 + -0.001324450231*_Complex_I, -0.014020557910 + -0.000950863534*_Complex_I, -0.011306257165 + -0.000520086651*_Complex_I, 0.025214827331 + -0.027199113964*_Complex_I, -0.023406560837 + 0.003949552479*_Complex_I, -0.041930892788 + 0.016117503991*_Complex_I, -0.002573727540 + -0.024804241879*_Complex_I, -0.036096841921 + 0.022961064703*_Complex_I, 0.031847322765 + -0.046819879524*_Complex_I, 0.007740249190 + -0.006771536473*_Complex_I, 0.001665062016 + 0.020313331769*_Complex_I, -0.051320971549 + -0.008165457704*_Complex_I, 0.057246239219 + -0.015598020100*_Complex_I, 0.020777735323 + 0.029309410804*_Complex_I, 0.004586628235 + 0.042828336116*_Complex_I, 0.036544916785 + 0.001529339266*_Complex_I, 0.034254870037 + -0.029648210991*_Complex_I, 0.018166856966 + -0.002136023066*_Complex_I, -0.020485570645 + 0.016777734021*_Complex_I, -0.066536421479 + 0.031283983440*_Complex_I, 0.012940550380 + 0.020303008580*_Complex_I, 0.023195801416 + -0.072912377311*_Complex_I, -0.066574302932 + 0.014524209319*_Complex_I, -0.046087408784 + 0.059314287035*_Complex_I, 0.051145158090 + -0.018053503400*_Complex_I, 0.003319584852 + 0.019225038270*_Complex_I, -0.002381437087 + -0.018745607253*_Complex_I, 0.026600447010 + 0.023038482211*_Complex_I, -0.054100537802 + -0.035500673450*_Complex_I, -0.044770266493 + 0.009968159227*_Complex_I, 0.006304211224 + 0.001543141693*_Complex_I, -0.023283661455 + -0.009128698496*_Complex_I, 0.002209473868 + -0.000822823133*_Complex_I, 0.002052052541 + 0.022819476191*_Complex_I, -0.002213516155 + 0.004613633607*_Complex_I, -0.041860771422 + 0.000627854778*_Complex_I, -0.032948617085 + 0.038855531028*_Complex_I, -0.017437619533 + 0.046788113461*_Complex_I, 0.026062969909 + -0.045935009629*_Complex_I, 0.015631583001 + -0.046464537818*_Complex_I, -0.036593182213 + 0.039547933437*_Complex_I, -0.024611804187 + -0.022132462723*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_crcf_data_h7x256.c000066400000000000000000000647211474751757600245750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_crcf_data_h7x256.c: autotest fftfilt data // #include float fftfilt_crcf_data_h7x256_h[] = { -0.040934386849, 0.135112583637, 0.002939097211, 0.060173767805, -0.080519974232, 0.155969536304, 0.169374001026}; float complex fftfilt_crcf_data_h7x256_x[] = { 0.040651902556 + 0.099964648485*_Complex_I, -0.099666911364 + 0.065967345238*_Complex_I, 0.160125207901 + 0.220931744576*_Complex_I, 0.040764364600 + -0.044899615645*_Complex_I, -0.134997522831 + 0.246626877785*_Complex_I, 0.081977373362 + -0.136002039909*_Complex_I, 0.110743105412 + 0.054145228863*_Complex_I, 0.044197705388 + -0.067522579432*_Complex_I, -0.109018945694 + -0.106943678856*_Complex_I, 0.006750953943 + -0.091825586557*_Complex_I, 0.074130672216 + 0.058626526594*_Complex_I, -0.109099924564 + -0.185111522675*_Complex_I, 0.050862681866 + -0.099265706539*_Complex_I, 0.139591431618 + -0.009831842780*_Complex_I, 0.098799163103 + 0.068593806028*_Complex_I, -0.134761643410 + -0.071746927500*_Complex_I, 0.040908864141 + -0.077851450443*_Complex_I, 0.009703576565 + 0.085823422670*_Complex_I, -0.088899284601 + -0.024389025569*_Complex_I, 0.131887495518 + 0.003364508972*_Complex_I, -0.016711652279 + -0.064561820030*_Complex_I, -0.028739383817 + 0.119105470181*_Complex_I, -0.037841024995 + 0.130922996998*_Complex_I, -0.036886861920 + 0.049854472280*_Complex_I, 0.195188224316 + 0.196104526520*_Complex_I, 0.090881633759 + -0.049584397674*_Complex_I, 0.095823466778 + -0.010633364320*_Complex_I, -0.026297450066 + 0.112273478508*_Complex_I, 0.064357328415 + -0.151258838177*_Complex_I, 0.083770233393 + -0.010217200220*_Complex_I, -0.085294854641 + -0.001434229873*_Complex_I, -0.024482454360 + -0.028102940321*_Complex_I, 0.007926462591 + 0.049879977107*_Complex_I, -0.019109925628 + -0.122103679180*_Complex_I, 0.065177565813 + -0.099032187462*_Complex_I, -0.029712364078 + 0.058807843924*_Complex_I, 0.014222274721 + -0.111795830727*_Complex_I, -0.013231332600 + -0.097048926353*_Complex_I, -0.042737719417 + -0.082051867247*_Complex_I, -0.000470168283 + 0.065859609842*_Complex_I, -0.012786905468 + 0.140206325054*_Complex_I, 0.101196074486 + 0.024098466337*_Complex_I, 0.029521119595 + 0.073089057207*_Complex_I, 0.036042726040 + -0.055842936039*_Complex_I, 0.006287913024 + 0.163206160069*_Complex_I, 0.162955164909 + -0.168543994427*_Complex_I, 0.025857266784 + 0.046382865310*_Complex_I, 0.105994081497 + -0.114217007160*_Complex_I, 0.166455543041 + -0.042309248447*_Complex_I, -0.055975890160 + -0.082556062937*_Complex_I, 0.100109672546 + 0.042784979939*_Complex_I, -0.133630573750 + 0.026788604259*_Complex_I, -0.124175155163 + 0.100820934772*_Complex_I, -0.018217980862 + 0.020558734238*_Complex_I, 0.020028033853 + -0.023399496078*_Complex_I, 0.041591683030 + 0.234618091583*_Complex_I, 0.114061284065 + 0.076200354099*_Complex_I, -0.044339376688 + 0.155996751785*_Complex_I, -0.137206864357 + 0.152004182339*_Complex_I, -0.125251030922 + -0.189576375484*_Complex_I, -0.096886903048 + 0.100963902473*_Complex_I, 0.045814022422 + -0.153462719917*_Complex_I, 0.018112409115 + 0.033487904072*_Complex_I, -0.094020819664 + -0.066115939617*_Complex_I, -0.183385014534 + -0.106691968441*_Complex_I, 0.008264037967 + -0.041415163875*_Complex_I, -0.061662602425 + -0.034961605072*_Complex_I, 0.125767064095 + 0.063457810879*_Complex_I, 0.017231588066 + -0.019841212034*_Complex_I, 0.129437744617 + -0.025927716494*_Complex_I, -0.060927426815 + 0.096969240904*_Complex_I, -0.015513072908 + 0.036051341891*_Complex_I, -0.111995267868 + 0.039143866301*_Complex_I, -0.073930400610 + 0.029889217019*_Complex_I, -0.175347507000 + 0.054301995039*_Complex_I, 0.052788543701 + 0.158147716522*_Complex_I, 0.015504409373 + 0.139973330498*_Complex_I, -0.031992411613 + -0.023225200176*_Complex_I, 0.025022339821 + -0.131516921520*_Complex_I, 0.018602204323 + 0.044248020649*_Complex_I, -0.173263669014 + -0.001720846072*_Complex_I, -0.067457306385 + -0.031605756283*_Complex_I, -0.120310330391 + 0.084929233789*_Complex_I, -0.217696404457 + 0.025325486064*_Complex_I, -0.051374822855 + 0.090975987911*_Complex_I, 0.090311527252 + -0.099616253376*_Complex_I, -0.032548421621 + 0.022745725513*_Complex_I, 0.136037707329 + 0.054802763462*_Complex_I, 0.137908041477 + -0.013432055712*_Complex_I, -0.055867260695 + 0.124781918526*_Complex_I, -0.042160874605 + -0.145593822002*_Complex_I, -0.119642519951 + 0.119596099854*_Complex_I, 0.139787364006 + 0.183254098892*_Complex_I, -0.134095728397 + -0.062589937449*_Complex_I, -0.132995867729 + -0.087235867977*_Complex_I, -0.066653913260 + -0.209919691086*_Complex_I, 0.103792250156 + -0.098301386833*_Complex_I, -0.047595480084 + -0.060045230389*_Complex_I, -0.112747573853 + -0.090008395910*_Complex_I, -0.209859752655 + -0.037542074919*_Complex_I, 0.126466608047 + -0.080237525702*_Complex_I, 0.016278307140 + 0.020775717497*_Complex_I, -0.172989428043 + -0.065381830931*_Complex_I, -0.146700656414 + -0.139556598663*_Complex_I, -0.016435039043 + 0.061182838678*_Complex_I, 0.033882060647 + -0.038332518935*_Complex_I, -0.062427771091 + -0.101914501190*_Complex_I, 0.005463292450 + -0.123674154282*_Complex_I, -0.021189038455 + 0.067074733973*_Complex_I, -0.026172134280 + -0.118123090267*_Complex_I, -0.056077581644 + -0.012562614679*_Complex_I, -0.044715997577 + -0.070106768608*_Complex_I, -0.131478667259 + -0.141248393059*_Complex_I, 0.029736247659 + -0.026428756118*_Complex_I, -0.037444081903 + -0.068290340900*_Complex_I, 0.001371991076 + 0.079103118181*_Complex_I, 0.096291542053 + -0.006254652143*_Complex_I, 0.011948133260 + -0.061023879051*_Complex_I, 0.012181475013 + -0.016896595061*_Complex_I, 0.018844342232 + -0.121562480927*_Complex_I, -0.075810509920 + -0.044127961993*_Complex_I, -0.065980046988 + -0.120858967304*_Complex_I, 0.017340828478 + 0.001790644042*_Complex_I, -0.158844494820 + -0.130223393440*_Complex_I, 0.112532448769 + -0.015026393533*_Complex_I, 0.207700538635 + 0.072319573164*_Complex_I, -0.005225989595 + -0.052219772339*_Complex_I, -0.040421813726 + -0.137831771374*_Complex_I, -0.173290038109 + 0.160280382633*_Complex_I, 0.051121586561 + -0.104382145405*_Complex_I, -0.088693290949 + 0.112509071827*_Complex_I, 0.035253915191 + -0.128079938889*_Complex_I, 0.069757878780 + -0.118046510220*_Complex_I, 0.072834354639 + 0.093183624744*_Complex_I, 0.098304384947 + -0.038691642880*_Complex_I, 0.043434667587 + -0.021110518277*_Complex_I, 0.053629237413 + 0.059115654230*_Complex_I, 0.016377405822 + -0.074930238724*_Complex_I, -0.082616806030 + -0.107039499283*_Complex_I, 0.063279908895 + 0.085305947065*_Complex_I, -0.034898114204 + 0.129442250729*_Complex_I, -0.014594067633 + -0.068186104298*_Complex_I, -0.013007178903 + 0.240023064613*_Complex_I, -0.017352801561 + -0.107890737057*_Complex_I, -0.104129159451 + 0.294831180573*_Complex_I, 0.034248217940 + -0.020147347450*_Complex_I, -0.068929183483 + -0.145515120029*_Complex_I, 0.021941699088 + -0.150268518925*_Complex_I, 0.106213212013 + 0.050292271376*_Complex_I, -0.139671075344 + -0.032991030812*_Complex_I, -0.077905637026 + -0.102883970737*_Complex_I, 0.060987144709 + 0.119357335567*_Complex_I, 0.035836818814 + -0.036872345209*_Complex_I, 0.104147458076 + 0.079617452621*_Complex_I, -0.002261339687 + -0.082611733675*_Complex_I, -0.012895359099 + 0.065233492851*_Complex_I, 0.006274250150 + 0.018203525245*_Complex_I, 0.133517765999 + 0.130283260345*_Complex_I, -0.197759151459 + -0.014819876850*_Complex_I, -0.113921284676 + -0.029470649362*_Complex_I, 0.057060551643 + 0.010812921077*_Complex_I, -0.017510490119 + -0.139960432053*_Complex_I, -0.051596522331 + -0.019726826251*_Complex_I, 0.128962993622 + 0.032193422318*_Complex_I, -0.085369610786 + 0.007678684592*_Complex_I, -0.040599119663 + 0.058400410414*_Complex_I, 0.034683728218 + 0.006657131016*_Complex_I, -0.062493687868 + 0.258592700958*_Complex_I, 0.030317050219 + -0.182111239433*_Complex_I, -0.029376697540 + 0.052327275276*_Complex_I, -0.109441542625 + -0.079162907600*_Complex_I, -0.090063333511 + -0.016401563585*_Complex_I, -0.209231019020 + 0.104617154598*_Complex_I, 0.033998718858 + 0.114239072800*_Complex_I, 0.016250103712 + -0.094514828920*_Complex_I, -0.065307158232 + -0.109144735336*_Complex_I, 0.044777354598 + 0.034570571780*_Complex_I, 0.047505182028 + 0.106286907196*_Complex_I, 0.032323399186 + -0.060076057911*_Complex_I, 0.009413731098 + 0.113497722149*_Complex_I, -0.001863899827 + 0.103868281841*_Complex_I, -0.136217641830 + 0.035371488333*_Complex_I, 0.035117888451 + -0.181699144840*_Complex_I, 0.012568083405 + 0.029830288887*_Complex_I, 0.222174477577 + -0.128343975544*_Complex_I, -0.073185539246 + 0.019389149547*_Complex_I, 0.101314771175 + 0.003134848550*_Complex_I, 0.029810345173 + 0.106935989857*_Complex_I, 0.062490916252 + -0.069559586048*_Complex_I, 0.149825906754 + 0.072701114416*_Complex_I, 0.123934853077 + -0.025215783715*_Complex_I, 0.009782531857 + -0.153410112858*_Complex_I, 0.160168147087 + 0.089273881912*_Complex_I, 0.168133974075 + 0.006127674505*_Complex_I, 0.045770967007 + -0.068010586500*_Complex_I, 0.031379061937 + -0.011051291972*_Complex_I, 0.158589434624 + -0.111993229389*_Complex_I, -0.076348328590 + -0.078152877092*_Complex_I, -0.134444558620 + -0.117534625530*_Complex_I, -0.079543095827 + -0.066662031412*_Complex_I, -0.071512258053 + -0.002769588307*_Complex_I, 0.044172352552 + -0.001636494324*_Complex_I, 0.106910932064 + 0.067301118374*_Complex_I, -0.189863562584 + -0.210064339638*_Complex_I, 0.160713946819 + -0.175641644001*_Complex_I, 0.107809066772 + -0.015213376284*_Complex_I, 0.122092103958 + -0.030190780759*_Complex_I, -0.003812288493 + -0.100728774071*_Complex_I, -0.106180906296 + 0.040024718642*_Complex_I, -0.023936416209 + 0.098257493973*_Complex_I, 0.036565282941 + 0.003215969726*_Complex_I, -0.103855776787 + -0.073435127735*_Complex_I, -0.050348949432 + 0.062807798386*_Complex_I, -0.112694954872 + 0.127760851383*_Complex_I, -0.090150475502 + 0.123642957211*_Complex_I, 0.045266637206 + -0.160168957710*_Complex_I, 0.026377058029 + 0.006977221370*_Complex_I, 0.102039659023 + -0.043179959059*_Complex_I, 0.013855941594 + 0.044194161892*_Complex_I, -0.218561863899 + -0.144262731075*_Complex_I, -0.137404084206 + 0.063279211521*_Complex_I, 0.238168430328 + 0.085272878408*_Complex_I, -0.048531836271 + 0.178845489025*_Complex_I, -0.144287097454 + 0.058967697620*_Complex_I, -0.049209004641 + -0.025680020452*_Complex_I, 0.024836380780 + -0.005075773597*_Complex_I, 0.102902829647 + 0.135188984871*_Complex_I, 0.011638478935 + -0.053264147043*_Complex_I, 0.022318521142 + -0.005398513377*_Complex_I, -0.073730462790 + -0.112155592442*_Complex_I, -0.006353335828 + -0.047271516919*_Complex_I, -0.009832777083 + -0.083933675289*_Complex_I, -0.189570760727 + -0.024030640721*_Complex_I, 0.170936667919 + -0.021397763491*_Complex_I, 0.027291259170 + 0.065315496922*_Complex_I, 0.021211113036 + 0.016976553202*_Complex_I, 0.009872701019 + -0.091594105959*_Complex_I, 0.057232087851 + -0.185351312160*_Complex_I, 0.200562620163 + -0.098748236895*_Complex_I, 0.055897176266 + -0.010039170831*_Complex_I, -0.127369284630 + -0.044656923413*_Complex_I, 0.137353527546 + 0.299679923058*_Complex_I, 0.045141702890 + -0.044110915065*_Complex_I, -0.004061393067 + -0.012276126444*_Complex_I, -0.177904891968 + 0.037945824862*_Complex_I, 0.154672491550 + -0.095904517174*_Complex_I, -0.175321102142 + 0.007050059736*_Complex_I, -0.146184301376 + -0.079787492752*_Complex_I, 0.189255583286 + 0.028883567452*_Complex_I, -0.122478711605 + -0.069346314669*_Complex_I, -0.046293541789 + 0.053173589706*_Complex_I, -0.007427679747 + 0.097887659073*_Complex_I, 0.015306715667 + 0.002264038287*_Complex_I, -0.000068226655 + 0.105025970936*_Complex_I, 0.003785865381 + -0.108235859871*_Complex_I, -0.007453963161 + 0.090025615692*_Complex_I}; float complex fftfilt_crcf_data_h7x256_y[] = { -0.001664060705 + -0.004091991592*_Complex_I, 0.009572387490 + 0.010806149100*_Complex_I, -0.019901401209 + 0.000163118771*_Complex_I, 0.022119513679 + 0.037897731040*_Complex_I, 0.002233819268 + -0.019592330428*_Complex_I, 0.002525225428 + 0.062331636862*_Complex_I, -0.012953756015 + -0.013138017071*_Complex_I, 0.010082536290 + 0.073767533264*_Complex_I, 0.060041705276 + -0.002211361863*_Complex_I, -0.028964339812 + 0.034181387304*_Complex_I, -0.018779359256 + -0.002983805531*_Complex_I, 0.035540274574 + -0.000359767320*_Complex_I, 0.018230003371 + -0.019050266810*_Complex_I, -0.004763113580 + -0.030748598959*_Complex_I, -0.014980219026 + -0.052722939755*_Complex_I, 0.043826553194 + 0.014698974734*_Complex_I, -0.019748368274 + -0.017846203362*_Complex_I, -0.011106427606 + -0.056159008955*_Complex_I, 0.019392753020 + -0.015821591090*_Complex_I, 0.034983837452 + 0.006944986235*_Complex_I, 0.011247676464 + 0.014886292150*_Complex_I, -0.023269214094 + -0.046261333224*_Complex_I, 0.021153525557 + 0.012909728412*_Complex_I, -0.027534552856 + 0.022575118010*_Complex_I, -0.007955539149 + 0.007852778474*_Complex_I, 0.042312648793 + 0.017460367142*_Complex_I, 0.002444803765 + -0.005588089285*_Complex_I, 0.018236124634 + 0.042201155890*_Complex_I, -0.028316282736 + 0.032506714358*_Complex_I, 0.027833124697 + 0.022694313405*_Complex_I, 0.052935514738 + 0.031327141782*_Complex_I, 0.026052595484 + -0.027272295746*_Complex_I, 0.008104080597 + 0.021431694747*_Complex_I, -0.004512749861 + 0.007815877639*_Complex_I, 0.024134102168 + -0.041085781838*_Complex_I, 0.013299793171 + -0.012836542385*_Complex_I, -0.024458533812 + -0.003758988445*_Complex_I, 0.004926203119 + -0.004067048560*_Complex_I, -0.008670506918 + -0.009165691319*_Complex_I, 0.004383190990 + -0.061656974229*_Complex_I, 0.004798093293 + -0.001521204143*_Complex_I, -0.010192016400 + 0.013551533652*_Complex_I, 0.016184999222 + -0.022825917758*_Complex_I, -0.006827691414 + -0.013869452441*_Complex_I, 0.004506159339 + -0.027475686016*_Complex_I, -0.014160870823 + 0.064266780404*_Complex_I, 0.034386845087 + -0.005930865931*_Complex_I, 0.018854367860 + 0.040245466115*_Complex_I, 0.027504376699 + -0.033177621818*_Complex_I, 0.020613311216 + 0.029686212518*_Complex_I, 0.019605341108 + -0.022282553995*_Complex_I, 0.051946574188 + -0.010220239313*_Complex_I, -0.008537785955 + -0.011901108333*_Complex_I, 0.038021151548 + -0.003863047727*_Complex_I, -0.000285452285 + -0.017843481523*_Complex_I, 0.010371007070 + -0.016105029388*_Complex_I, 0.006025408264 + 0.033055735207*_Complex_I, -0.021980650718 + 0.021798423647*_Complex_I, -0.023022513053 + 0.051363849161*_Complex_I, -0.009988970700 + 0.014282686356*_Complex_I, -0.015333264002 + 0.006580976190*_Complex_I, 0.004814453158 + 0.067575161384*_Complex_I, 0.021078361301 + -0.008218606426*_Complex_I, -0.018224318008 + 0.078249889963*_Complex_I, -0.037359896117 + -0.025653924650*_Complex_I, -0.064316968357 + -0.014904552890*_Complex_I, -0.013278818311 + -0.017987895509*_Complex_I, -0.006335027346 + -0.029308988553*_Complex_I, 0.019772938592 + 0.010742017022*_Complex_I, -0.051503658033 + -0.028040995216*_Complex_I, 0.002794574067 + -0.025427598795*_Complex_I, -0.024524259323 + -0.007221318106*_Complex_I, 0.017882433375 + 0.007567005700*_Complex_I, -0.002250551860 + 0.019747472870*_Complex_I, 0.023938973082 + -0.011112496998*_Complex_I, -0.019139308840 + 0.011136397615*_Complex_I, -0.002187533851 + 0.036491286044*_Complex_I, -0.021134226221 + 0.033399966516*_Complex_I, -0.018505797162 + 0.019092652268*_Complex_I, -0.040662996211 + -0.010428531884*_Complex_I, -0.014960045707 + 0.026857740562*_Complex_I, -0.005153165788 + 0.043765214305*_Complex_I, -0.007957971301 + 0.025585809340*_Complex_I, -0.020982171142 + -0.017767345049*_Complex_I, -0.010632593672 + -0.017190118051*_Complex_I, -0.036959052593 + 0.031325636500*_Complex_I, -0.029896295979 + -0.024658675955*_Complex_I, -0.025453655228 + 0.011865474671*_Complex_I, -0.032120802983 + 0.013036366771*_Complex_I, -0.032795629447 + 0.021107115286*_Complex_I, 0.010773771971 + 0.024117992872*_Complex_I, 0.006601385448 + -0.042746141925*_Complex_I, -0.020772448711 + 0.029219872585*_Complex_I, 0.070536673110 + 0.016052326150*_Complex_I, -0.001423170033 + 0.031759755912*_Complex_I, -0.013628227138 + -0.003553860969*_Complex_I, -0.058771606883 + -0.049123627122*_Complex_I, 0.020108788723 + 0.037188142016*_Complex_I, 0.007949063332 + 0.010951582458*_Complex_I, -0.038626115166 + -0.024020666588*_Complex_I, -0.078006273376 + -0.045266963734*_Complex_I, 0.017751019078 + -0.063270144075*_Complex_I, 0.016258961397 + -0.015778900175*_Complex_I, -0.018458853139 + -0.029074158472*_Complex_I, -0.080688576156 + -0.034942123609*_Complex_I, -0.031578691749 + -0.015054873307*_Complex_I, 0.036145679578 + -0.014310450501*_Complex_I, -0.021959415316 + -0.000580080691*_Complex_I, -0.047396546182 + -0.059828747217*_Complex_I, -0.035670847715 + -0.003606200086*_Complex_I, 0.006553370474 + -0.010100243677*_Complex_I, -0.011536306226 + -0.007568475396*_Complex_I, -0.010414782074 + -0.052787147602*_Complex_I, -0.022759606756 + -0.019938883855*_Complex_I, -0.000682229297 + -0.011460511608*_Complex_I, -0.022518239866 + -0.037363417124*_Complex_I, -0.007962730587 + 0.007463843703*_Complex_I, -0.020202765636 + -0.034000570007*_Complex_I, -0.013134852636 + -0.025359042386*_Complex_I, 0.005789769049 + -0.019359516099*_Complex_I, -0.007477326398 + -0.017065274446*_Complex_I, 0.007535152908 + 0.014947146624*_Complex_I, 0.008478526310 + -0.033064163294*_Complex_I, 0.006495736538 + -0.000621013504*_Complex_I, -0.018881009743 + -0.042515704819*_Complex_I, 0.003959382518 + -0.023006182258*_Complex_I, -0.005478138646 + -0.022439956712*_Complex_I, 0.012649989781 + -0.011810626415*_Complex_I, -0.016784136514 + -0.039783192634*_Complex_I, -0.052016102486 + -0.007841932680*_Complex_I, 0.059471950363 + -0.013592303981*_Complex_I, 0.013914799172 + 0.044984722860*_Complex_I, 0.011486842937 + -0.061671443344*_Complex_I, -0.036780337271 + -0.003311742125*_Complex_I, -0.006092641235 + 0.007927763608*_Complex_I, 0.007902421446 + -0.001011649739*_Complex_I, -0.006795769455 + 0.008805976503*_Complex_I, 0.023605170020 + -0.038943989870*_Complex_I, 0.023625556066 + -0.009183727558*_Complex_I, 0.013693690762 + -0.003169361400*_Complex_I, 0.029827583427 + -0.013202113602*_Complex_I, 0.005499368566 + 0.025768234920*_Complex_I, 0.020555898301 + -0.006579736075*_Complex_I, -0.018397046470 + 0.008180231852*_Complex_I, -0.000311933642 + -0.045290959470*_Complex_I, -0.009854739488 + 0.094914113403*_Complex_I, -0.001041015584 + -0.010428696751*_Complex_I, -0.019479887241 + 0.038746806007*_Complex_I, 0.003949972577 + -0.023915676515*_Complex_I, -0.005952904345 + 0.028280800121*_Complex_I, -0.020794732314 + 0.049370817714*_Complex_I, -0.013758601114 + -0.029866172207*_Complex_I, -0.018665194668 + -0.036784877494*_Complex_I, 0.027598854453 + -0.029032203867*_Complex_I, 0.020417636582 + 0.032869611698*_Complex_I, -0.038033374173 + -0.047062159994*_Complex_I, -0.002307491697 + 0.016775992609*_Complex_I, 0.002741426303 + 0.000401399904*_Complex_I, 0.047873297365 + 0.035012972663*_Complex_I, -0.002960979438 + -0.003970085476*_Complex_I, -0.013174401910 + -0.001911987889*_Complex_I, -0.015764753015 + 0.009609419552*_Complex_I, 0.030869778703 + 0.004752229880*_Complex_I, -0.007925303167 + 0.018384260100*_Complex_I, -0.036144266243 + -0.012421792859*_Complex_I, -0.021583982780 + 0.005519018931*_Complex_I, 0.011692092106 + -0.008831839761*_Complex_I, -0.019409391330 + -0.038426827460*_Complex_I, 0.006223391109 + 0.046989172728*_Complex_I, 0.018999067344 + -0.023638921178*_Complex_I, -0.026744966281 + 0.035209035395*_Complex_I, -0.005797132267 + -0.030721098320*_Complex_I, -0.012007029920 + 0.052541286005*_Complex_I, -0.040002533893 + 0.015828735411*_Complex_I, 0.007259346684 + 0.002315325843*_Complex_I, -0.022414689402 + -0.003834870337*_Complex_I, -0.024299572844 + -0.033955598422*_Complex_I, -0.045734353675 + -0.001347407015*_Complex_I, -0.030146751771 + 0.053501404395*_Complex_I, 0.020367548034 + 0.003025664117*_Complex_I, -0.006737275010 + -0.018512929694*_Complex_I, -0.000605709571 + -0.012347963683*_Complex_I, -0.006890463622 + 0.046621939143*_Complex_I, 0.016047502033 + -0.019923449202*_Complex_I, -0.008396903768 + 0.010041927047*_Complex_I, 0.047436458062 + 0.003595322623*_Complex_I, -0.037015474086 + 0.041649052012*_Complex_I, 0.007016220323 + -0.036370210637*_Complex_I, -0.012617538063 + 0.002683467470*_Complex_I, 0.051168439092 + -0.028397908806*_Complex_I, 0.035205638612 + -0.001881106820*_Complex_I, 0.021551345104 + -0.005936731955*_Complex_I, 0.020923031070 + 0.002729234686*_Complex_I, 0.024976448430 + 0.011252084504*_Complex_I, 0.045876193259 + -0.003769034340*_Complex_I, 0.058950819572 + 0.017386610345*_Complex_I, 0.017620108715 + -0.032126491912*_Complex_I, 0.040499252854 + -0.028610567370*_Complex_I, 0.047208712591 + 0.014810229612*_Complex_I, 0.027499183980 + -0.028800252172*_Complex_I, -0.012932302613 + -0.018166904753*_Complex_I, 0.016403288642 + -0.020622110742*_Complex_I, 0.022373704021 + -0.028689811011*_Complex_I, -0.009452243729 + -0.008680644929*_Complex_I, -0.058678992249 + -0.051174770891*_Complex_I, -0.005006438141 + -0.031267299630*_Complex_I, -0.015215097299 + -0.020119691971*_Complex_I, 0.066084164099 + 0.016564502968*_Complex_I, -0.013768201897 + -0.023474209345*_Complex_I, -0.021803271593 + -0.062476214596*_Complex_I, 0.028932477041 + -0.022490403547*_Complex_I, 0.040341712936 + 0.006962852165*_Complex_I, 0.015330216728 + -0.030617975708*_Complex_I, -0.015573978799 + -0.015495893724*_Complex_I, -0.042595498240 + 0.029811952687*_Complex_I, -0.007383005008 + 0.050473873697*_Complex_I, -0.007960910417 + -0.029841422966*_Complex_I, -0.022273885029 + -0.003249632656*_Complex_I, -0.002824822559 + 0.003348401440*_Complex_I, -0.024087272328 + 0.065990131062*_Complex_I, -0.028057881818 + -0.029151797322*_Complex_I, -0.024558131583 + -0.015268822223*_Complex_I, 0.039877624209 + -0.013405850916*_Complex_I, 0.028823486535 + 0.037004255305*_Complex_I, -0.023970193031 + -0.005435181200*_Complex_I, -0.088636699560 + -0.013757698161*_Complex_I, 0.008098637338 + 0.006870343753*_Complex_I, 0.054927003829 + 0.056475265541*_Complex_I, -0.024306265176 + 0.034672928541*_Complex_I, -0.021853531429 + 0.018230890552*_Complex_I, -0.021682656382 + -0.032466179919*_Complex_I, 0.019989585378 + 0.020908798620*_Complex_I, 0.019423343509 + -0.002219973236*_Complex_I, -0.021632746497 + -0.006294932050*_Complex_I, 0.013621743308 + -0.025286913038*_Complex_I, -0.020772874190 + -0.012989704190*_Complex_I, 0.025482399527 + -0.014215236725*_Complex_I, -0.044300771406 + -0.017049381631*_Complex_I, -0.006816700080 + -0.032915524093*_Complex_I, 0.057073619573 + -0.013791458776*_Complex_I, 0.023935306468 + 0.010113795207*_Complex_I, -0.010074654341 + -0.020758506394*_Complex_I, 0.014148879115 + 0.005089223239*_Complex_I, 0.035479315734 + -0.053250867185*_Complex_I, 0.068075559099 + -0.000004138871*_Complex_I, -0.049122106052 + -0.026433363499*_Complex_I, 0.023522704576 + 0.028855355307*_Complex_I, 0.002677137744 + 0.051086576447*_Complex_I, 0.002630815479 + -0.030154181511*_Complex_I, -0.021284842311 + 0.018492273061*_Complex_I, -0.014785053010 + -0.025361228004*_Complex_I, 0.015700956081 + -0.004007983078*_Complex_I, -0.076870199719 + -0.004459394713*_Complex_I, 0.013883703469 + -0.003931123862*_Complex_I, 0.016113428385 + 0.014312499105*_Complex_I, -0.025629511396 + -0.029198167224*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_rrrf_data_h13x256.c000066400000000000000000000270471474751757600247100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_rrrf_data_h13x256.c: autotest fftfilt data // float fftfilt_rrrf_data_h13x256_h[] = { -0.039212104678, -0.045289030671, -0.184304034710, 0.077858728170, 0.040869677067, 0.142814588547, -0.108285641670, 0.089570593834, -0.172709572315, 0.001841047592, 0.074960124493, -0.114357507229, 0.043473127484}; float fftfilt_rrrf_data_h13x256_x[] = { 0.122770094872, 0.089148938656, 0.017954966426, -0.028631305695, -0.024217808247, -0.019191932678, 0.124998247623, -0.010905320942, -0.182813262939, 0.022872561216, -0.167512893677, 0.004144698754, -0.091696554422, 0.145599734783, 0.149157440662, 0.111943149567, -0.083463251591, 0.074205029011, 0.057325953245, 0.098762345314, -0.056830596924, 0.129721879959, 0.070393782854, 0.044613954425, -0.041217750311, -0.047065210342, 0.042085236311, 0.065604847670, 0.011089600623, 0.055663853884, 0.010694834590, -0.107917737961, 0.091816771030, -0.071010309458, 0.225902843475, -0.193409955502, 0.134397053719, 0.006444688141, -0.100715303421, 0.013986042142, 0.037019279599, -0.018146976829, 0.038268235326, 0.124087500572, -0.065513682365, 0.243372726440, 0.070982813835, -0.114888060093, 0.083260691166, 0.078598594666, 0.119385373592, 0.124578750134, 0.229874610901, 0.068851232529, -0.152908086777, 0.022878190875, -0.038320010900, -0.019077518582, -0.187935698032, 0.000150304066, 0.107031500340, -0.054503691196, -0.189286994934, 0.106510078907, 0.016531120241, -0.062976771593, -0.034572181106, 0.116243016720, 0.014939060807, -0.104378926754, 0.035551485419, -0.211227297783, 0.056110930443, -0.069913518429, 0.050586497784, 0.100069129467, 0.307702898979, 0.186338675022, 0.197983598709, 0.070847284794, -0.168327832222, -0.115514957905, -0.069601941109, 0.079878026247, 0.015964616835, 0.128264808655, 0.015298053622, 0.210790205002, 0.040280216932, 0.091706073284, 0.090860366821, -0.034307426214, -0.043785154819, 0.100965428352, 0.062400549650, 0.122274744511, -0.063038861752, -0.173100697994, -0.167581903934, 0.088559448719, -0.130531704426, -0.021028609574, 0.060926514864, 0.078577047586, 0.197759902477, 0.019897483289, -0.015052948892, -0.156514930725, 0.121016633511, 0.080825585127, 0.026895985007, -0.032256072760, -0.033008736372, 0.101098561287, -0.004690715298, -0.097240817547, 0.124587404728, -0.080275380611, -0.170625138283, 0.064333653450, -0.082882106304, 0.055449581146, 0.036299997568, -0.036278706789, 0.075224477053, 0.005092585459, 0.031370615959, 0.020764264464, 0.049643722177, 0.021591423452, -0.040642136335, 0.027282950282, 0.134740507603, -0.029146528244, 0.034743618965, -0.014017164707, -0.070363909006, 0.020523373783, 0.000458177784, -0.068270605803, 0.180056059361, -0.119201040268, -0.046510973573, -0.058247959614, 0.155885064602, -0.083602911234, -0.119938647747, -0.114219510555, 0.161393058300, 0.232402944565, -0.151511478424, 0.066477537155, -0.115181660652, -0.164413774014, 0.031050026417, -0.038917222619, 0.093678462505, -0.040763008595, -0.004956462234, 0.044149956107, 0.113123583794, -0.092754375935, -0.027752390504, 0.137882554531, 0.035738137364, -0.051311886311, 0.134906625748, 0.123595929146, 0.159623205662, 0.014216412604, -0.078501766920, -0.046537932754, 0.066755509377, -0.061657583714, 0.008335828036, 0.009980520606, 0.106155145168, -0.010150838643, -0.012183431536, 0.101287877560, 0.024197725952, -0.060843515396, -0.240097737312, 0.065998744965, -0.050199592113, -0.055537813902, 0.165046787262, 0.133701193333, -0.018093936145, -0.113999474049, -0.069255769253, -0.081180727482, 0.070946794748, 0.136880230904, 0.025476306677, -0.102032244205, -0.024109381437, -0.016868881881, 0.167234003544, 0.171832489967, -0.030091801286, 0.011118320376, -0.008921170235, 0.101217842102, -0.048454919457, 0.151966249943, 0.198045432568, 0.040109497309, 0.016406393051, 0.089656168222, 0.035927999020, -0.033026877046, -0.054043507576, 0.211845135689, -0.036055120826, 0.160977423191, -0.197179889679, 0.040342581272, 0.150020170212, -0.073872137070, -0.164493560791, 0.124404942989, 0.031155037880, -0.061415308714, 0.000370543310, -0.019733832777, 0.089461517334, 0.229397058487, 0.149904847145, -0.119740092754, -0.233863234520, -0.029367747903, 0.070431739092, 0.001778364740, 0.166927957535, -0.018398888409, -0.102967965603, 0.006021655723, 0.067407786846, -0.140168070793, 0.011420756578, 0.095064306259, 0.020388415456, -0.112541508675, -0.085077953339, 0.125045490265, 0.210480499268, -0.117026185989, -0.089133924246, 0.147170877457, 0.107982301712, 0.096577769518, -0.058198565245, 0.027206465602, 0.002091913670, -0.088938659430}; float fftfilt_rrrf_data_h13x256_y[] = { -0.004814073811, -0.009055856107, -0.027368544867, -0.006562254910, 0.010895739671, 0.029701022061, -0.001626673446, -0.000844726806, -0.037111011029, 0.004419375864, 0.047068466895, 0.003910634431, 0.012396721813, -0.025213063245, 0.000635157075, -0.085524325904, 0.041146455184, -0.050979327116, 0.077630920989, -0.003623999480, -0.004841852073, -0.028754487596, 0.001410758665, -0.034036822601, 0.014107997579, -0.022709798205, 0.025617017445, -0.003252183639, -0.003963481395, -0.036270671993, -0.021399438537, 0.017388718079, -0.000128062767, 0.028859143315, -0.030391114442, 0.001543784470, -0.046555566322, 0.058215460338, -0.063274785430, 0.077974731120, -0.057110585904, 0.054791309007, -0.060943087255, 0.010461367165, 0.008954983539, -0.076741190112, 0.063566034944, -0.058742851449, 0.008267455413, 0.026477649501, 0.013490128892, -0.071421597975, -0.011335301312, -0.030890897000, -0.062240856218, 0.083426871968, 0.015357553814, -0.000362231866, 0.008918381045, -0.028650443960, 0.017482443006, -0.052161386060, 0.020679845153, -0.025369370715, 0.045526628268, -0.011020145844, 0.002644272584, 0.006285259524, -0.004936878581, -0.019116352540, 0.039400594243, 0.000124031921, 0.002039447415, 0.062249843178, -0.043579179266, -0.001996355335, -0.069473606074, 0.023450651628, -0.118043698351, 0.033847857380, 0.001708993883, 0.047506531454, 0.075888786942, 0.008727973204, -0.040651907871, -0.077531568445, -0.017930168448, -0.069340649806, 0.041402166708, -0.040029272550, 0.025336666274, -0.018448259990, 0.033311907821, -0.013731300546, 0.016338663490, -0.049502280186, -0.034415215410, 0.005555120775, 0.018242670176, 0.047690282789, 0.041262648570, -0.072855941506, 0.009723921419, -0.029262747157, -0.011884300184, -0.027377242282, 0.003541591160, 0.004992461263, 0.044689949294, 0.066697897821, -0.089113718326, 0.005326909592, -0.042616477087, 0.036692093307, -0.004180374377, -0.003271218876, -0.009369454837, -0.002500828958, 0.016544265383, 0.002187635659, 0.029976595593, -0.018441944452, -0.020909152277, 0.007956140844, -0.021637777770, -0.014177920945, 0.055566577829, -0.042960866797, 0.006896087167, 0.024767376727, -0.043457653016, 0.034935882911, -0.015575911379, -0.009819491182, -0.018887628248, -0.001068307187, 0.006963055931, 0.013680239410, 0.005809808354, 0.005066455307, -0.040283759818, 0.017470897286, -0.022805491441, 0.015206465884, 0.019136018024, 0.021643961761, -0.071515530177, 0.078236064221, -0.029742524131, 0.032918640371, -0.053023950617, -0.047312921105, 0.034250312751, 0.032284357688, 0.068808863735, -0.015296681918, 0.000837419600, -0.075314366704, 0.024501519621, 0.005869076899, -0.039416548615, 0.069295643723, -0.060264925779, 0.046170239698, -0.002067325538, -0.026442474538, -0.007890011691, 0.000037015562, -0.035959976850, -0.016139843757, -0.002858263222, 0.006428619035, 0.027561864469, 0.042341971465, -0.058543104834, -0.007599628510, -0.014902259564, -0.011133330016, -0.020432058943, 0.017048024915, -0.016928345566, 0.012963663673, 0.008408004748, 0.018403366116, 0.046619907266, -0.038433448340, 0.007648025051, -0.059208853553, -0.011295552139, -0.025495843506, 0.062840766336, 0.041709165483, -0.000905313483, 0.033310202711, -0.082126428402, -0.037682258830, 0.020034347469, 0.049244781989, -0.001378192350, -0.008849598752, -0.050136739148, -0.035155204482, 0.024111310154, 0.038903294513, -0.003167046710, -0.032326890373, 0.004090324360, -0.075671618163, 0.006238782693, -0.017653047474, 0.025665426828, -0.012204527876, 0.007845325954, 0.005183653849, -0.034222431570, -0.037618568932, 0.013395877564, -0.045882750561, 0.072052386700, -0.040677327938, 0.025524603777, -0.058679392496, 0.073277528966, -0.045606738121, -0.018120414293, 0.035599866018, -0.037821283601, 0.009959320327, -0.008944663864, -0.071448196749, -0.002389984851, 0.105394267739, 0.040560858684, -0.015716980196, -0.051319091715, -0.053534618918, -0.028961761656, 0.040242569747, 0.040510770959, 0.011016182224, -0.040345662543, 0.048481523965, -0.035361728505, -0.024831493953, 0.018886824467, 0.026390411027, -0.016368948643, -0.009813816544, -0.035846470146, 0.008843767444, 0.038479236659, -0.019424751909, -0.036842320539, -0.011401190478, 0.012789717510, 0.024104726420}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_rrrf_data_h23x256.c000066400000000000000000000273571474751757600247150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_rrrf_data_h23x256.c: autotest fftfilt data // float fftfilt_rrrf_data_h23x256_h[] = { -0.118176388741, -0.025418123603, -0.059258782864, 0.142066907883, 0.004454790801, -0.016711865366, 0.005629793927, -0.123983550072, 0.173112368584, -0.160880231857, 0.054240733385, -0.031276765466, 0.154612803459, -0.006389370561, 0.079528987408, -0.002910712734, -0.159243178368, 0.022829471529, -0.113626921177, -0.095083606243, -0.122057342529, 0.104624044895, 0.011057048291}; float fftfilt_rrrf_data_h23x256_x[] = { 0.059350812435, -0.000424881605, -0.049009537697, -0.034536927938, 0.103308689594, -0.055876135826, -0.148367643356, -0.111977064610, 0.067770421505, 0.043956550956, 0.143173515797, 0.004022727162, 0.111428678036, 0.028413870931, 0.166605424881, 0.038992109895, -0.010133068264, 0.076038408279, 0.105890285969, 0.147610998154, -0.047342804074, 0.055655419827, -0.013745918870, -0.016829429567, -0.062561410666, 0.095859551430, 0.019820876420, 0.037723916769, 0.054752278328, 0.057050412893, 0.207521724701, -0.130268049240, 0.165039086342, -0.194032716751, 0.189072954655, -0.137876522541, 0.047114580870, -0.072617882490, -0.100785088539, 0.064732289314, -0.073995077610, 0.019561932981, 0.046311601996, -0.104536223412, -0.033436897397, 0.151995897293, 0.031935700774, -0.028941801190, 0.078559994698, -0.047812539339, 0.130064833164, -0.056572306156, -0.042208436131, 0.085643953085, -0.080961161852, 0.057486045361, 0.020754659176, 0.070619314909, 0.158251059055, 0.088375788927, -0.043805596232, 0.127501475811, 0.115190374851, -0.044433131814, 0.034547865391, -0.044843772054, -0.062454062700, 0.030952209234, 0.040272334218, -0.046460473537, 0.054621320963, -0.026183435321, -0.025449073315, 0.053822481632, 0.173386669159, 0.039320838451, 0.080104076862, -0.057773065567, -0.145702457428, -0.104137754440, 0.001670002751, -0.015087755024, 0.030506807566, 0.050601142645, -0.168711090088, 0.072758728266, -0.085856407881, 0.036477252841, 0.033204284310, -0.074460619688, -0.132449066639, -0.005033437908, 0.051431566477, -0.000122980447, 0.104783654213, 0.086071228981, 0.087956553698, 0.018256981671, 0.273954725266, -0.047239318490, 0.061503499746, 0.006188166887, -0.009299278259, 0.085814112425, 0.131504595280, -0.038905382156, -0.043368801475, 0.201532816887, 0.094288158417, 0.092639130354, 0.049885711074, -0.063641804457, -0.134385573864, -0.129504549503, 0.116876983643, 0.034869593382, 0.110995888710, 0.209363675117, 0.089506244659, 0.032240226865, -0.035387760401, -0.011358998716, -0.217154717445, -0.075535118580, 0.154909908772, 0.035121211410, -0.009927383065, -0.017504146695, -0.041967305541, 0.001003832649, 0.014955335855, 0.081758105755, 0.026359021664, -0.056244474649, -0.145741295815, 0.020014302433, 0.017129588127, -0.074675554037, -0.048099777102, 0.079832047224, 0.177468204498, -0.064336484671, 0.007799343765, 0.058800733089, -0.015487244725, 0.040828344226, -0.009191709757, 0.097432601452, -0.064271640778, 0.010111794621, -0.088703465462, 0.031145793200, 0.060152173042, -0.041082245111, 0.033332934976, -0.040413409472, 0.004355887696, 0.058080500364, 0.014798428118, -0.067486256361, -0.059195333719, -0.058406758308, -0.032816353440, -0.179800736904, -0.068667584658, -0.086956882477, 0.275450372696, 0.033261230588, -0.055281239748, 0.144350075722, -0.202899336815, -0.041189083457, 0.045112118125, -0.064310503006, 0.123022067547, 0.007392913103, 0.059860253334, -0.088910865784, 0.246307659149, 0.136940467358, 0.148684620857, -0.067826855183, 0.044850471616, 0.021945165098, -0.050006192923, -0.015575663745, -0.011492988467, -0.215618276596, 0.015057675540, -0.014546294510, -0.091270244122, -0.014081606269, -0.005267200246, 0.008527950943, 0.084022140503, 0.050226074457, -0.086916053295, 0.009611618519, 0.078965556622, -0.269776344299, 0.251430296898, -0.083879828453, 0.058131092787, 0.093344569206, -0.009404690564, -0.180945825577, 0.026505178213, 0.178118884563, -0.036366626620, 0.119481074810, -0.046089172363, 0.012725484371, 0.105508100986, 0.139382028580, -0.145310318470, 0.066300112009, -0.155467641354, -0.186421251297, 0.136932229996, 0.091225856543, -0.057187086344, 0.073608285189, 0.008684530854, -0.131529307365, -0.020294201374, 0.129804944992, 0.146946787834, -0.069120013714, -0.056884109974, -0.069945359230, -0.075904464722, 0.096382999420, -0.052887690067, -0.023378646374, -0.020363801718, 0.052989178896, 0.097394061089, -0.095514106750, 0.114465987682, 0.149921727180, -0.145940053463, 0.116530537605, -0.002146193571, -0.033402639627, 0.088303333521, 0.014771881700, 0.033233019710, -0.034135624766, -0.053486305475, 0.064908540249, 0.001977766119, 0.061249178648, -0.045406821370, 0.009912858903, 0.121469497681, 0.103848683834}; float fftfilt_rrrf_data_h23x256_y[] = { -0.007013864682, -0.001458375313, 0.002285512965, 0.013784144279, -0.008222504569, -0.001932445802, 0.008048223230, 0.028296439689, 0.006779838852, -0.027075112618, -0.038021355416, -0.008207405447, 0.022727377225, 0.003661135507, -0.025140469834, -0.012236287908, 0.016448242015, -0.022041432338, 0.003765875876, -0.086743626880, 0.008804356573, -0.012282203678, 0.096545010469, -0.016051310432, 0.025673500424, 0.031954762710, 0.010291226924, -0.004617541860, -0.078915357449, 0.016347541321, -0.078243227224, 0.053416005824, -0.073942376885, 0.075168320113, -0.105443090203, 0.032685403487, -0.054354778278, -0.017947992570, 0.028325854650, -0.066017207222, 0.127152882603, -0.129786378633, 0.153392128443, -0.101101386787, 0.089515971822, -0.098153948006, -0.018623281322, -0.007210919422, -0.052842605245, 0.032639231668, -0.084346314422, 0.075150470719, -0.077797755022, 0.090483672403, -0.028648123276, -0.018159951111, 0.048359402647, -0.037666024522, 0.028960325781, -0.033371992052, 0.026921999056, -0.009095421681, -0.003055504078, 0.008517976100, -0.047205023338, 0.015219099504, -0.029899324803, 0.037376834246, -0.058818185973, 0.016202491134, 0.027713179518, 0.010360717592, 0.018872350014, -0.007238271158, -0.026777182477, -0.042586692131, -0.005396798853, -0.053278897967, 0.003600267191, 0.021901335336, -0.013091061698, -0.047316523688, 0.018443222297, -0.025150770998, 0.036826636675, 0.013809067598, 0.036530318086, -0.025825991720, 0.047029879857, -0.018694842890, -0.024991556586, 0.021396439314, -0.100068124600, 0.002032355704, -0.058647750333, 0.054049505689, -0.025341189676, 0.067615154602, -0.044899284658, 0.021135756051, -0.004151297683, -0.010694122753, 0.009371387806, -0.029794165824, 0.013390817044, -0.059682815079, 0.111820810826, -0.059861745262, 0.045667041385, -0.016011228532, 0.043233291738, -0.024093786781, 0.036936965515, -0.007311481950, -0.104248864495, 0.022282329467, -0.092586037340, -0.017084241199, -0.042839250540, 0.036605764530, 0.013232172340, 0.027382131751, 0.061010646729, -0.075041791947, -0.032923246322, -0.064505588738, -0.062494604045, -0.014118814560, 0.041292311729, 0.082239901043, -0.005253566244, 0.046726579388, 0.010585548464, -0.055116829572, -0.057026861265, -0.032618339372, -0.034378961584, -0.034963708479, 0.058675519175, 0.029871506017, -0.031900560694, 0.023355935441, -0.001213445200, 0.026491853482, -0.027623272659, -0.003191991347, -0.004121011628, -0.029001573940, 0.026187127755, -0.056189942809, 0.041920449009, -0.012905850771, 0.030518693114, 0.033991468359, 0.003919996873, 0.023741085525, -0.055324780487, 0.059796004556, -0.070732526849, 0.002634444280, 0.006125322170, 0.020783019394, -0.008248981557, -0.019686458368, 0.030194556929, -0.000581311209, -0.020507462528, -0.044154988493, 0.008251496795, 0.032183839802, 0.053024468712, -0.042724151114, 0.042587433931, -0.075197608106, 0.019796200862, -0.044058022099, -0.054716564872, 0.056900772003, -0.025187522741, 0.065664264024, -0.010713761704, 0.060761984311, -0.016047173875, 0.028406749588, -0.011879920533, -0.118533899059, 0.071371773260, -0.012801056424, 0.063748099223, -0.029818945809, 0.059673780884, 0.002981467618, 0.014900750827, 0.005863349123, -0.039271388965, -0.047804844624, -0.005476117492, -0.002941660427, -0.084269578445, -0.007723144927, -0.019565778540, 0.026971812744, -0.069210853637, 0.071362335146, -0.034155620576, 0.049871029844, 0.102419559566, -0.067458257439, 0.053173633928, -0.083831072696, 0.070644801531, -0.073425276208, 0.065129431849, -0.109383680801, 0.028592225091, 0.086994019490, -0.034044742467, 0.053289338054, -0.050965593897, 0.008752040612, -0.097246591796, 0.115066726542, -0.074721917181, 0.057622211485, 0.035793970560, -0.018555134605, -0.047793260188, -0.023063158221, -0.035765778569, 0.000988835923, 0.043336509870, -0.077241994534, 0.019293408578, 0.033162609969, 0.051320440605, -0.043008262694, 0.032451189832, -0.017267827022, -0.043257260696, 0.050857662915, -0.017938260516, -0.027199631897, 0.002448747593, 0.004648939335, -0.022984164695, -0.052488307553, 0.014620583398, 0.060946098284, -0.005975541627, 0.036790785823, -0.003976400632, -0.031985970920, 0.020296749161, 0.022385014193, -0.041326326661, -0.052361612870}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_rrrf_data_h4x256.c000066400000000000000000000265571474751757600246350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_rrrf_data_h4x256.c: autotest fftfilt data // float fftfilt_rrrf_data_h4x256_h[] = { -0.103940248489, -0.125938880444, 0.019687046111, 0.038741669059}; float fftfilt_rrrf_data_h4x256_x[] = { -0.059766334295, -0.066150742769, -0.115301787853, 0.034305834770, -0.116833734512, 0.037061965466, -0.058715832233, 0.103076207638, 0.134518480301, 0.079880267382, 0.012277089804, 0.043612530828, 0.034223002195, 0.113585817814, 0.069119685888, -0.130585312843, -0.169095098972, 0.012008042634, -0.133639252186, 0.173219811916, -0.083090245724, 0.129079174995, 0.023044827580, 0.088738435507, 0.102692329884, 0.009038489312, 0.159331941605, 0.072815608978, 0.078159433603, 0.087989467382, -0.150272154808, 0.144541347027, 0.013840167224, 0.008892998844, 0.118263459206, 0.026517456770, -0.071624934673, -0.036617729068, -0.005045709386, -0.113883030415, -0.208834385872, 0.086749321222, -0.013728235662, 0.043468075991, -0.096142125130, 0.020740854740, -0.034397336841, 0.085756975412, 0.007817015052, 0.026385569572, 0.146892285347, -0.156527042389, 0.141406416893, -0.023495438695, 0.049500951171, -0.035764679313, 0.071550452709, -0.003587320819, -0.186498534679, -0.080298507214, 0.134777379036, -0.081320983171, 0.001440288033, -0.026431754231, 0.076391905546, -0.008682205528, -0.218401527405, -0.006006127596, -0.150505733490, 0.031596601009, -0.030527853966, 0.192572534084, -0.008412856609, 0.041643416882, -0.028573197126, 0.172620558739, 0.092417323589, 0.038117933273, -0.115529227257, -0.017371174693, -0.128486943245, 0.049849176407, 0.064552265406, 0.094295257330, 0.016759039462, 0.093557018042, 0.020290662348, 0.005136798322, 0.054379999638, -0.015200743079, 0.015589100122, 0.080561774969, -0.027493861318, -0.097876155376, -0.090297585726, 0.048021733761, 0.026696670055, -0.154493343830, 0.041202291846, -0.082294452190, -0.036641538143, -0.046914353967, 0.022663275898, -0.076259374619, -0.156308090687, -0.068274164200, -0.126401603222, -0.200392508507, 0.018104647100, -0.017743445933, -0.141112804413, -0.159551227093, 0.075381636620, -0.220814013481, 0.038408300281, -0.004995152354, 0.010078751296, 0.040657266974, 0.056239426136, 0.085060149431, 0.068754714727, 0.072872400284, 0.106947481632, -0.308546304703, -0.069674599171, -0.112623000145, -0.063631707430, 0.078959625959, -0.228999781609, -0.113809764385, 0.038127812743, -0.046605563164, -0.048587369919, -0.235435414314, -0.217472290993, 0.053750389814, -0.035415196419, -0.067825865746, -0.150451087952, 0.047033441067, 0.091101139784, -0.194262254238, -0.111800551414, -0.285789370537, -0.007608364522, -0.149913394451, -0.096925151348, -0.305913662910, -0.080984199047, -0.036364766955, 0.092257493734, 0.099389094114, -0.225461554527, -0.044632428885, -0.025108575821, -0.014164578915, 0.001609388553, 0.104212951660, 0.016141586006, 0.131583070755, -0.175425446033, -0.006701639295, -0.114346027374, -0.035700270534, 0.021623027325, -0.127881789207, 0.100705778599, 0.045099687576, -0.037036603689, -0.068620997667, 0.104958283901, -0.153554320335, 0.094572162628, -0.042882648110, -0.064524829388, 0.009822543710, 0.113274049759, 0.060883563757, -0.039188215137, 0.073277068138, -0.110787749290, 0.098354798555, 0.109893596172, -0.042616480589, -0.014896343648, -0.040605995059, 0.127049469948, 0.003995794803, -0.061846542358, 0.016790096462, 0.079767954350, 0.026320463419, 0.049973765016, -0.133794248104, -0.014496140182, -0.245779371262, 0.112647521496, -0.046020454168, -0.190287458897, 0.154702842236, -0.087878227234, -0.094459164143, -0.189534711838, -0.055773961544, 0.065852761269, -0.046472328901, 0.110529434681, 0.073642146587, 0.123039674759, 0.047418674827, -0.039671051502, -0.026384806633, 0.050780695677, 0.001590615511, -0.054047483206, -0.081048285961, -0.063029623032, -0.083545958996, 0.075329506397, -0.047838664055, 0.040128618479, -0.104642879963, 0.093437254429, -0.038486540318, -0.082574462891, -0.065856921673, -0.071426254511, 0.019827936590, 0.133355295658, 0.094185638428, 0.077937924862, 0.060769236088, 0.125227236748, 0.128954041004, 0.119129931927, -0.007088107616, 0.067930990458, -0.097152686119, -0.086086273193, 0.029765573144, -0.162787938118, -0.091519236565, -0.078853517771, 0.116651356220, -0.025571110845, -0.151243126392, -0.166459095478, 0.048026204109, -0.046259659529, -0.216182160378, -0.018041458726, 0.014725986123, 0.130805134773, -0.088644373417, -0.039490658045, 0.067798143625}; float fftfilt_rrrf_data_h4x256_y[] = { 0.006212127638, 0.014402629871, 0.019138824386, 0.007337460817, 0.002990547175, 0.007070076667, 0.000464349934, -0.007115853714, -0.026683285355, -0.025489364937, -0.004694499360, 0.000704816717, -0.005713266142, -0.014781907855, -0.019125815998, 0.008430239467, 0.039782821314, 0.020154501439, 0.003990141650, -0.007488755965, -0.015344438902, -0.004719450259, -0.013576348764, -0.012803601954, -0.016395058243, -0.011232627125, -0.012239715093, -0.023478145421, -0.013807285781, -0.011382649065, 0.008897756697, 0.008661723023, -0.019191481858, -0.005643557602, -0.007540062613, -0.016938930639, 0.006777922483, 0.017930194135, 0.004753295233, 0.008976717035, 0.034530632258, 0.014846123076, -0.018021547028, -0.009171918769, 0.007609260636, 0.010276125260, 0.000754459077, -0.007898019473, -0.011486286587, -0.003371297493, -0.015114727435, -0.001407692146, 0.008929118567, -0.012757146890, -0.005466396146, 0.002499060105, -0.002868533164, -0.007424468314, 0.019859520897, 0.034535023664, -0.007706674216, -0.017327293951, 0.009634239964, 0.006186465510, -0.007733563710, -0.009182844461, 0.024274056965, 0.030918145186, 0.011763964249, 0.007090882408, -0.004001868553, -0.021380192871, -0.022754833149, -0.000660437013, 0.005020336999, -0.013849839551, -0.030294705862, -0.013309506170, 0.015714639418, 0.020686016629, 0.014744994233, 0.006182383795, -0.016190044652, -0.021927128113, -0.010415294145, -0.007477696788, -0.009908390960, -0.000598168905, -0.002275175069, -0.004381364749, 0.001563619326, -0.008529370506, -0.007570139794, 0.015825789161, 0.024291791638, 0.003388535453, -0.014392240260, 0.010143054713, 0.017560162996, 0.001357491276, 0.008998423176, 0.009466994781, -0.000356873396, 0.002729071359, 0.024479354632, 0.026158390848, 0.015704925808, 0.029347970586, 0.018221877386, -0.009277966443, 0.009494776448, 0.034707471003, 0.008793011874, 0.004849946576, 0.019119662287, -0.005744666206, -0.008217061474, -0.004105571223, -0.010960970310, -0.014733014296, -0.015176443566, -0.012379874872, -0.015644666925, 0.022699848187, 0.051028649748, 0.018549762248, 0.007472224160, -0.005109901608, 0.008242283953, 0.039758674555, 0.008920758417, -0.011069992067, 0.007261079530, 0.031149863671, 0.049492477364, 0.015284004318, -0.016490747527, 0.004142934403, 0.025564996273, 0.011351639261, -0.020982038768, 0.003815714690, 0.039701414255, 0.043490014719, 0.027055742092, 0.006582535902, 0.017732605940, 0.040757274537, 0.039227876953, 0.004201243751, -0.018455474336, -0.025802710495, 0.011325024528, 0.038564368478, 0.007642577107, -0.004979021836, -0.000606857515, -0.012286211537, -0.015319298242, -0.013595634758, 0.006017503669, 0.026005288293, 0.014373290385, 0.011183095605, -0.000262218936, 0.005436096272, 0.004680511180, -0.019050348257, -0.004801965020, 0.016586221529, -0.001249242642, -0.000043659144, 0.008916431699, -0.006409851067, 0.008020215359, 0.009924877896, -0.015942421690, -0.022900282471, -0.000983801859, 0.002905926546, 0.003874104947, 0.003653855068, -0.023151268515, -0.011766095752, 0.012889310865, 0.009515094775, -0.010035978512, -0.017792313224, 0.006853203808, 0.011044491421, -0.011468398919, -0.014847133247, -0.006288183493, 0.011221483243, 0.020360164728, 0.026674050122, 0.013775768815, -0.014803599781, 0.018270084125, 0.011342883867, -0.015878125160, 0.016558982776, 0.035859750030, 0.024402777719, -0.007211526384, -0.011903993248, -0.006500113845, -0.019937993274, -0.021687601373, -0.014692296619, 0.003426871553, 0.013438867168, -0.000899212332, -0.008616954586, 0.005394918949, 0.017229501936, 0.015756032882, 0.012932176847, -0.001688896039, -0.008601197014, 0.000100074788, 0.007799442483, 0.002403379977, -0.008272542196, 0.011215225703, 0.020106749108, 0.012601329561, 0.002438821104, -0.020315669734, -0.028961114111, -0.016568981922, -0.009111140762, -0.015486083309, -0.024958681018, -0.023803066262, -0.006876114273, 0.001173115553, 0.006018669947, 0.022245884571, 0.008466878338, 0.007712934138, 0.027264733171, 0.017670238763, -0.010302467061, -0.017131074405, 0.018182248950, 0.040365038360, 0.012003618618, -0.010376624909, 0.022792508105, 0.030050872208, -0.005306666123, -0.024180933161, -0.007668779085, 0.018414117957, 0.001248916742}; liquid-dsp-1.7.0/src/filter/tests/data/fftfilt_rrrf_data_h7x256.c000066400000000000000000000266531474751757600246350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fftfilt_rrrf_data_h7x256.c: autotest fftfilt data // float fftfilt_rrrf_data_h7x256_h[] = { 0.140616559982, -0.011992717534, -0.003013938852, -0.011477991939, -0.112187731266, -0.093354654312, 0.074616163969}; float fftfilt_rrrf_data_h7x256_x[] = { -0.198634433746, -0.276704359055, -0.007436756045, -0.029181697965, -0.130730390549, 0.145140337944, 0.093274253607, -0.028276038170, -0.026093566418, 0.183164799213, 0.053475326300, -0.103025162220, 0.062650483847, -0.188771390915, -0.037113583088, 0.002068812773, -0.008017702401, -0.109960675240, -0.077615725994, 0.026018035412, -0.109660518169, -0.170424306393, -0.037413102388, 0.057296097279, -0.017119997740, -0.108221471310, -0.035699757934, 0.091696447134, -0.179859602451, 0.172208881378, 0.047351920605, 0.009508173168, 0.096329414845, 0.048371517658, -0.020774090290, 0.017976391315, -0.049352347851, -0.049652296305, -0.076197183132, -0.059912049770, 0.049865084887, -0.183295714855, 0.092628794909, -0.026747608185, 0.013366179168, -0.097838991880, 0.071832561493, -0.057548421621, 0.150674271584, 0.204948568344, 0.068133813143, 0.134078955650, 0.147824907303, 0.023681402206, 0.074496239424, -0.257152867317, -0.046538749337, 0.077637636662, 0.244811058044, 0.205812954903, 0.076498079300, 0.050237774849, 0.058088797331, 0.058162277937, -0.003535797447, 0.002892631851, -0.204548168182, 0.005657804012, 0.103203463554, 0.142777621746, -0.033477127552, 0.199837732315, -0.027476757765, -0.044394394755, -0.060066252947, -0.104752016068, -0.097709661722, -0.130706298351, 0.032775890827, -0.018839289248, 0.050399136543, 0.028471961617, -0.059291934967, 0.089571076632, -0.172548770905, -0.012040051073, 0.020502640307, -0.123626136780, -0.026196390390, -0.020364558697, -0.019754604995, -0.057270252705, -0.317011761665, -0.067777991295, -0.081966227293, 0.051007336378, 0.005001089722, -0.059572064877, -0.246018052101, 0.084007954597, 0.111875116825, -0.105674767494, -0.093867790699, 0.124696004391, -0.114728307724, 0.145655667782, 0.087596571445, 0.031920900941, -0.048701521754, -0.036635088921, 0.078258597851, -0.174296259880, 0.001777398773, -0.011556741595, 0.016063742340, -0.122294688225, -0.062106817961, -0.083234494925, -0.093048858643, -0.132832098007, -0.130951321125, -0.075790464878, 0.107826757431, 0.065403455496, -0.021866463125, 0.076470321417, -0.115176773071, -0.177813613415, 0.007404306531, 0.034460625052, 0.091559529305, 0.025584965944, -0.233118081093, 0.016783872247, 0.118527340889, 0.002443835139, -0.066102498770, 0.099924069643, 0.110413837433, 0.012530249357, 0.039682874084, -0.102561068535, -0.070982843637, -0.224049115181, -0.046074494720, -0.053951752186, -0.024024085701, -0.020918877423, -0.049386295676, -0.124434947968, 0.201082754135, -0.082364642620, -0.069723898172, -0.077210056782, -0.078793448210, 0.021326577663, -0.029980614781, 0.095146137476, 0.002052852511, 0.121688973904, 0.231916475296, 0.069326949120, -0.106731951237, 0.110438179970, 0.032615479827, -0.039900502563, 0.014169178903, 0.135481488705, 0.150449824333, -0.034293845296, -0.125741934776, 0.137323367596, -0.073314142227, -0.256729173660, -0.066909456253, -0.035936996341, -0.142958796024, -0.140863418579, -0.085215097666, -0.066673463583, 0.035038682818, -0.087599039078, -0.024130514264, 0.142523336411, 0.051653099060, 0.186094677448, -0.169976019859, 0.064971995354, 0.007105557621, -0.083290928602, -0.028115510941, -0.012801435590, -0.001878900640, -0.234911966324, -0.035020393133, 0.021636278927, 0.075562286377, 0.018644069135, -0.081580567360, -0.153186178207, 0.046364918351, -0.053498959541, -0.063731038570, -0.168667137623, -0.226871848106, 0.215677857399, 0.166028416157, -0.072063165903, -0.145152175426, 0.010212332010, -0.216380715370, -0.124420678616, 0.041640162468, -0.019694516063, -0.128491973877, -0.063744425774, 0.036548280716, -0.048697099090, 0.177138936520, 0.101957058907, 0.200418853760, -0.044115161896, -0.081440508366, 0.134256255627, 0.034881916642, -0.016943645477, 0.056465440989, -0.041392689943, 0.020602276921, 0.080228483677, 0.113952696323, 0.142240214348, 0.065034645796, 0.036655876040, -0.010240229964, 0.075093430281, 0.116919255257, -0.045885655284, -0.016456852853, -0.016743476689, 0.059479594231, -0.071723133326, 0.004458283633, 0.177911329269, -0.114906835556, -0.055673146248, -0.121907567978, 0.113892269135, -0.031124478579, 0.026398393512, 0.121518325806, -0.129203355312, 0.013991312683, -0.047266671062, -0.165797197819, 0.099366217852}; float fftfilt_rrrf_data_h7x256_y[] = { -0.027931290767, -0.036527048446, 0.002871378203, -0.000900348620, 0.007449880861, 0.071736541733, 0.023948851395, -0.020710146276, 0.011558567506, 0.018827456694, -0.028042283949, -0.010086450022, 0.020308556524, -0.047821747894, -0.027006769038, 0.020818889038, 0.007705728630, -0.007304606298, 0.016866205381, -0.005839934759, -0.016298973644, -0.008597800781, 0.015189446945, 0.006399836981, 0.003056670822, 0.016542526688, 0.007596592949, -0.001806787749, -0.031260991935, 0.044520387756, 0.016913430809, -0.012715020434, 0.020266125790, 0.009387467377, -0.038709991484, 0.008887802636, -0.015809331270, -0.019915827876, -0.005174084562, -0.003262775658, 0.010838392511, -0.013798289642, 0.025261915119, 0.005237958158, -0.001661751700, -0.003462670878, 0.021981362166, -0.028135663622, 0.030693053673, 0.034093858112, 0.009401595589, 0.008139424059, 0.010449388245, -0.040981872086, -0.007327036366, -0.044931617778, -0.027973650948, 0.004942790683, 0.037047060381, 0.049966777634, 0.041445787750, -0.020836545762, -0.033212295434, -0.033698438557, -0.011475301474, 0.002186574921, -0.034953267018, -0.004918868576, 0.014328874613, 0.025515369387, 0.015618207275, 0.045563709091, -0.035167131438, -0.031361372075, -0.011997409010, -0.022200908255, -0.029863902791, 0.006254205122, 0.016506100233, 0.012520079323, 0.024973348930, 0.019048886905, -0.007380278502, 0.001942907036, -0.026935332102, -0.008518025534, 0.010273786799, -0.018002092298, 0.004447210446, 0.021730271212, -0.015086741356, 0.003602761453, -0.027587176784, -0.009823822714, -0.006937488555, 0.018748089942, 0.040553778014, 0.025275375143, -0.042611521568, 0.011757676443, 0.004710422831, -0.003608358999, 0.020301233199, 0.026791678092, -0.054882770430, 0.030238791621, 0.038228983560, -0.008795472799, -0.014940802385, -0.001995096866, -0.020761276696, -0.025668476061, 0.011544716840, 0.009019018042, -0.004600880195, -0.007860348130, 0.014728952731, -0.022649831750, -0.011085775543, -0.005240739986, 0.003997918140, -0.001607881215, 0.031565581702, 0.027013196139, 0.016834464421, 0.020396729202, -0.032590176622, -0.046660538625, 0.007036097494, 0.004957313420, 0.018631105443, 0.038717489292, -0.026583582426, -0.013797276939, 0.003938127652, -0.007299187180, 0.020722040319, 0.035264671435, -0.017759711601, -0.009191541583, 0.019981890768, -0.021059713833, -0.035662571010, -0.035057540677, 0.000216222158, 0.003192531187, 0.020478284609, 0.022147450700, 0.014786561310, -0.022930234264, 0.034450785115, -0.012487537726, -0.002293520691, 0.004929010876, -0.023625633332, -0.013839752803, 0.027167472950, 0.023604122988, 0.009838224295, 0.016346254731, 0.025546898715, 0.000292790611, -0.029285103586, 0.007194347038, -0.034437467230, -0.025457756182, 0.023911766892, 0.021373937942, -0.001986685444, 0.002474461915, -0.014709692341, -0.000304917342, -0.039652662083, -0.034280490433, 0.020849251951, -0.008861922819, -0.030500204522, 0.028675656081, 0.016552898220, -0.015166145728, 0.022000859239, 0.014908498909, 0.010360380914, 0.025116858815, 0.002567172058, 0.026977540816, -0.014425407319, -0.010252117168, -0.022304314803, -0.025107189270, 0.001828790258, 0.021171226565, -0.018615482629, -0.019119842628, 0.009505383997, 0.002038013339, 0.012475689592, 0.027626671729, 0.013547534561, -0.038171874263, -0.004721419960, -0.014212116960, 0.006348483281, 0.002868666481, -0.026061180698, 0.024531926129, 0.038983308893, 0.010709672428, 0.013920220038, -0.014113848161, -0.084973755410, -0.004587206797, 0.043282508352, 0.006617714415, -0.004038115641, 0.027079484275, -0.002684682004, -0.016580593774, 0.045475009133, 0.029616879939, 0.019247518497, -0.013652480208, -0.025296757973, -0.013920765792, -0.014738586605, -0.008423961018, 0.034706519850, -0.017597737374, -0.019105819963, 0.019173187919, 0.013324282832, 0.016264621044, 0.011940905269, -0.011374704130, -0.022444725917, -0.010784037503, 0.003078174417, -0.007533459622, -0.000398654282, -0.008094217007, -0.011750423046, -0.010723392199, 0.016353940211, 0.024488199896, -0.023819390187, -0.005793482451, -0.007536630407, -0.006763537688, -0.008121110474, 0.035389300910, 0.025857426716, -0.024898575974, -0.013389203604, 0.000622597391, -0.039725817044, 0.021063238241}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_cccf_data_M2h4x20.c000066400000000000000000000057721474751757600250040ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_cccf_data_M2h4x20.c: autotest firdecim data // #include float complex firdecim_cccf_data_M2h4x20_h[] = { -0.010020822840 + 0.161896349165*_Complex_I, -0.160666600378 + -0.002813281324*_Complex_I, 0.074990149666 + -0.043630565869*_Complex_I, -0.147489652317 + -0.117556939153*_Complex_I}; float complex firdecim_cccf_data_M2h4x20_x[] = { -0.062219283216 + 0.083707729807*_Complex_I, 0.142772365864 + -0.155087351763*_Complex_I, -0.035707773590 + -0.015572103950*_Complex_I, 0.031591519635 + -0.047093660211*_Complex_I, -0.037688362501 + -0.218679837029*_Complex_I, -0.138226220905 + 0.033491576346*_Complex_I, 0.021866054096 + -0.113640931250*_Complex_I, 0.067925963478 + 0.054442249893*_Complex_I, 0.057780733571 + -0.143139771263*_Complex_I, -0.066200531759 + -0.072426438814*_Complex_I, -0.024130609496 + -0.023984088453*_Complex_I, 0.021066337898 + 0.123433455812*_Complex_I, 0.036017867444 + 0.011208051823*_Complex_I, 0.151336512188 + -0.046531046794*_Complex_I, -0.073914188474 + -0.026770749988*_Complex_I, -0.035715003742 + -0.020256147810*_Complex_I, -0.126178961558 + 0.049437469177*_Complex_I, -0.105599807940 + -0.032488566671*_Complex_I, 0.008377427496 + -0.015424316799*_Complex_I, -0.115074264949 + 0.025508983239*_Complex_I}; float complex firdecim_cccf_data_M2h4x20_y[] = { -0.012928487438 + -0.010911895131*_Complex_I, -0.021509784691 + 0.027882703574*_Complex_I, -0.012073246090 + 0.010047339289*_Complex_I, 0.017918504479 + -0.011835742405*_Complex_I, 0.032840148626 + 0.003684533788*_Complex_I, 0.009026607516 + -0.021113482694*_Complex_I, -0.006819209614 + 0.003546692017*_Complex_I, -0.004777468860 + -0.026060577544*_Complex_I, -0.035559582789 + -0.027278788500*_Complex_I, 0.014869302818 + 0.023426450224*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_cccf_data_M3h7x30.c000066400000000000000000000072041474751757600250010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_cccf_data_M3h7x30.c: autotest firdecim data // #include float complex firdecim_cccf_data_M3h7x30_h[] = { -0.006640626991 + 0.118904206653*_Complex_I, -0.083146000558 + -0.275130943103*_Complex_I, 0.079550052655 + 0.061532677877*_Complex_I, 0.065868508847 + 0.151901113121*_Complex_I, 0.044201174511 + 0.012455933659*_Complex_I, 0.055782888955 + 0.071073047549*_Complex_I, -0.102933394297 + -0.076862023914*_Complex_I}; float complex firdecim_cccf_data_M3h7x30_x[] = { 0.069053975334 + -0.000060226964*_Complex_I, 0.052934817246 + 0.026246887839*_Complex_I, -0.008314557685 + 0.123860251104*_Complex_I, 0.013641467876 + -0.040765094693*_Complex_I, 0.054181459433 + 0.105277320749*_Complex_I, 0.068589348571 + -0.094171049027*_Complex_I, -0.186652190115 + -0.131382418642*_Complex_I, -0.166555782200 + 0.069458887805*_Complex_I, 0.041855583632 + -0.063553427322*_Complex_I, -0.100690278440 + -0.092501422890*_Complex_I, 0.083259362864 + -0.058212988803*_Complex_I, 0.105969639897 + -0.053978459405*_Complex_I, -0.056835014832 + -0.111112267168*_Complex_I, 0.030289623782 + -0.152387642602*_Complex_I, 0.065445845678 + -0.096149080571*_Complex_I, 0.111690055005 + -0.006676373032*_Complex_I, -0.003193339244 + -0.073652552575*_Complex_I, -0.250738405778 + 0.063945369804*_Complex_I, 0.082690418566 + 0.008257821532*_Complex_I, -0.012580995920 + -0.092904421381*_Complex_I, -0.042140374030 + -0.035352352256*_Complex_I, -0.102518977358 + -0.014894177307*_Complex_I, -0.080456903607 + -0.102303385723*_Complex_I, 0.067967690554 + -0.008961243903*_Complex_I, -0.008051789902 + -0.288191500473*_Complex_I, 0.052113077407 + 0.045119892331*_Complex_I, 0.026292838395 + -0.234398783970*_Complex_I, 0.043314256874 + 0.060501473229*_Complex_I, -0.063513872529 + -0.087941912765*_Complex_I, -0.065933510466 + 0.101592986516*_Complex_I}; float complex firdecim_cccf_data_M3h7x30_y[] = { -0.000451400453 + 0.008211208098*_Complex_I, 0.046679220394 + 0.009712412319*_Complex_I, -0.017763427623 + -0.015970470090*_Complex_I, -0.023951776164 + -0.049756621013*_Complex_I, 0.005079568893 + -0.033963764074*_Complex_I, 0.010470512110 + -0.004032766261*_Complex_I, 0.063479867902 + 0.089940072424*_Complex_I, -0.013695440245 + -0.005147235363*_Complex_I, 0.018210209849 + -0.062011233592*_Complex_I, -0.014235918784 + 0.002032286514*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_cccf_data_M4h13x40.c000066400000000000000000000106501474751757600250570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_cccf_data_M4h13x40.c: autotest firdecim data // #include float complex firdecim_cccf_data_M4h13x40_h[] = { -0.002562542003 + -0.154124323834*_Complex_I, -0.023583498668 + 0.104733275459*_Complex_I, 0.022367426058 + -0.120923475320*_Complex_I, -0.132621145254 + -0.178735883634*_Complex_I, -0.168112709779 + 0.034712075125*_Complex_I, 0.057724042805 + 0.008285579385*_Complex_I, -0.047739385482 + 0.142477282131*_Complex_I, 0.067869682601 + 0.097364083820*_Complex_I, 0.059426213111 + 0.468175487351*_Complex_I, 0.006482342651 + -0.003418897658*_Complex_I, -0.004209444510 + -0.083952075513*_Complex_I, 0.011361818419 + -0.070937481458*_Complex_I, 0.094086356591 + -0.103332276920*_Complex_I}; float complex firdecim_cccf_data_M4h13x40_x[] = { -0.024194231006 + -0.138925187631*_Complex_I, 0.203856156849 + -0.080078393335*_Complex_I, -0.068961728054 + 0.201298529466*_Complex_I, -0.051809449253 + 0.046347258011*_Complex_I, -0.149903686678 + -0.212870505681*_Complex_I, 0.029836494947 + -0.048639942573*_Complex_I, 0.037533241642 + -0.206079736569*_Complex_I, 0.051371569347 + -0.039092683420*_Complex_I, -0.090350663461 + 0.047672789069*_Complex_I, -0.156001075276 + 0.148239674685*_Complex_I, 0.151211606918 + -0.081137753153*_Complex_I, 0.014410288934 + -0.091766222951*_Complex_I, 0.128650669104 + -0.109361279278*_Complex_I, -0.014454025380 + -0.017884354391*_Complex_I, -0.027777545721 + 0.014889779800*_Complex_I, -0.102482421038 + 0.153280094094*_Complex_I, 0.054231085410 + -0.036048916993*_Complex_I, -0.097774825326 + 0.071640661283*_Complex_I, 0.016069399348 + -0.072264453423*_Complex_I, -0.020335452514 + -0.102705025246*_Complex_I, -0.001428129588 + 0.058319600411*_Complex_I, 0.050490262274 + 0.068382581850*_Complex_I, 0.037146918761 + -0.014078089282*_Complex_I, 0.131825401964 + -0.052212284043*_Complex_I, -0.021358931115 + 0.034076612121*_Complex_I, 0.007883745543 + -0.045225145346*_Complex_I, 0.066077716475 + -0.011748246722*_Complex_I, 0.020987892322 + 0.148992296687*_Complex_I, 0.046814707826 + -0.080934756420*_Complex_I, 0.092525039263 + 0.149989890332*_Complex_I, 0.063112963675 + -0.084774798237*_Complex_I, -0.019463083228 + 0.059819778564*_Complex_I, -0.026299503842 + -0.005553793151*_Complex_I, 0.135276140520 + -0.011249885171*_Complex_I, -0.055971818305 + -0.061539002690*_Complex_I, 0.041589677363 + 0.218745686754*_Complex_I, -0.154541640002 + 0.176344746584*_Complex_I, -0.093756310243 + 0.038311802363*_Complex_I, 0.075234897328 + 0.138257000400*_Complex_I, -0.097930194448 + -0.076486145877*_Complex_I}; float complex firdecim_cccf_data_M4h13x40_y[] = { -0.021349751874 + 0.004084921123*_Complex_I, -0.045716199011 + 0.026670647628*_Complex_I, 0.062793796326 + 0.020298966406*_Complex_I, 0.171764657602 + -0.129296598427*_Complex_I, -0.140510571307 + -0.025391053246*_Complex_I, 0.078880319262 + 0.080737389437*_Complex_I, 0.026829099733 + -0.015427110029*_Complex_I, -0.058971359279 + -0.004947680884*_Complex_I, -0.009091338962 + -0.022653029705*_Complex_I, 0.017223757651 + 0.057653177650*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_cccf_data_M5h23x50.c000066400000000000000000000126201474751757600250610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_cccf_data_M5h23x50.c: autotest firdecim data // #include float complex firdecim_cccf_data_M5h23x50_h[] = { 0.105720400924 + 0.057437069192*_Complex_I, -0.028209083196 + -0.004313504575*_Complex_I, -0.072874560021 + 0.042888303750*_Complex_I, -0.085512857926 + 0.020535437583*_Complex_I, -0.100456191359 + 0.103253822583*_Complex_I, 0.021202177209 + 0.035197979854*_Complex_I, -0.181412547496 + -0.065280832354*_Complex_I, -0.089735489990 + -0.035169413725*_Complex_I, 0.091350151539 + 0.024388575583*_Complex_I, 0.115625359788 + -0.072145623875*_Complex_I, -0.051852629863 + -0.004567932396*_Complex_I, 0.009526328844 + -0.150554350114*_Complex_I, 0.111472545344 + 0.100620569627*_Complex_I, 0.072732704374 + -0.028216475627*_Complex_I, -0.041864189108 + 0.010588416120*_Complex_I, 0.050598746124 + -0.003896637950*_Complex_I, -0.118777133157 + 0.070610240227*_Complex_I, -0.016104655770 + 0.004328632751*_Complex_I, 0.057125599610 + 0.100422001833*_Complex_I, 0.154824278727 + -0.040505357012*_Complex_I, 0.019585396789 + 0.108879628006*_Complex_I, 0.052374918456 + -0.044109539660*_Complex_I, 0.013011637257 + -0.076892387668*_Complex_I}; float complex firdecim_cccf_data_M5h23x50_x[] = { -0.045706059285 + -0.026925548272*_Complex_I, 0.074640818692 + 0.020008220501*_Complex_I, -0.041286610033 + -0.136882935267*_Complex_I, 0.009816935182 + -0.078646240225*_Complex_I, 0.089010380616 + -0.149190270600*_Complex_I, 0.083497556154 + -0.043557829025*_Complex_I, 0.182551809767 + -0.029983057525*_Complex_I, 0.156019880201 + 0.005770028753*_Complex_I, 0.061786541086 + -0.064921440736*_Complex_I, 0.243601293648 + 0.048234370911*_Complex_I, -0.038392905410 + 0.026874189965*_Complex_I, 0.098986088062 + -0.051036508330*_Complex_I, 0.145073787044 + 0.133408806994*_Complex_I, -0.012274691331 + -0.001003240627*_Complex_I, -0.047977493556 + 0.090394581449*_Complex_I, 0.067234934373 + -0.080081570574*_Complex_I, -0.066259448979 + 0.124203939183*_Complex_I, -0.107414957417 + -0.017911178063*_Complex_I, -0.035170912051 + -0.011180346308*_Complex_I, 0.087106081663 + 0.108450957223*_Complex_I, -0.071732901242 + -0.054445545216*_Complex_I, -0.027106150089 + 0.035717288781*_Complex_I, 0.008967266976 + -0.124029666988*_Complex_I, -0.027842462142 + 0.016454828477*_Complex_I, 0.035515455355 + 0.042131771080*_Complex_I, 0.012844114428 + 0.106011213637*_Complex_I, 0.081631987459 + 0.062426819327*_Complex_I, 0.130657890629 + -0.002602075127*_Complex_I, -0.094246564430 + -0.033523978166*_Complex_I, -0.053733329944 + 0.108359828647*_Complex_I, -0.005664508011 + 0.021469330759*_Complex_I, -0.014929153350 + 0.017941698073*_Complex_I, 0.020461861960 + -0.100937164479*_Complex_I, 0.001605545133 + 0.153966424471*_Complex_I, -0.042286310689 + -0.074770813879*_Complex_I, 0.171684109561 + 0.076554260668*_Complex_I, 0.175238329863 + 0.075856527238*_Complex_I, 0.060276983038 + -0.075910005194*_Complex_I, 0.009291016375 + -0.012009065640*_Complex_I, 0.165631852407 + -0.056358816657*_Complex_I, 0.022403278379 + -0.053838057764*_Complex_I, 0.012578774881 + -0.028070849755*_Complex_I, 0.111896323878 + -0.067413483086*_Complex_I, 0.193577629326 + 0.022715731850*_Complex_I, -0.024575467522 + -0.001589364951*_Complex_I, 0.049219675943 + -0.168094546969*_Complex_I, -0.052368096464 + 0.158302243383*_Complex_I, 0.029964399158 + -0.012022357247*_Complex_I, 0.126368745124 + 0.002307518720*_Complex_I, 0.014850257877 + 0.006988676981*_Complex_I}; float complex firdecim_cccf_data_M5h23x50_y[] = { -0.003285538333 + -0.005471801848*_Complex_I, 0.007588480326 + 0.024542591101*_Complex_I, -0.057029837651 + 0.045181309977*_Complex_I, -0.052759259646 + -0.065315303001*_Complex_I, 0.096950584899 + -0.077249583961*_Complex_I, 0.000722131494 + 0.033051673725*_Complex_I, 0.010653757445 + -0.053755642413*_Complex_I, 0.037166575400 + 0.001442464438*_Complex_I, 0.015685676896 + 0.008079773457*_Complex_I, -0.025642858413 + 0.014281592109*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_crcf_data_M2h4x20.c000066400000000000000000000055721474751757600250210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_crcf_data_M2h4x20.c: autotest firdecim data // #include float firdecim_crcf_data_M2h4x20_h[] = { 0.031235809409, -0.216021656042, -0.123125426658, 0.014724190886}; float complex firdecim_crcf_data_M2h4x20_x[] = { -0.121360059018 + -0.040946328225*_Complex_I, -0.048183917318 + -0.090893384286*_Complex_I, 0.050431539967 + -0.039477767743*_Complex_I, -0.092873851447 + -0.016290157417*_Complex_I, 0.067927836995 + 0.034766499357*_Complex_I, -0.062738323035 + -0.070124552362*_Complex_I, -0.089685845706 + 0.085063483262*_Complex_I, 0.036320846361 + 0.192249836854*_Complex_I, -0.097540647206 + -0.078675689987*_Complex_I, 0.062450869382 + 0.091837474249*_Complex_I, -0.062450045345 + -0.029363766863*_Complex_I, -0.030191356564 + 0.094898259922*_Complex_I, 0.130002759179 + -0.034950407712*_Complex_I, 0.030652983878 + 0.015398314893*_Complex_I, -0.028490871597 + 0.130293581637*_Complex_I, 0.114396819866 + -0.058213046230*_Complex_I, -0.090569184709 + -0.080687388201*_Complex_I, -0.002440656567 + 0.093805498501*_Complex_I, 0.181551012573 + 0.015635958339*_Complex_I, 0.081568978667 + 0.051967040191*_Complex_I}; float complex firdecim_crcf_data_M2h4x20_y[] = { -0.003790779673 + -0.001278991704*_Complex_I, 0.026926548630 + 0.023443353500*_Complex_I, 0.015265670091 + 0.008127371986*_Complex_I, 0.001020290227 + 0.013284949227*_Complex_I, -0.000774013472 + -0.055493631953*_Complex_I, -0.002896889061 + -0.008238383106*_Complex_I, 0.019191455251 + -0.016624124713*_Complex_I, -0.023962832263 + 0.006444039955*_Complex_I, -0.023581901158 + -0.005760782332*_Complex_I, 0.019033897622 + -0.010698088224*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_crcf_data_M3h7x30.c000066400000000000000000000066521474751757600250260ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_crcf_data_M3h7x30.c: autotest firdecim data // #include float firdecim_crcf_data_M3h7x30_h[] = { -0.067137698321, 0.054412252965, -0.182856503708, -0.054617127674, -0.009870765494, -0.026617010237, 0.011725565067}; float complex firdecim_crcf_data_M3h7x30_x[] = { -0.088297122268 + 0.055665944654*_Complex_I, -0.016432697221 + 0.148455554729*_Complex_I, 0.140757522457 + 0.073543902343*_Complex_I, 0.063460474341 + 0.032803595179*_Complex_I, -0.010344707877 + -0.062988102121*_Complex_I, 0.039529652200 + -0.054529222034*_Complex_I, 0.119571808389 + -0.098769254813*_Complex_I, 0.014024766895 + -0.018877394409*_Complex_I, 0.075151006910 + -0.136112320307*_Complex_I, 0.167466666363 + 0.037009456983*_Complex_I, -0.006066715214 + 0.052827861682*_Complex_I, 0.048336909246 + -0.157938756841*_Complex_I, 0.022542224668 + 0.123894877722*_Complex_I, -0.109162126495 + -0.080322251267*_Complex_I, 0.060401040885 + -0.013549823453*_Complex_I, -0.065450090580 + 0.134084060551*_Complex_I, 0.080552956850 + -0.129409082705*_Complex_I, -0.054479718117 + -0.047011198746*_Complex_I, 0.186369060662 + -0.125658475188*_Complex_I, -0.191665411586 + -0.030921221765*_Complex_I, 0.063129882080 + 0.100182552563*_Complex_I, 0.065520569371 + -0.107290345371*_Complex_I, 0.146258184364 + -0.041133067761*_Complex_I, 0.048045169203 + 0.040835459595*_Complex_I, 0.006679291241 + 0.024648912594*_Complex_I, 0.038593404874 + -0.254488576034*_Complex_I, -0.176346189965 + -0.001937288661*_Complex_I, -0.171141933206 + -0.024023949503*_Complex_I, 0.216869453975 + 0.054039885226*_Complex_I, 0.165978694869 + -0.091956658785*_Complex_I}; float complex firdecim_crcf_data_M3h7x30_y[] = { 0.005928065557 + -0.003737283399*_Complex_I, 0.011225704498 + -0.028387046159*_Complex_I, -0.009438639157 + 0.009365565615*_Complex_I, -0.015620112302 + 0.001554880391*_Complex_I, -0.006633571221 + -0.027905221566*_Complex_I, 0.028058535196 + -0.001231894454*_Complex_I, -0.024058004824 + 0.025942864482*_Complex_I, 0.021530701506 + 0.030652367492*_Complex_I, -0.021493289366 + 0.012309152915*_Complex_I, -0.009126109290 + 0.046129860989*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_crcf_data_M4h13x40.c000066400000000000000000000100321474751757600250700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_crcf_data_M4h13x40.c: autotest firdecim data // #include float firdecim_crcf_data_M4h13x40_h[] = { -0.017634479811, 0.078644323992, 0.010062975901, 0.002767448419, -0.012666798459, 0.072474187801, 0.138641311321, 0.096895207192, 0.005424669952, -0.095669120702, 0.115011527536, 0.045576979285, -0.032175124851}; float complex firdecim_crcf_data_M4h13x40_x[] = { -0.112962750920 + -0.174396579717*_Complex_I, 0.036553706748 + -0.051072169083*_Complex_I, 0.022797265387 + 0.042572931849*_Complex_I, 0.008765340086 + 0.005707935306*_Complex_I, 0.106501635473 + -0.087740150292*_Complex_I, -0.021475975887 + 0.041386858553*_Complex_I, -0.140639585019 + 0.075707242551*_Complex_I, -0.170100822245 + 0.024811268189*_Complex_I, 0.077084240435 + 0.022103264096*_Complex_I, -0.034031018357 + 0.008016611966*_Complex_I, 0.042615847754 + -0.119291859183*_Complex_I, 0.004089922446 + 0.056510429034*_Complex_I, 0.145879823424 + 0.102239060582*_Complex_I, 0.131816984427 + -0.085645947698*_Complex_I, -0.118561232326 + 0.150671338454*_Complex_I, -0.032855598424 + 0.084885603624*_Complex_I, -0.029028910328 + 0.095508389514*_Complex_I, 0.162474927440 + -0.002144805045*_Complex_I, -0.066178053685 + -0.010931400887*_Complex_I, -0.164098083762 + -0.014709199385*_Complex_I, -0.042421547313 + -0.165166102873*_Complex_I, -0.143613555453 + -0.020483960094*_Complex_I, 0.074273402726 + 0.026166548871*_Complex_I, 0.039546848666 + 0.060817356400*_Complex_I, -0.283154531123 + -0.068141024882*_Complex_I, -0.171382954008 + 0.157655929741*_Complex_I, 0.100887524169 + -0.227019774244*_Complex_I, -0.134270894830 + -0.095892207602*_Complex_I, 0.061905242843 + -0.098697402618*_Complex_I, 0.070002196277 + 0.099716632447*_Complex_I, -0.111631217405 + -0.033672309864*_Complex_I, -0.042616607537 + -0.111931082366*_Complex_I, -0.004433766647 + -0.118350103892*_Complex_I, -0.029922536821 + 0.288101612082*_Complex_I, 0.112347437422 + 0.012061775097*_Complex_I, 0.121008925435 + 0.081465180909*_Complex_I, -0.022480348602 + 0.032724942501*_Complex_I, -0.057932648610 + 0.146711091659*_Complex_I, 0.091043924052 + -0.118961124120*_Complex_I, -0.060921349688 + -0.036527277081*_Complex_I}; float complex firdecim_crcf_data_M4h13x40_y[] = { 0.001992039351 + 0.003075392964*_Complex_I, 0.000572688534 + 0.004492265743*_Complex_I, -0.010835528800 + 0.003970601587*_Complex_I, -0.029138197244 + 0.024645444782*_Complex_I, -0.005729955161 + 0.004471983412*_Complex_I, -0.016781980003 + 0.000255273787*_Complex_I, -0.005670110185 + 0.008026992933*_Complex_I, 0.007921191245 + -0.004652046754*_Complex_I, -0.019294993452 + -0.027474217637*_Complex_I, 0.025318608692 + -0.002964377998*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_crcf_data_M5h23x50.c000066400000000000000000000113261474751757600251020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_crcf_data_M5h23x50.c: autotest firdecim data // #include float firdecim_crcf_data_M5h23x50_h[] = { 0.002280218687, 0.030259168999, 0.042315352513, 0.023335125905, 0.187877503860, -0.125992843938, 0.011263591538, 0.085275043313, -0.000421564647, -0.061084018425, -0.061455696212, -0.019398732964, 0.054084065833, -0.139019814895, -0.006954271771, 0.066739670458, 0.060380686235, -0.030379569378, 0.062093917175, -0.108597003256, -0.026039280890, -0.061515114912, 0.038253839794}; float complex firdecim_crcf_data_M5h23x50_x[] = { -0.182183709645 + -0.105810548671*_Complex_I, -0.119835664561 + 0.052187599214*_Complex_I, -0.080413311444 + -0.007654126449*_Complex_I, 0.097423911392 + 0.139994199967*_Complex_I, 0.227363312459 + 0.148762801146*_Complex_I, -0.035703226649 + 0.016200983468*_Complex_I, 0.112245547440 + -0.012233367286*_Complex_I, 0.048367738935 + -0.084918284786*_Complex_I, 0.014605478600 + -0.020568647750*_Complex_I, -0.097889245398 + 0.168068267634*_Complex_I, 0.049395920002 + 0.049056756925*_Complex_I, 0.077571659414 + -0.016603490981*_Complex_I, -0.184216448023 + 0.038356590636*_Complex_I, -0.001919304196 + 0.044652884985*_Complex_I, -0.137958101403 + 0.039437297572*_Complex_I, -0.014249713446 + -0.012873748415*_Complex_I, 0.080615138558 + 0.010722054400*_Complex_I, 0.163287071747 + 0.157849778887*_Complex_I, 0.014760203683 + 0.017904920717*_Complex_I, -0.023896962586 + -0.167898683088*_Complex_I, -0.103145190697 + -0.052205104745*_Complex_I, 0.060639622041 + 0.000262344853*_Complex_I, -0.103152379379 + 0.094308639066*_Complex_I, 0.087724817642 + 0.138912843443*_Complex_I, 0.118286611822 + -0.059245080063*_Complex_I, 0.072397607400 + 0.055570352604*_Complex_I, -0.120828136006 + -0.053193491502*_Complex_I, 0.017568748356 + 0.062747031152*_Complex_I, -0.173562312809 + 0.024099395003*_Complex_I, 0.029150371763 + 0.142074561483*_Complex_I, 0.025859464873 + 0.055295550529*_Complex_I, 0.033521057962 + 0.015990392806*_Complex_I, -0.153314777647 + 0.029921210372*_Complex_I, -0.083426782876 + 0.085727794977*_Complex_I, -0.082913880724 + 0.118554053112*_Complex_I, -0.000295266978 + 0.046816730776*_Complex_I, -0.091635622603 + -0.074886539618*_Complex_I, 0.187307078036 + 0.079033670911*_Complex_I, 0.016483267210 + 0.214994027303*_Complex_I, 0.182841584926 + -0.060579741754*_Complex_I, 0.098946994244 + 0.014088074701*_Complex_I, 0.103226498009 + -0.107310190377*_Complex_I, -0.102346312686 + -0.043967864658*_Complex_I, 0.003356469485 + 0.080001448898*_Complex_I, 0.015380876414 + -0.033386312073*_Complex_I, 0.113435756454 + 0.076011600452*_Complex_I, 0.222681717597 + -0.048179807062*_Complex_I, 0.213685265876 + 0.154819154890*_Complex_I, -0.145263809029 + 0.080441672618*_Complex_I, -0.065703128284 + 0.056608305388*_Complex_I}; float complex firdecim_crcf_data_M5h23x50_y[] = { -0.000415418699 + -0.000241271190*_Complex_I, 0.009483904304 + 0.033419922261*_Complex_I, 0.053902979681 + 0.014937609575*_Complex_I, -0.004064163171 + -0.007100167361*_Complex_I, 0.027338357030 + 0.015054094814*_Complex_I, 0.032378938500 + 0.015062971531*_Complex_I, -0.072114751319 + -0.021601257083*_Complex_I, -0.000363929634 + -0.002841410024*_Complex_I, -0.028488318939 + -0.002263371809*_Complex_I, 0.049749343516 + 0.025688357259*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_rrrf_data_M2h4x20.c000066400000000000000000000037201474751757600250500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_rrrf_data_M2h4x20.c: autotest firdecim data // float firdecim_rrrf_data_M2h4x20_h[] = { 0.070782309250, -0.114245586699, 0.008215220382, -0.116718567037}; float firdecim_rrrf_data_M2h4x20_x[] = { 0.098311328839, -0.051405684088, -0.097846553674, 0.070744555579, -0.092569362020, 0.125743342560, -0.015936561579, 0.092440100110, -0.007046555447, -0.011409188742, 0.065796277764, 0.121624056526, 0.001291608019, -0.103251042400, -0.067174551288, -0.069262060525, 0.038107684731, -0.091432498375, 0.094339814736, 0.004969612518}; float firdecim_rrrf_data_M2h4x20_y[] = { 0.006958702881, -0.000245283250, -0.009438359685, -0.024511329437, -0.025867150062, -0.004886703086, -0.011931393613, -0.007143968697, 0.022109694637, 0.025520580844}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_rrrf_data_M3h7x30.c000066400000000000000000000043241474751757600250560ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_rrrf_data_M3h7x30.c: autotest firdecim data // float firdecim_rrrf_data_M3h7x30_h[] = { -0.074705344704, 0.020538592337, -0.020061495576, 0.096703320953, 0.100160540368, 0.097166994081, 0.083888510566}; float firdecim_rrrf_data_M3h7x30_x[] = { -0.077089593357, 0.032375219181, 0.141488397385, 0.034405467968, -0.138389144841, 0.154646756715, 0.086331166522, 0.041332691838, 0.091791117954, -0.065105465675, 0.075745848821, 0.012475523017, -0.107768670583, 0.233864631918, -0.110944430251, -0.060308141718, -0.251948448147, 0.153274083486, -0.114102376762, -0.183548035449, -0.152968693185, 0.049660839590, -0.056844064619, -0.153304122180, 0.018994945270, 0.000201893929, -0.055497296237, 0.101173781919, -0.050453255942, -0.019320758294}; float firdecim_rrrf_data_M3h7x30_y[] = { 0.005759004645, -0.007768614835, 0.013680669269, 0.019197170461, 0.020943849985, -0.009738613503, 0.013465672357, -0.028391740957, -0.041353046024, -0.023577651344}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_rrrf_data_M4h13x40.c000066400000000000000000000050301474751757600251300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_rrrf_data_M4h13x40.c: autotest firdecim data // float firdecim_rrrf_data_M4h13x40_h[] = { -0.050178519704, 0.099634819705, 0.087767256514, 0.031474342328, -0.161835107291, 0.031896126939, -0.240761793751, -0.044460468897, 0.019656280155, 0.150308997913, -0.145260671043, 0.044691633752, -0.228340355042}; float firdecim_rrrf_data_M4h13x40_x[] = { -0.006034368030, -0.171592529075, -0.063780807965, 0.013676314399, 0.116628260211, 0.119863895134, 0.111602959230, 0.130154286756, 0.038035316610, 0.059453633879, -0.109240225614, 0.077742393809, -0.021666946122, 0.067622802572, -0.058137116614, -0.069171140610, 0.067330056503, 0.087258333681, 0.042012179512, -0.025556605587, -0.111286144010, -0.040760608600, 0.127330790275, 0.033399307914, -0.005634951089, 0.043243872564, 0.038979737383, -0.045742865035, -0.193432344744, -0.020574800494, -0.065306698326, -0.101479446471, -0.016230721248, 0.000392179194, -0.065936759641, 0.032965659365, 0.057788436776, -0.268236198963, -0.077821704788, -0.125842807499}; float firdecim_rrrf_data_M4h13x40_y[] = { 0.000302795655, -0.014511652270, 0.029055193091, -0.025764218622, -0.000775391175, 0.028459415706, 0.024044484393, -0.040542156850, 0.012864586577, -0.002482554609}; liquid-dsp-1.7.0/src/filter/tests/data/firdecim_rrrf_data_M5h23x50.c000066400000000000000000000056501474751757600251430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firdecim_rrrf_data_M5h23x50.c: autotest firdecim data // float firdecim_rrrf_data_M5h23x50_h[] = { -0.067636988306, -0.129830871935, -0.096852198413, -0.101084148415, -0.099274002866, 0.068432593779, -0.123467175510, 0.053608743344, 0.062001100783, -0.186969419240, 0.089108369240, -0.007475824870, 0.163590779858, 0.097601917788, 0.092009543577, -0.041838135753, -0.056136168702, 0.003032887982, 0.009882398914, 0.074984250657, -0.019855593061, -0.060394654408, 0.023157699589}; float firdecim_rrrf_data_M5h23x50_x[] = { -0.053013073944, -0.096057779578, 0.089544324704, -0.000543553496, 0.162822533187, -0.074585191755, 0.104404924404, -0.029558379775, -0.007349400311, -0.194774278732, -0.170758029656, 0.045377876421, 0.080652365875, 0.072939196850, -0.089654082233, -0.103982998990, 0.163030711963, -0.024228077817, 0.131281994357, 0.016327074888, -0.055411828614, 0.043034256150, 0.018076404143, 0.097676360852, 0.137184094723, 0.082482387627, 0.056634950389, 0.027836125209, -0.014908882821, 0.162327107907, -0.153015761693, -0.020845168829, -0.001125342955, -0.044310410921, -0.053090705118, -0.024619825348, 0.039550843685, -0.206275854122, 0.034696692856, -0.153816675012, -0.028473257841, 0.054242064784, 0.197473069156, 0.002233912029, 0.021458220407, 0.122982229244, 0.127458372904, -0.040153514587, -0.055390576800, 0.126488480454}; float firdecim_rrrf_data_M5h23x50_y[] = { 0.003585644662, -0.019185323038, 0.023723637517, -0.016266117610, -0.039970055370, -0.037092249176, 0.027140256398, 0.025837751181, 0.028127341349, -0.054916331965}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_cccf_data_h13x32.c000066400000000000000000000121271474751757600245350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_cccf_data_h13x32.c: autotest firfilt data // #include float complex firfilt_cccf_data_h13x32_h[] = { -0.016900612660 + -0.094711890552*_Complex_I, 0.021604417271 + 0.142776429157*_Complex_I, -0.115236149764 + -0.169153952067*_Complex_I, -0.104650665737 + -0.070706448696*_Complex_I, -0.324134992109 + 0.000276600538*_Complex_I, 0.084579923351 + 0.050862911890*_Complex_I, 0.037182962083 + -0.060208798591*_Complex_I, -0.025070759196 + -0.102300651911*_Complex_I, -0.172106098520 + 0.036477087826*_Complex_I, -0.104230620945 + -0.026070285900*_Complex_I, -0.098231380216 + 0.164187739422*_Complex_I, 0.073260028098 + 0.102435049392*_Complex_I, -0.064585416482 + 0.016491998619*_Complex_I}; float complex firfilt_cccf_data_h13x32_x[] = { -0.230394652772 + -0.084902186709*_Complex_I, 0.116521954181 + -0.075921100646*_Complex_I, -0.037505572140 + 0.050295775262*_Complex_I, 0.011196490896 + -0.111587364031*_Complex_I, -0.136496843877 + 0.079379261628*_Complex_I, 0.119267886716 + -0.106802817114*_Complex_I, -0.019101973377 + -0.012951763335*_Complex_I, 0.013025947353 + -0.027697311008*_Complex_I, -0.019147300547 + 0.101327659435*_Complex_I, 0.099708276687 + -0.005787000260*_Complex_I, 0.068401822498 + 0.064073386055*_Complex_I, -0.037396159261 + -0.075336873450*_Complex_I, -0.100404642212 + -0.010670539381*_Complex_I, 0.158140877685 + -0.091346399746*_Complex_I, -0.014860736865 + -0.063687261938*_Complex_I, 0.080260238653 + -0.095670107832*_Complex_I, -0.039374218095 + -0.044034420137*_Complex_I, -0.064080642555 + -0.070686889846*_Complex_I, 0.001854749241 + 0.115365376524*_Complex_I, 0.010746506918 + -0.241675580817*_Complex_I, 0.000549090314 + -0.105646197984*_Complex_I, 0.076651038231 + 0.139227636964*_Complex_I, 0.142025555338 + -0.030479656574*_Complex_I, 0.052085787214 + 0.049670506263*_Complex_I, 0.072171078854 + 0.026786779778*_Complex_I, -0.025753470644 + 0.135280754343*_Complex_I, -0.021573256842 + -0.151434524956*_Complex_I, 0.075816838810 + -0.117216580293*_Complex_I, 0.072760555750 + -0.032730991216*_Complex_I, -0.066907752810 + -0.020500064860*_Complex_I, -0.166213598571 + 0.030726287248*_Complex_I, -0.276903984324 + -0.003789664941*_Complex_I}; float complex firfilt_cccf_data_h13x32_y[] = { -0.004147435830 + 0.023256012109*_Complex_I, -0.002015434559 + -0.044482089545*_Complex_I, 0.030942859967 + 0.066454518780*_Complex_I, -0.026911288885 + 0.010771317579*_Complex_I, 0.095968947613 + 0.038484837745*_Complex_I, -0.092014317271 + -0.013169924277*_Complex_I, 0.049198135608 + 0.035484075721*_Complex_I, -0.025796455461 + 0.044082591823*_Complex_I, 0.078672781715 + -0.025486364457*_Complex_I, -0.072129355236 + 0.058152098733*_Complex_I, 0.060708464475 + -0.020499489129*_Complex_I, -0.012897457718 + 0.010369404477*_Complex_I, 0.040569721031 + -0.076402320248*_Complex_I, -0.061438066081 + 0.022914256728*_Complex_I, 0.010560216826 + 0.008397165450*_Complex_I, -0.007466249710 + 0.045405657448*_Complex_I, 0.045052264644 + -0.014977016558*_Complex_I, -0.103883227654 + 0.025733650083*_Complex_I, -0.020931229354 + 0.011790200727*_Complex_I, -0.082554523156 + 0.082257052415*_Complex_I, 0.062290900829 + 0.006126149167*_Complex_I, -0.001939383449 + 0.054104380393*_Complex_I, -0.080894136635 + -0.026061525625*_Complex_I, -0.014425095108 + 0.144945090491*_Complex_I, 0.027136649299 + 0.013953073572*_Complex_I, -0.004380661218 + -0.036741472069*_Complex_I, -0.088435984052 + -0.001543185349*_Complex_I, 0.051743211037 + -0.012397485596*_Complex_I, -0.019549545189 + 0.010425517862*_Complex_I, -0.009114204900 + 0.008932656001*_Complex_I, -0.003773949758 + 0.033245440352*_Complex_I, -0.062498938791 + 0.037655501652*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_cccf_data_h23x64.c000066400000000000000000000213131474751757600245400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_cccf_data_h23x64.c: autotest firfilt data // #include float complex firfilt_cccf_data_h23x64_h[] = { 0.007386483162 + -0.009424072453*_Complex_I, 0.050423187035 + 0.150124405632*_Complex_I, 0.243542351374 + 0.080326589069*_Complex_I, -0.024338280301 + -0.114090910866*_Complex_I, 0.196460953569 + -0.124970764904*_Complex_I, -0.105561981596 + 0.041404720111*_Complex_I, -0.101639566392 + -0.046297689433*_Complex_I, -0.163657198362 + 0.005526168199*_Complex_I, -0.112922732770 + 0.063835893419*_Complex_I, 0.101174309677 + -0.014946487353*_Complex_I, 0.022730956655 + -0.120281555357*_Complex_I, 0.098219187560 + -0.193182817593*_Complex_I, -0.104212145985 + 0.050487269587*_Complex_I, -0.111765574417 + 0.198335922799*_Complex_I, -0.176342404298 + 0.020342954856*_Complex_I, -0.008161867550 + 0.131912314088*_Complex_I, 0.002095296558 + 0.017356532465*_Complex_I, -0.048192202598 + -0.033184854044*_Complex_I, -0.116973286896 + 0.160940600018*_Complex_I, -0.117776822786 + 0.154916853064*_Complex_I, -0.054689494037 + -0.147596255159*_Complex_I, -0.061473756719 + -0.101802249138*_Complex_I, -0.069996222196 + 0.068670445429*_Complex_I}; float complex firfilt_cccf_data_h23x64_x[] = { -0.078781393877 + 0.110995541416*_Complex_I, -0.047869391092 + -0.021406341819*_Complex_I, 0.037075730398 + 0.142733143372*_Complex_I, 0.030132814646 + -0.067132734894*_Complex_I, 0.061282796666 + 0.010485822100*_Complex_I, 0.102675878253 + -0.033081022766*_Complex_I, 0.033541370777 + 0.079278562425*_Complex_I, -0.054593695346 + -0.027854211664*_Complex_I, 0.145123800751 + -0.056723330167*_Complex_I, 0.011046150157 + 0.040345229995*_Complex_I, -0.035136035623 + 0.087660836105*_Complex_I, 0.016994675402 + 0.012775882535*_Complex_I, 0.044321746934 + -0.049948987747*_Complex_I, -0.028623515736 + 0.009984465451*_Complex_I, -0.047556759717 + 0.018286483908*_Complex_I, -0.006226807241 + 0.024241509652*_Complex_I, 0.064579293390 + -0.055779520425*_Complex_I, 0.006724710050 + -0.045321225291*_Complex_I, -0.014197864403 + -0.074364241862*_Complex_I, -0.189692736681 + 0.036236471869*_Complex_I, -0.043006387932 + 0.015254723104*_Complex_I, 0.183456865086 + -0.046633999430*_Complex_I, -0.096745178650 + -0.157866894203*_Complex_I, 0.049851534577 + -0.011841563370*_Complex_I, -0.128605225270 + -0.121500740667*_Complex_I, 0.208521246393 + 0.074928493344*_Complex_I, 0.015993704716 + -0.142778722944*_Complex_I, 0.099274527811 + 0.252094407113*_Complex_I, 0.095595074594 + -0.110420978049*_Complex_I, -0.160033363989 + 0.021797330986*_Complex_I, -0.033832678704 + 0.074483735094*_Complex_I, 0.063099121768 + 0.029430379768*_Complex_I, 0.073790479995 + 0.116859113625*_Complex_I, 0.029697732194 + -0.064419571602*_Complex_I, -0.121376933005 + -0.068190026772*_Complex_I, 0.157696201880 + 0.013694270490*_Complex_I, 0.192086239328 + 0.177711736014*_Complex_I, 0.050443921971 + 0.194189638728*_Complex_I, 0.104425685379 + 0.145809752108*_Complex_I, 0.052724394018 + -0.077432998652*_Complex_I, -0.138821609433 + 0.064732623753*_Complex_I, -0.091470669189 + 0.063059053083*_Complex_I, 0.126212251998 + 0.047314249385*_Complex_I, -0.096047066646 + 0.177236809567*_Complex_I, 0.052301840404 + -0.008778675600*_Complex_I, -0.121968378742 + -0.054938313986*_Complex_I, -0.052829966951 + -0.030310428105*_Complex_I, 0.018028043678 + -0.025287719529*_Complex_I, -0.027374857808 + 0.073286356627*_Complex_I, 0.097021248414 + 0.117164045551*_Complex_I, 0.041807049929 + -0.087406811774*_Complex_I, -0.016480216738 + 0.009889058359*_Complex_I, 0.025179492882 + 0.203064743411*_Complex_I, 0.157077633956 + -0.037868143998*_Complex_I, 0.186492422521 + 0.007792322512*_Complex_I, -0.058684153831 + 0.005148456049*_Complex_I, 0.043091823396 + 0.043031309641*_Complex_I, 0.070177096613 + -0.053637529243*_Complex_I, -0.026547396369 + -0.080476576072*_Complex_I, -0.001571308583 + -0.035758437403*_Complex_I, -0.015191595806 + -0.121248560074*_Complex_I, -0.150343511708 + -0.218457418741*_Complex_I, 0.214202412315 + -0.062090364159*_Complex_I, 0.051648310107 + 0.008540965007*_Complex_I}; float complex firfilt_cccf_data_h23x64_y[] = { 0.000464112585 + 0.001562308262*_Complex_I, -0.021190870009 + -0.005937253959*_Complex_I, -0.025683625328 + 0.013143026224*_Complex_I, -0.015326079628 + 0.009211447989*_Complex_I, 0.006829901541 + 0.076012393531*_Complex_I, 0.021716854352 + -0.026318353103*_Complex_I, 0.061035502538 + 0.035739634892*_Complex_I, 0.020352690891 + -0.042409807844*_Complex_I, 0.023045428223 + -0.028106571621*_Complex_I, 0.010032616072 + -0.021662309111*_Complex_I, 0.022940764323 + 0.032595296512*_Complex_I, -0.051515604616 + 0.041000933031*_Complex_I, 0.005746042283 + -0.027665280631*_Complex_I, 0.029717785937 + 0.005867034288*_Complex_I, 0.009507729239 + -0.065470886864*_Complex_I, -0.055592736641 + -0.039847345306*_Complex_I, -0.019477634830 + -0.054757658494*_Complex_I, -0.001079490064 + 0.040551530555*_Complex_I, -0.023105026049 + -0.021489136993*_Complex_I, -0.013772576463 + -0.059289523063*_Complex_I, 0.010368064793 + -0.051492201632*_Complex_I, -0.052573934313 + 0.036913855369*_Complex_I, -0.029463371581 + 0.017335195435*_Complex_I, -0.002016229441 + 0.029445890489*_Complex_I, -0.064174313079 + -0.021020171587*_Complex_I, 0.046007178326 + -0.038216963612*_Complex_I, -0.047237084003 + -0.018439493080*_Complex_I, 0.077901945535 + 0.026803231226*_Complex_I, -0.160590610173 + -0.048895121067*_Complex_I, 0.033009384953 + 0.122366292068*_Complex_I, 0.047500812021 + 0.030446168988*_Complex_I, 0.027755264333 + 0.023740335853*_Complex_I, -0.029958186540 + -0.099197879754*_Complex_I, -0.093565182221 + 0.037118606810*_Complex_I, 0.037892348897 + 0.081665210582*_Complex_I, 0.017203419707 + -0.049660120581*_Complex_I, 0.123469958964 + 0.075552201157*_Complex_I, 0.075598725500 + -0.068066054148*_Complex_I, -0.019888756884 + 0.076027214270*_Complex_I, -0.016956893179 + 0.064628354823*_Complex_I, 0.054092135963 + 0.231143717249*_Complex_I, 0.107916203047 + -0.024623113347*_Complex_I, -0.067826976867 + -0.080607084998*_Complex_I, -0.084406829425 + 0.006461650420*_Complex_I, -0.097403134020 + 0.026083051061*_Complex_I, -0.174546809897 + 0.011876261770*_Complex_I, 0.073748943090 + -0.055147402729*_Complex_I, 0.097549181238 + -0.004423842043*_Complex_I, 0.077466051940 + -0.102440912522*_Complex_I, -0.159166842272 + -0.050231066222*_Complex_I, -0.169079556837 + 0.020999784115*_Complex_I, -0.011606027825 + 0.070186046595*_Complex_I, 0.059157126631 + -0.011799023310*_Complex_I, 0.026862671786 + -0.020855448914*_Complex_I, -0.068295073554 + 0.079282428595*_Complex_I, -0.048389220558 + -0.036671891516*_Complex_I, -0.104950395650 + -0.102233724778*_Complex_I, -0.028973062537 + -0.073361406548*_Complex_I, 0.093580906591 + -0.063967765018*_Complex_I, 0.024718362523 + -0.132740996962*_Complex_I, -0.024359580020 + -0.079781595584*_Complex_I, -0.073363097948 + -0.031874352056*_Complex_I, 0.007512286472 + -0.110602957303*_Complex_I, 0.074317818667 + -0.076288705193*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_cccf_data_h4x8.c000066400000000000000000000044551474751757600244050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_cccf_data_h4x8.c: autotest firfilt data // #include float complex firfilt_cccf_data_h4x8_h[] = { -0.031084031859 + -0.013523088141*_Complex_I, -0.129175459526 + 0.067705781544*_Complex_I, 0.221460930668 + -0.057515301525*_Complex_I, -0.023734659272 + 0.094741117144*_Complex_I}; float complex firfilt_cccf_data_h4x8_x[] = { 0.035529355081 + -0.025645176804*_Complex_I, 0.010053327033 + 0.058182925297*_Complex_I, -0.051911580279 + -0.038455783791*_Complex_I, 0.087876912441 + -0.008273223193*_Complex_I, -0.195891631367 + 0.043381908184*_Complex_I, -0.018068686759 + 0.096890714727*_Complex_I, 0.072440149482 + 0.119581756000*_Complex_I, -0.070807340362 + 0.027693599784*_Complex_I}; float complex firfilt_cccf_data_h4x8_y[] = { -0.001451197592 + 0.000316688892*_Complex_I, -0.002378879142 + 0.003773758321*_Complex_I, 0.002248990658 + -0.012660658356*_Complex_I, 0.013625136077 + 0.016803422304*_Complex_I, -0.023574746940 + 0.002359815677*_Complex_I, 0.048100008285 + -0.032526172551*_Complex_I, -0.047049781567 + 0.010960128197*_Complex_I, -0.012767824065 + -0.007537619160*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_cccf_data_h7x16.c000066400000000000000000000063471474751757600244710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_cccf_data_h7x16.c: autotest firfilt data // #include float complex firfilt_cccf_data_h7x16_h[] = { 0.059672454354 + -0.020066091352*_Complex_I, -0.074492656514 + -0.047414131969*_Complex_I, 0.035667494507 + -0.071294810193*_Complex_I, 0.039143057258 + 0.079656472813*_Complex_I, -0.014290705994 + -0.119186857470*_Complex_I, 0.072724115403 + 0.012655052298*_Complex_I, -0.195972668164 + -0.009791166658*_Complex_I}; float complex firfilt_cccf_data_h7x16_x[] = { -0.078420841238 + 0.087748743839*_Complex_I, -0.108100101013 + 0.135812982907*_Complex_I, -0.084609799993 + -0.122999836505*_Complex_I, 0.004784051237 + -0.110951409765*_Complex_I, -0.051782714777 + -0.055641082544*_Complex_I, -0.152740278646 + 0.078038723137*_Complex_I, -0.069927868237 + -0.029365176615*_Complex_I, -0.014589069109 + -0.028292391657*_Complex_I, -0.001773824861 + 0.092262042610*_Complex_I, 0.013547386638 + 0.007206123368*_Complex_I, 0.024099272780 + -0.029680768546*_Complex_I, -0.084253318229 + -0.003754881467*_Complex_I, -0.074747526125 + 0.016818234473*_Complex_I, -0.018741410126 + 0.035601500906*_Complex_I, -0.022799538279 + 0.052284827296*_Complex_I, -0.019334058586 + 0.032106298627*_Complex_I}; float complex firfilt_cccf_data_h7x16_y[] = { -0.002918789759 + 0.006809782675*_Complex_I, 0.006276944689 + 0.007455059607*_Complex_I, 0.010434073117 + -0.001912734754*_Complex_I, -0.005702292584 + 0.016196656152*_Complex_I, -0.025081177186 + 0.012200218722*_Complex_I, 0.003335423652 + 0.014801280201*_Complex_I, 0.006724005065 + 0.002747460191*_Complex_I, 0.009525148495 + -0.023079851588*_Complex_I, -0.004054704111 + 0.027058137376*_Complex_I, 0.008922503980 + 0.020765026017*_Complex_I, 0.003379220673 + 0.021621450005*_Complex_I, 0.008092396331 + -0.009379092265*_Complex_I, 0.024410342880 + 0.008452609790*_Complex_I, 0.007947112966 + 0.022079470097*_Complex_I, -0.003430027671 + -0.018931432282*_Complex_I, 0.001572545942 + 0.003497349824*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_crcf_data_h13x32.c000066400000000000000000000113111474751757600245460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_crcf_data_h13x32.c: autotest firfilt data // #include float firfilt_crcf_data_h13x32_h[] = { 0.005113901796, 0.005286268339, -0.119811540901, -0.004501609093, -0.065007372397, 0.048866593324, 0.013172470077, -0.002661385800, 0.103490232103, -0.080549511664, 0.044381828692, 0.059428974785, 0.036011050317}; float complex firfilt_crcf_data_h13x32_x[] = { -0.150478051517 + 0.011369787230*_Complex_I, -0.011682362019 + -0.131898855698*_Complex_I, 0.002241423344 + 0.056583759593*_Complex_I, -0.059449335305 + 0.187622651747*_Complex_I, -0.180436000741 + 0.005303426369*_Complex_I, 0.011260126047 + 0.058406411239*_Complex_I, 0.104607282644 + 0.079267822272*_Complex_I, 0.085374933204 + 0.051946754389*_Complex_I, -0.022910313299 + 0.030414137098*_Complex_I, 0.088237668857 + -0.149226301695*_Complex_I, -0.077336181799 + 0.011213633150*_Complex_I, -0.041671694767 + -0.010591371244*_Complex_I, -0.072827057153 + 0.029626684791*_Complex_I, -0.031258311706 + -0.032641520688*_Complex_I, -0.008154356734 + 0.089595819254*_Complex_I, 0.008874945980 + 0.055052307581*_Complex_I, 0.021540988384 + 0.002343360972*_Complex_I, 0.031406241630 + -0.041565525378*_Complex_I, -0.186621079183 + -0.055706611874*_Complex_I, -0.204887932486 + 0.107546397697*_Complex_I, -0.001299342939 + -0.091725815207*_Complex_I, 0.098883395599 + -0.042781095000*_Complex_I, -0.148848628287 + 0.075959712533*_Complex_I, 0.168232372928 + 0.044377154144*_Complex_I, 0.162761143249 + -0.111406681457*_Complex_I, -0.069728838323 + 0.030195226651*_Complex_I, -0.015037533839 + 0.032270195219*_Complex_I, 0.047319395233 + -0.049920188058*_Complex_I, -0.275633692987 + -0.077201329969*_Complex_I, 0.260550021883 + -0.026872750426*_Complex_I, 0.154250187563 + -0.051859524539*_Complex_I, 0.085702710731 + -0.034956856551*_Complex_I}; float complex firfilt_crcf_data_h13x32_y[] = { -0.000769529978 + 0.000058143975*_Complex_I, -0.000855209812 + -0.000614414049*_Complex_I, 0.017978713542 + -0.001770120683*_Complex_I, 0.001784905863 + 0.017010423559*_Complex_I, 0.008329226648 + -0.005905805446*_Complex_I, -0.000377533572 + -0.013277356194*_Complex_I, 0.019781654463 + -0.010739936790*_Complex_I, 0.004673510867 + -0.017536447645*_Complex_I, -0.018937503016 + 0.001766778181*_Complex_I, -0.009796095237 + -0.022965903194*_Complex_I, -0.011542534189 + 0.009647205778*_Complex_I, -0.026694559597 + 0.028680204257*_Complex_I, -0.004613286077 + -0.018608161470*_Complex_I, 0.011559988327 + 0.025425767569*_Complex_I, 0.015974924004 + 0.005946996608*_Complex_I, -0.007726490650 + 0.012377335870*_Complex_I, -0.007714581040 + -0.006039979551*_Complex_I, 0.018766419009 + -0.012572800123*_Complex_I, -0.012542031545 + 0.012437887461*_Complex_I, 0.000458385988 + 0.000571447349*_Complex_I, 0.016943660061 + 0.007409564688*_Complex_I, 0.024399758745 + -0.020976831445*_Complex_I, 0.007946403220 + 0.025133322345*_Complex_I, -0.012852674380 + -0.005689128468*_Complex_I, 0.003313037804 + 0.000263249514*_Complex_I, -0.027377402722 + -0.004127607511*_Complex_I, -0.026320368186 + 0.009134835527*_Complex_I, -0.012297987932 + 0.013200852928*_Complex_I, 0.007101262388 + -0.017149417134*_Complex_I, 0.000657385901 + 0.001192381502*_Complex_I, -0.008080139857 + 0.018480645475*_Complex_I, -0.007551765865 + 0.003627711775*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_crcf_data_h23x64.c000066400000000000000000000200211474751757600245520ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_crcf_data_h23x64.c: autotest firfilt data // #include float firfilt_crcf_data_h23x64_h[] = { 0.158654410967, -0.020397216842, -0.054283334982, 0.077922310650, -0.072938526203, -0.018649195029, 0.037699516688, 0.039617662775, -0.201106990060, -0.045133363773, -0.083275831491, -0.080588772189, -0.009860694810, 0.086105167459, 0.145475786114, -0.015729607185, -0.064199255334, -0.041339777246, 0.031333251672, -0.178929283974, -0.144469434532, -0.088642880661, 0.061210119166}; float complex firfilt_crcf_data_h23x64_x[] = { -0.061754655621 + 0.035123551291*_Complex_I, -0.042987945529 + 0.204710494551*_Complex_I, -0.115448103025 + -0.048546960311*_Complex_I, -0.107929842580 + -0.067280385493*_Complex_I, -0.138103588190 + 0.010448310166*_Complex_I, -0.001556297552 + 0.087792883061*_Complex_I, 0.046355639811 + 0.064514990229*_Complex_I, -0.073718979418 + 0.103212389197*_Complex_I, -0.167000830993 + -0.051389222147*_Complex_I, -0.014426416714 + 0.176317900074*_Complex_I, -0.107373342455 + -0.005804161965*_Complex_I, 0.080493073150 + -0.061646586042*_Complex_I, 0.027796421084 + -0.154117176222*_Complex_I, 0.146227243025 + -0.085442723323*_Complex_I, -0.069720789489 + 0.186876621048*_Complex_I, 0.062823376713 + 0.065977046975*_Complex_I, 0.090031816754 + 0.114581114467*_Complex_I, 0.086442323768 + 0.125045380084*_Complex_I, 0.019615700330 + -0.022164049481*_Complex_I, 0.002010913947 + 0.016348332723*_Complex_I, 0.115492888651 + -0.140112679132*_Complex_I, -0.000370552599 + 0.115418598778*_Complex_I, 0.171462023973 + 0.045787506437*_Complex_I, -0.044111687463 + -0.011704116119*_Complex_I, -0.267816339997 + 0.084734013406*_Complex_I, 0.013814245144 + 0.002740227971*_Complex_I, 0.090220778414 + 0.134830380675*_Complex_I, -0.106145737111 + -0.024658098491*_Complex_I, -0.112807070004 + 0.044997920710*_Complex_I, -0.192053613103 + -0.062114377970*_Complex_I, -0.079637314543 + 0.045259089396*_Complex_I, 0.012470128523 + -0.117498759881*_Complex_I, -0.029098880159 + 0.100511335166*_Complex_I, 0.076820185739 + -0.000579442122*_Complex_I, -0.146557365265 + 0.068919305920*_Complex_I, 0.046650052137 + 0.086754950098*_Complex_I, 0.049312254431 + 0.100155311839*_Complex_I, -0.018181427657 + -0.155695073922*_Complex_I, -0.020818721382 + 0.050839229113*_Complex_I, 0.075624933038 + -0.140809485613*_Complex_I, 0.024131064286 + -0.061085135867*_Complex_I, -0.031646019927 + -0.020171616314*_Complex_I, 0.029466323016 + -0.143095954720*_Complex_I, -0.000140873686 + 0.104732973661*_Complex_I, 0.124462359562 + -0.105079943629*_Complex_I, -0.058374142846 + 0.033466529094*_Complex_I, 0.026595988216 + 0.220281782376*_Complex_I, -0.007221829817 + 0.141135026450*_Complex_I, -0.021218003577 + -0.050066565886*_Complex_I, 0.035694484054 + 0.231602026762*_Complex_I, 0.102466686268 + -0.099286054817*_Complex_I, -0.054792214672 + 0.060392934122*_Complex_I, -0.001852582407 + 0.025794064903*_Complex_I, 0.071274514129 + 0.142237231718*_Complex_I, 0.029476880291 + 0.023165981190*_Complex_I, -0.027797892310 + -0.051616914281*_Complex_I, 0.061786844168 + 0.001190554171*_Complex_I, 0.041304624689 + -0.028506531399*_Complex_I, -0.075701492591 + -0.019189579127*_Complex_I, -0.043195431393 + -0.100084431779*_Complex_I, 0.039964361882 + 0.004559897250*_Complex_I, -0.252729884604 + -0.091698894534*_Complex_I, -0.056671384848 + 0.100393269844*_Complex_I, 0.047875493425 + -0.053453060952*_Complex_I}; float complex firfilt_crcf_data_h23x64_y[] = { -0.009797648512 + 0.005572506341*_Complex_I, -0.005560604075 + 0.031761800240*_Complex_I, -0.014087267678 + -0.013784337240*_Complex_I, -0.017247262021 + -0.018059567129*_Complex_I, -0.012287793463 + 0.019054948700*_Complex_I, 0.003719976223 + -0.002001383647*_Complex_I, 0.013367035883 + 0.003682443788*_Complex_I, -0.017360179024 + 0.026029334165*_Complex_I, -0.009179615321 + -0.007210433367*_Complex_I, 0.014210107693 + -0.025365792504*_Complex_I, 0.004045839585 + -0.004700697501*_Complex_I, 0.037185762921 + -0.032401586998*_Complex_I, 0.069046316115 + -0.013271584282*_Complex_I, 0.033064747039 + -0.020579633062*_Complex_I, -0.010997016057 + 0.045070901497*_Complex_I, 0.004422576554 + 0.002390243257*_Complex_I, 0.033125238067 + -0.006016697456*_Complex_I, -0.016975087630 + -0.035483520861*_Complex_I, 0.038314599881 + -0.033008052971*_Complex_I, 0.036960796853 + 0.013280585218*_Complex_I, 0.048652304550 + -0.021208466846*_Complex_I, -0.029006820125 + 0.022587827802*_Complex_I, 0.028022156827 + 0.005836099363*_Complex_I, 0.022094506847 + 0.031041275846*_Complex_I, -0.052928165220 + -0.021052052066*_Complex_I, 0.018511503181 + -0.110568047514*_Complex_I, 0.013151749885 + -0.084455750067*_Complex_I, -0.002103151576 + -0.014246866235*_Complex_I, -0.004981810769 + 0.036099080474*_Complex_I, 0.027562144328 + -0.004142628424*_Complex_I, -0.062965485082 + -0.000721660223*_Complex_I, 0.001355528130 + 0.039494603193*_Complex_I, -0.013676340973 + 0.019821560124*_Complex_I, 0.017190322837 + -0.023603201848*_Complex_I, -0.013639010839 + -0.090413596530*_Complex_I, 0.035568646535 + -0.005785803158*_Complex_I, 0.009541669638 + -0.037656127703*_Complex_I, -0.037436737172 + -0.045380997215*_Complex_I, -0.001373976193 + -0.005853270514*_Complex_I, 0.037863401295 + 0.058080181959*_Complex_I, 0.036122757372 + -0.031465040781*_Complex_I, -0.080256218002 + 0.010144726857*_Complex_I, -0.012130289685 + -0.064577476905*_Complex_I, 0.001740193468 + -0.024376309816*_Complex_I, 0.062877940058 + -0.049615721082*_Complex_I, 0.020116976889 + -0.036592663265*_Complex_I, -0.000380054511 + 0.039223753313*_Complex_I, 0.017068821785 + 0.021526831643*_Complex_I, 0.021954695055 + 0.037691348334*_Complex_I, 0.067990755649 + 0.068783656132*_Complex_I, 0.037145711035 + 0.043650952232*_Complex_I, -0.014003385917 + -0.065891325372*_Complex_I, -0.048189055475 + 0.056129109261*_Complex_I, 0.057414520047 + -0.036184434048*_Complex_I, -0.016064913162 + -0.054756587631*_Complex_I, -0.016229690128 + -0.092689300019*_Complex_I, 0.009080345865 + 0.006957646952*_Complex_I, 0.017213929524 + -0.068928651567*_Complex_I, -0.036862824002 + 0.024446597685*_Complex_I, -0.018313177259 + 0.012846228600*_Complex_I, -0.002556177228 + 0.060786016298*_Complex_I, -0.069716561264 + 0.004791194532*_Complex_I, -0.004221111697 + -0.015828369005*_Complex_I, 0.018252044788 + 0.020184229477*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_crcf_data_h4x8.c000066400000000000000000000042551474751757600244220ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_crcf_data_h4x8.c: autotest firfilt data // #include float firfilt_crcf_data_h4x8_h[] = { 0.081125556518, -0.048097526791, 0.083945750272, 0.016820374297}; float complex firfilt_crcf_data_h4x8_x[] = { 0.212556497097 + -0.062593316778*_Complex_I, 0.074632428892 + -0.155168218555*_Complex_I, -0.139928836211 + -0.151937330426*_Complex_I, 0.057785165005 + 0.027214057011*_Complex_I, 0.047104310251 + -0.016114794312*_Complex_I, 0.140236563713 + 0.296500956218*_Complex_I, -0.134588116658 + -0.011633439603*_Complex_I, 0.035369414992 + -0.047878728319*_Complex_I}; float complex firfilt_crcf_data_h4x8_y[] = { 0.017243764119 + -0.005077917658*_Complex_I, -0.004168844485 + -0.009577524353*_Complex_I, 0.002901774665 + -0.010117235877*_Complex_I, 0.021258439696 + -0.004562990201*_Complex_I, -0.009449045890 + -0.017980731205*_Complex_I, 0.011608332082 + 0.024557748499*_Complex_I, -0.012737392976 + -0.016099749821*_Complex_I, 0.021907294708 + 0.021294289547*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_crcf_data_h7x16.c000066400000000000000000000060151474751757600245000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_crcf_data_h7x16.c: autotest firfilt data // #include float firfilt_crcf_data_h7x16_h[] = { 0.027835212534, -0.040645664069, -0.095885554580, 0.200974194416, 0.142773900141, -0.084839081860, 0.026675441534}; float complex firfilt_crcf_data_h7x16_x[] = { -0.050554619430 + -0.051932459243*_Complex_I, 0.033654160787 + 0.041969310283*_Complex_I, 0.083110727700 + 0.078162488859*_Complex_I, -0.077891200631 + -0.098321707426*_Complex_I, -0.187861386260 + -0.107086777579*_Complex_I, -0.151977015997 + 0.027468572824*_Complex_I, 0.081513596724 + 0.062785557274*_Complex_I, 0.031782625481 + -0.013462505188*_Complex_I, -0.007610286404 + 0.087544934055*_Complex_I, 0.155881117469 + 0.110195135092*_Complex_I, -0.104429397916 + 0.137400420010*_Complex_I, -0.116176549274 + 0.071085593565*_Complex_I, -0.164136953851 + 0.202903767828*_Complex_I, 0.084667802512 + 0.059492856539*_Complex_I, 0.026416620904 + 0.138990393077*_Complex_I, -0.116423582608 + -0.028759261678*_Complex_I}; float complex firfilt_crcf_data_h7x16_y[] = { -0.001407198576 + -0.001445551040*_Complex_I, 0.002991596797 + 0.003279053964*_Complex_I, 0.005792966776 + 0.005449371658*_Complex_I, -0.018933330628 + -0.020375106640*_Complex_I, -0.010486602589 + -0.005458937140*_Complex_I, 0.036671134061 + 0.040651505702*_Complex_I, 0.018467514775 + -0.002647275592*_Complex_I, -0.042885517171 + -0.046631668104*_Complex_I, -0.057859564144 + -0.002378383977*_Complex_I, 0.010144797998 + 0.023802283800*_Complex_I, 0.017394817258 + -0.007977151925*_Complex_I, -0.021897278604 + -0.003093924849*_Complex_I, 0.039886090889 + 0.027046322091*_Complex_I, 0.022929460881 + 0.022153334200*_Complex_I, -0.038653803420 + 0.008885169596*_Complex_I, -0.048989194709 + 0.030055784593*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_rrrf_data_h13x32.c000066400000000000000000000054431474751757600246150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_rrrf_data_h13x32.c: autotest firfilt data // float firfilt_rrrf_data_h13x32_h[] = { 0.061701400663, -0.003256845257, 0.085737504490, -0.119088464421, -0.094195167190, -0.035614627393, -0.075640421976, -0.178180567927, 0.062656377018, 0.024575001277, 0.158593583928, 0.002228379520, 0.112351904789}; float firfilt_rrrf_data_h13x32_x[] = { -0.020470493148, 0.102018118476, -0.054985718021, 0.006308577753, -0.136776277914, -0.097553343057, 0.015106021667, -0.115276028482, -0.139555063727, -0.008140535272, 0.149942052537, -0.011892278070, 0.065230575705, 0.142075094351, -0.164907789585, -0.032484693281, -0.096276951150, 0.147981941286, -0.058167278365, 0.122586631059, -0.085249376452, -0.044902927900, 0.078432553797, 0.057861317911, -0.063852807160, -0.049949958624, -0.041909155283, -0.022591033341, 0.048035976026, 0.022495836486, -0.073843897589, 0.112675367305}; float firfilt_rrrf_data_h13x32_y[] = { -0.001263058100, 0.006361330031, -0.005480042042, 0.011752906544, -0.023395131780, -0.007365237036, -0.008133908376, -0.001942584790, 0.002035200118, 0.017539310799, 0.018129651215, 0.071947442682, 0.032171241395, 0.004309016586, -0.015673178031, 0.002288611018, -0.077270639492, -0.048373764758, -0.012295934305, 0.006856074159, -0.019007594657, 0.044313034038, 0.016681139459, 0.021356291565, -0.035698344648, 0.018453059195, -0.069848287101, 0.038262898124, -0.010626132241, 0.023942333214, -0.013545270316, 0.034191460826}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_rrrf_data_h23x64.c000066400000000000000000000103531474751757600246170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_rrrf_data_h23x64.c: autotest firfilt data // float firfilt_rrrf_data_h23x64_h[] = { 0.023507854506, 0.027103933172, 0.106752895472, 0.074063587060, 0.012575431714, -0.014208904360, -0.189995720602, 0.034113160679, 0.175609922460, 0.105200934542, -0.005136522642, -0.005531746670, 0.139731146359, -0.079842377920, -0.233214917226, 0.035638281722, -0.163205439104, -0.032478500610, 0.199430113992, 0.220129425730, -0.036005167889, 0.056409106456, -0.004421322176}; float firfilt_rrrf_data_h23x64_x[] = { -0.013049061997, 0.119281727724, -0.119365267096, 0.039835879910, -0.009513587246, 0.082243762515, 0.027956820983, -0.069085027701, 0.052848019057, 0.146020985374, 0.037417929487, -0.084232021180, -0.009683296201, -0.090624445719, -0.006075254980, 0.165633370941, -0.073874907410, 0.017988275377, 0.070181770610, -0.244164921762, -0.038716233769, 0.076498331411, -0.013031514838, -0.213155932917, -0.027341233086, -0.146873071789, -0.026995500788, -0.072655809839, 0.156894258163, 0.124930378658, 0.056420922814, 0.134062816355, -0.086478418152, 0.065523216564, -0.081200039055, 0.011086704550, 0.085758668011, 0.132499850065, 0.054287271241, 0.057554900510, -0.022403923256, 0.244428874813, 0.084740945011, 0.112048571173, -0.245511705590, 0.030473857673, -0.089496518267, 0.112146468923, -0.038155919073, -0.079948318739, 0.081965047586, 0.060785574587, -0.015596830096, 0.062834032397, -0.138572554778, 0.183714729747, 0.046778584717, -0.046081790098, -0.074463177805, -0.206183023427, 0.125672790474, 0.071969502765, 0.088478692161, -0.118547492713}; float firfilt_rrrf_data_h23x64_y[] = { -0.000306755451, 0.002450376596, -0.000966042507, 0.009468397319, -0.003216187841, -0.001227073462, 0.004104453009, -0.013702311097, 0.032216367463, 0.008663721625, -0.000634352930, -0.004782446546, 0.012088802412, 0.038158275560, -0.033642624259, -0.056941408268, 0.025461989933, 0.042996863950, 0.042722153417, -0.013343258900, -0.002992404220, -0.070410666038, -0.020716833687, -0.012052257283, 0.015366009966, -0.010804920764, -0.018064798938, 0.027733552912, -0.024577324228, 0.020395693321, 0.044679445466, -0.071992656961, -0.028274328337, 0.109882255190, -0.054423216252, -0.062518613459, 0.073109299563, -0.001030697779, 0.000264209985, 0.117080616804, 0.074883914872, 0.008816712343, -0.093804636161, -0.024674797173, -0.069634193023, -0.015132328421, 0.010801011890, -0.019904446976, 0.054767171785, 0.070007069212, 0.098407344602, -0.023208041689, -0.034398540605, -0.056178855164, 0.015638332591, 0.011048505195, -0.032658159097, -0.031311550317, 0.061445928366, 0.033547250971, 0.134751463913, -0.058463369920, 0.012179813382, -0.001597271199}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_rrrf_data_h4x8.c000066400000000000000000000032471474751757600244600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_rrrf_data_h4x8.c: autotest firfilt data // float firfilt_rrrf_data_h4x8_h[] = { -0.121887159208, -0.231303112477, -0.011081038093, 0.002940945390}; float firfilt_rrrf_data_h4x8_x[] = { 0.087523073427, 0.091626543082, 0.069905988906, -0.025530671018, -0.085926435885, 0.016121796124, 0.067241716218, 0.036151454364}; float firfilt_rrrf_data_h4x8_y[] = { -0.010667938785, -0.031412458342, -0.030683993510, -0.013815528486, 0.015873490575, 0.018398508167, -0.011047853592, -0.020390967516}; liquid-dsp-1.7.0/src/filter/tests/data/firfilt_rrrf_data_h7x16.c000066400000000000000000000040471474751757600245410ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firfilt_rrrf_data_h7x16.c: autotest firfilt data // float firfilt_rrrf_data_h7x16_h[] = { 0.167653994833, 0.011522192990, 0.015882599202, -0.093561396312, 0.074301353348, -0.124295601121, 0.032095823166}; float firfilt_rrrf_data_h7x16_x[] = { 0.096678620741, 0.015023630036, 0.051530016668, -0.094237043292, 0.007423744308, 0.024664429619, -0.199548815687, 0.003258035222, 0.082829872734, 0.142277057992, -0.149671886106, -0.058687993370, 0.018936199920, -0.026660942281, 0.016612364911, 0.178689105006}; float firfilt_rrrf_data_h7x16_y[] = { 0.016208556982, 0.003632721318, 0.010347826097, -0.024012250428, 0.006754954149, -0.012997772766, -0.019171751321, -0.014980556455, 0.022366048926, 0.041414757082, -0.040097174540, 0.008782967641, -0.013845574916, 0.009200324306, -0.017877119698, 0.046763669812}; liquid-dsp-1.7.0/src/filter/tests/data/gen_firfilt_data.m000066400000000000000000000120021474751757600234020ustar00rootroot00000000000000% % generate firfilt data for autotests % clear all; close all; % % function to generate data % function gen_firfilt_datafile(type,h_len,x_len); % determine type x_complex = 0; h_complex = 0; y_complex = 0; if strcmp(type,'rrr'), x_complex = 0; h_complex = 0; y_complex = 0; elseif strcmp(type,'crc'), x_complex = 1; h_complex = 0; y_complex = 1; elseif strcmp(type,'ccc'), x_complex = 1; h_complex = 1; y_complex = 1; else, error(['invalid/unsupported type (' type ')']); end; % generate filter coefficients if h_complex, h = 0.1*[randn(1,h_len) + 1i*randn(1,h_len)]; else, h = 0.1*[randn(1,h_len)]; end; % generate input data if x_complex, x = 0.1*[randn(1,x_len) + 1i*randn(1,x_len)]; else, x = 0.1*[randn(1,x_len)]; end; % filter input y = filter(h,1,x); y_len = length(y); % print results % filename example: firfilt_crcf_data_h12x44.c filename = ['firfilt_' type 'f_data_h' num2str(h_len) 'x' num2str(x_len) '.c']; fid = fopen(filename,'w'); fprintf(fid,'/* Copyright (c) 2007 - 2015 Joseph Gaeddert\n'); fprintf(fid,' *\n'); fprintf(fid,' * Permission is hereby granted, free of charge, to any person obtaining a copy\n'); fprintf(fid,' * of this software and associated documentation files (the "Software"), to deal\n'); fprintf(fid,' * in the Software without restriction, including without limitation the rights\n'); fprintf(fid,' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'); fprintf(fid,' * copies of the Software, and to permit persons to whom the Software is\n'); fprintf(fid,' * furnished to do so, subject to the following conditions:\n'); fprintf(fid,' * \n'); fprintf(fid,' * The above copyright notice and this permission notice shall be included in\n'); fprintf(fid,' * all copies or substantial portions of the Software.\n'); fprintf(fid,' *\n'); fprintf(fid,' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n'); fprintf(fid,' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n'); fprintf(fid,' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n'); fprintf(fid,' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n'); fprintf(fid,' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n'); fprintf(fid,' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n'); fprintf(fid,' * THE SOFTWARE.\n'); fprintf(fid,' */\n'); fprintf(fid,'\n'); fprintf(fid,'//\n'); fprintf(fid,'// %s: autotest firfilt data\n', filename); fprintf(fid,'//\n'); fprintf(fid,'\n'); if h_complex || x_complex || y_complex, fprintf(fid,'#include \n\n'); end; % construct base name, e.g. 'firfilt_crcf_test_h12x44' basename = ['firfilt_' type 'f_data_h' num2str(h_len) 'x' num2str(x_len)]; % save coefficients array if h_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_h[] = {\n', basename); for i=1:h_len, if h_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(h(i)), imag(h(i))); else, fprintf(fid,' %16.12f', h(i)); end; if i==h_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; % save input array if x_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_x[] = {\n', basename); for i=1:x_len, if x_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(x(i)), imag(x(i))); else, fprintf(fid,' %16.12f', x(i)); end; if i==x_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; % save output array if y_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_y[] = {\n', basename); for i=1:y_len, if y_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(y(i)), imag(y(i))); else, fprintf(fid,' %16.12f', y(i)); end; if i==y_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; fclose(fid); printf('results written to %s\n', filename); endfunction; % % generate firfilt data for autotests % % rrrf data gen_firfilt_datafile('rrr', 4, 8); gen_firfilt_datafile('rrr', 7, 16); gen_firfilt_datafile('rrr', 13, 32); gen_firfilt_datafile('rrr', 23, 64); % crcf data gen_firfilt_datafile('crc', 4, 8); gen_firfilt_datafile('crc', 7, 16); gen_firfilt_datafile('crc', 13, 32); gen_firfilt_datafile('crc', 23, 64); % cccf data gen_firfilt_datafile('ccc', 4, 8); gen_firfilt_datafile('ccc', 7, 16); gen_firfilt_datafile('ccc', 13, 32); gen_firfilt_datafile('ccc', 23, 64); liquid-dsp-1.7.0/src/filter/tests/data/gen_iirfilt_data.m000066400000000000000000000146461474751757600234250ustar00rootroot00000000000000% % generate iirfilt data for autotests % clear all; close all; % % function to generate data % function gen_iirfilt_datafile(type,h_len,x_len); % determine type x_complex = 0; h_complex = 0; y_complex = 0; if strcmp(type,'rrr'), x_complex = 0; h_complex = 0; y_complex = 0; elseif strcmp(type,'crc'), x_complex = 1; h_complex = 0; y_complex = 1; elseif strcmp(type,'ccc'), x_complex = 1; h_complex = 1; y_complex = 1; else, error(['invalid/unsupported type (' type ')']); end; % % generate low-pass butterworth filter coefficients % % generate complex roots n = h_len - 1; % filter order r = mod(n, 2); % odd/even order L = (n-r)/2; % filter semi-length pa = zeros(1,n); % analog poles (roots of a) for i=0:(L-1), theta = (2*(i+1) + n - 1)*pi / (2*n); pa(2*i+1) = exp( j*theta ); pa(2*i+2) = exp(-j*theta ); end; if r, pa(end) = -1; end; % convert analog poles/zeros/gain to digital fc = 0.1; m = abs(tan(pi*fc)); p = zeros(1,n); z = zeros(1,n); k = 1; for i=1:n, % compute digital zeros... z(i) = -1; % compute digital pols pm = pa(i)*m; p(i) = (1 + pm)/(1 - pm); % compute digital gain k = k*(1 - p(i)) / (1 - z(i)); end; % expand roots b = [1]; a = [1]; k = 1; % gain for i=1:n, b = conv(b, [1, -z(i)]); a = conv(a, [1, -p(i)]); k = k*(1 - p(i))/(1 - z(i)); end; k = real(k); a = real(a); b = real(b) * k; % modulate coefficients for complex type if h_complex, for i=1:h_len, a(i) = a(i) * exp(j*2*pi*0.1*i); b(i) = b(i) * exp(j*2*pi*0.1*i); end; end; % generate input data if x_complex, x = 0.1*[randn(1,x_len) + 1i*randn(1,x_len)]; else, x = 0.1*[randn(1,x_len)]; end; % filter input y = filter(b,a,x); y_len = length(y); % print results % filename example: iirfilt_crcf_data_h12x44.c filename = ['iirfilt_' type 'f_data_h' num2str(h_len) 'x' num2str(x_len) '.c']; fid = fopen(filename,'w'); fprintf(fid,'/* Copyright (c) 2007 - 2015 Joseph Gaeddert\n'); fprintf(fid,' *\n'); fprintf(fid,' * Permission is hereby granted, free of charge, to any person obtaining a copy\n'); fprintf(fid,' * of this software and associated documentation files (the "Software"), to deal\n'); fprintf(fid,' * in the Software without restriction, including without limitation the rights\n'); fprintf(fid,' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'); fprintf(fid,' * copies of the Software, and to permit persons to whom the Software is\n'); fprintf(fid,' * furnished to do so, subject to the following conditions:\n'); fprintf(fid,' * \n'); fprintf(fid,' * The above copyright notice and this permission notice shall be included in\n'); fprintf(fid,' * all copies or substantial portions of the Software.\n'); fprintf(fid,' *\n'); fprintf(fid,' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n'); fprintf(fid,' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n'); fprintf(fid,' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n'); fprintf(fid,' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n'); fprintf(fid,' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n'); fprintf(fid,' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n'); fprintf(fid,' * THE SOFTWARE.\n'); fprintf(fid,' */\n'); fprintf(fid,'\n'); fprintf(fid,'//\n'); fprintf(fid,'// %s: autotest iirfilt data\n', filename); fprintf(fid,'//\n'); fprintf(fid,'\n'); if h_complex || x_complex || y_complex, fprintf(fid,'#include \n\n'); end; % construct base name, e.g. 'iirfilt_crcf_test_h12x44' basename = ['iirfilt_' type 'f_data_h' num2str(h_len) 'x' num2str(x_len)]; % save coefficients arrays if h_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_b[] = {\n', basename); for i=1:h_len, if h_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(b(i)), imag(b(i))); else, fprintf(fid,' %16.12f', b(i)); end; if i==h_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; % save coefficients arrays if h_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_a[] = {\n', basename); for i=1:h_len, if h_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(a(i)), imag(a(i))); else, fprintf(fid,' %16.12f', a(i)); end; if i==h_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; % save input array if x_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_x[] = {\n', basename); for i=1:x_len, if x_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(x(i)), imag(x(i))); else, fprintf(fid,' %16.12f', x(i)); end; if i==x_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; % save output array if y_complex, fprintf(fid,'float complex '); else, fprintf(fid,'float '); end; fprintf(fid,'%s_y[] = {\n', basename); for i=1:y_len, if y_complex, fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(y(i)), imag(y(i))); else, fprintf(fid,' %16.12f', y(i)); end; if i==y_len, fprintf(fid,'};\n\n'); else, fprintf(fid,',\n'); end; end; fclose(fid); printf('results written to %s\n', filename); endfunction; % % generate test data % % rrrf data gen_iirfilt_datafile('rrr', 3, 64); gen_iirfilt_datafile('rrr', 5, 64); gen_iirfilt_datafile('rrr', 7, 64); % crcf data gen_iirfilt_datafile('crc', 3, 64); gen_iirfilt_datafile('crc', 5, 64); gen_iirfilt_datafile('crc', 7, 64); % cccf data gen_iirfilt_datafile('ccc', 3, 64); gen_iirfilt_datafile('ccc', 5, 64); gen_iirfilt_datafile('ccc', 7, 64); liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_cccf_data_h3x64.c000066400000000000000000000176451474751757600244760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_cccf_data_h3x64.c: autotest iirfilt data // #include float complex iirfilt_cccf_data_h3x64_b[] = { 0.054572462936 + 0.039649215181*_Complex_I, 0.041689651984 + 0.128307555581*_Complex_I, -0.020844825992 + 0.064153777791*_Complex_I}; float complex iirfilt_cccf_data_h3x64_a[] = { 0.809016994375 + 0.587785252292*_Complex_I, -0.353200399524 + -1.087039054939*_Complex_I, -0.127562709117 + 0.392597649806*_Complex_I}; float complex iirfilt_cccf_data_h3x64_x[] = { -0.024833213118 + -0.034917156419*_Complex_I, -0.203303753453 + -0.146194321825*_Complex_I, 0.046955837790 + -0.018522626941*_Complex_I, -0.009310945228 + -0.145839543251*_Complex_I, 0.050014713286 + 0.074118954232*_Complex_I, 0.053029015111 + 0.038309174053*_Complex_I, 0.024855918446 + -0.013616668881*_Complex_I, -0.075445314910 + -0.100119258919*_Complex_I, 0.160017817197 + 0.023949186601*_Complex_I, 0.146076212120 + -0.000269193014*_Complex_I, 0.015195370146 + 0.275825448022*_Complex_I, 0.071299735570 + 0.054576601750*_Complex_I, -0.143098150747 + 0.029176300561*_Complex_I, -0.029456081088 + -0.072086611744*_Complex_I, 0.068475191123 + -0.216689722106*_Complex_I, 0.076757256920 + 0.097275143829*_Complex_I, -0.043846185419 + 0.306249972124*_Complex_I, 0.070413973865 + 0.090585247522*_Complex_I, 0.132485779791 + -0.159268673808*_Complex_I, 0.026917161537 + -0.100640356329*_Complex_I, 0.007473659993 + 0.080379816333*_Complex_I, 0.190359743048 + 0.112433411463*_Complex_I, -0.120301668631 + 0.050439886600*_Complex_I, -0.046297800762 + -0.003443247054*_Complex_I, -0.124614723514 + 0.115573697342*_Complex_I, 0.145848137742 + -0.028451577663*_Complex_I, 0.150217608922 + 0.041411226796*_Complex_I, 0.065634804159 + -0.047306957256*_Complex_I, -0.082921695322 + -0.079112928494*_Complex_I, -0.145226550689 + -0.188234399475*_Complex_I, -0.034483517482 + 0.115199412906*_Complex_I, 0.011933371178 + -0.013196555096*_Complex_I, -0.135183164034 + -0.016707765823*_Complex_I, -0.023217606041 + 0.034147466698*_Complex_I, 0.048294051851 + -0.023691893478*_Complex_I, 0.032010168738 + -0.060275616633*_Complex_I, -0.145436488960 + -0.187315942943*_Complex_I, -0.087977813311 + 0.136955551173*_Complex_I, -0.124764798898 + 0.030020090717*_Complex_I, -0.085914119584 + 0.066553144151*_Complex_I, 0.080940796771 + 0.007884486399*_Complex_I, -0.073277212995 + 0.029723354716*_Complex_I, 0.218025609607 + -0.011507652078*_Complex_I, -0.050453154704 + 0.168205457912*_Complex_I, 0.065308138197 + 0.010673521587*_Complex_I, 0.164945191560 + 0.069669644982*_Complex_I, -0.019014062556 + -0.020454796529*_Complex_I, 0.064918556283 + -0.050548033336*_Complex_I, 0.028164657959 + -0.173995204773*_Complex_I, 0.122134013651 + 0.005095487421*_Complex_I, 0.234213744496 + -0.143695630868*_Complex_I, 0.084679105788 + -0.021311700717*_Complex_I, 0.054268742828 + 0.007308179887*_Complex_I, -0.029620954263 + 0.054909993996*_Complex_I, 0.019992503058 + -0.115385511675*_Complex_I, -0.064206101272 + -0.057135496497*_Complex_I, 0.102760385313 + 0.007278409932*_Complex_I, 0.177210934528 + 0.054290451135*_Complex_I, 0.128563865148 + 0.003219961582*_Complex_I, -0.083833350402 + 0.040801324808*_Complex_I, -0.080842077428 + 0.120550027178*_Complex_I, -0.019021541271 + 0.041759686472*_Complex_I, -0.115073955933 + -0.091807014377*_Complex_I, 0.153344859386 + -0.062742865142*_Complex_I}; float complex iirfilt_cccf_data_h3x64_y[] = { -0.001675131192 + -0.002355346350*_Complex_I, -0.013622046565 + -0.018945208542*_Complex_I, -0.006286044544 + -0.061360482408*_Complex_I, 0.040817629094 + -0.077423785655*_Complex_I, 0.082560403156 + -0.042905448043*_Complex_I, 0.081885166095 + 0.020646150389*_Complex_I, 0.035185788192 + 0.059385572466*_Complex_I, -0.012349534229 + 0.041702279147*_Complex_I, -0.008719427172 + -0.005108227398*_Complex_I, 0.043586624569 + -0.002694870087*_Complex_I, 0.060010371171 + 0.071790678150*_Complex_I, -0.011700201664 + 0.134289646346*_Complex_I, -0.104085781588 + 0.103901309521*_Complex_I, -0.133770658357 + 0.006298194510*_Complex_I, -0.071593140378 + -0.089829654416*_Complex_I, 0.047530468946 + -0.094499459711*_Complex_I, 0.094339040540 + 0.021353778886*_Complex_I, 0.000763487486 + 0.119530519765*_Complex_I, -0.094370685059 + 0.079578408854*_Complex_I, -0.069334619720 + -0.012623371571*_Complex_I, 0.012050086613 + -0.029603434811*_Complex_I, 0.049219627613 + 0.026131367418*_Complex_I, 0.013542931769 + 0.089200137012*_Complex_I, -0.066921684818 + 0.079213353516*_Complex_I, -0.100736964307 + 0.008675016473*_Complex_I, -0.073014776026 + -0.045716119068*_Complex_I, -0.002251024625 + -0.047215888024*_Complex_I, 0.043409846071 + 0.011329094890*_Complex_I, 0.020075927067 + 0.051751627220*_Complex_I, -0.025464006128 + 0.018170901171*_Complex_I, -0.017900643236 + -0.046047380472*_Complex_I, 0.021720291461 + -0.051218319397*_Complex_I, 0.023820600962 + -0.021299144521*_Complex_I, -0.000443310781 + -0.015435045664*_Complex_I, -0.005171097244 + -0.029938427283*_Complex_I, 0.015962947694 + -0.032614702790*_Complex_I, 0.026567768778 + -0.027656459980*_Complex_I, 0.025886386590 + -0.031773276552*_Complex_I, 0.011142820861 + -0.022130140814*_Complex_I, -0.023018410554 + -0.024004380806*_Complex_I, -0.028989134806 + -0.045608118967*_Complex_I, -0.005447370179 + -0.044390449128*_Complex_I, 0.016111369022 + -0.025494020513*_Complex_I, 0.033164181168 + 0.018349162452*_Complex_I, -0.002881749460 + 0.064999887863*_Complex_I, -0.037794707920 + 0.054120734400*_Complex_I, -0.033549552744 + 0.041209685622*_Complex_I, -0.029745345484 + 0.028385093658*_Complex_I, -0.012206946909 + 0.000426141907*_Complex_I, 0.033070597342 + -0.013052292197*_Complex_I, 0.081548142195 + 0.013614572710*_Complex_I, 0.101806391304 + 0.065450185198*_Complex_I, 0.073804512902 + 0.112077362053*_Complex_I, 0.012136514124 + 0.118696097982*_Complex_I, -0.039510405075 + 0.074133214086*_Complex_I, -0.038427157781 + 0.006482000625*_Complex_I, 0.006530434509 + -0.025726623154*_Complex_I, 0.055688677705 + 0.002152977720*_Complex_I, 0.064499041530 + 0.067061388496*_Complex_I, 0.016662206642 + 0.109004403882*_Complex_I, -0.055089624558 + 0.092364887087*_Complex_I, -0.096355781376 + 0.032987760948*_Complex_I, -0.090540548264 + -0.030202075604*_Complex_I, -0.036200313340 + -0.078861745571*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_cccf_data_h5x64.c000066400000000000000000000201551474751757600244660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_cccf_data_h5x64.c: autotest iirfilt data // #include float complex iirfilt_cccf_data_h5x64_b[] = { 0.003902975763 + 0.002835677878*_Complex_I, 0.005963216337 + 0.018352892749*_Complex_I, -0.008944824505 + 0.027529339123*_Complex_I, -0.015611903052 + 0.011342711511*_Complex_I, -0.004824343358 + 0.000000000000*_Complex_I}; float complex iirfilt_cccf_data_h5x64_a[] = { 0.809016994375 + 0.587785252292*_Complex_I, -0.732219787612 + -2.253540785927*_Complex_I, -0.715061744841 + 2.200733760162*_Complex_I, 0.853242236735 + -0.619916771678*_Complex_I, -0.187379492368 + 0.000000000000*_Complex_I}; float complex iirfilt_cccf_data_h5x64_x[] = { -0.139691779780 + -0.008483106386*_Complex_I, -0.016364784445 + -0.044182994598*_Complex_I, -0.027693468539 + -0.032794063650*_Complex_I, -0.104737698912 + 0.045751273952*_Complex_I, 0.142328368973 + -0.016207638981*_Complex_I, -0.036733974222 + -0.069688017846*_Complex_I, 0.060203955630 + 0.133175392895*_Complex_I, -0.001765141276 + 0.015191859044*_Complex_I, -0.001821699218 + -0.185914660662*_Complex_I, -0.117231114471 + -0.018976758319*_Complex_I, 0.056506370766 + 0.169868105876*_Complex_I, 0.053136860955 + -0.057576775991*_Complex_I, -0.033555900108 + 0.043991132807*_Complex_I, 0.174322859539 + -0.016411750716*_Complex_I, 0.048756047942 + -0.098065494186*_Complex_I, 0.097489588055 + -0.128464359980*_Complex_I, 0.013198059974 + 0.124985844357*_Complex_I, 0.041433063500 + -0.091281097108*_Complex_I, -0.065717968668 + -0.070462413308*_Complex_I, -0.229581678727 + 0.016392994937*_Complex_I, 0.136389898546 + -0.044643438493*_Complex_I, 0.170063648104 + -0.138204335760*_Complex_I, -0.261885373085 + -0.036055969744*_Complex_I, 0.049405811588 + -0.051424162851*_Complex_I, 0.083569523085 + -0.051487491473*_Complex_I, 0.071788757486 + -0.084369347265*_Complex_I, 0.003003764878 + 0.132223891359*_Complex_I, -0.024192470852 + 0.070159890098*_Complex_I, 0.038349724977 + 0.034974242507*_Complex_I, -0.116330185087 + 0.073501409708*_Complex_I, 0.024045897003 + 0.055819960513*_Complex_I, 0.017889237527 + -0.004469182117*_Complex_I, -0.024106461932 + -0.117012466455*_Complex_I, 0.071738300668 + 0.045036393627*_Complex_I, 0.028843052996 + -0.078769113102*_Complex_I, 0.063621483394 + -0.058568970562*_Complex_I, -0.068750316567 + 0.039728781772*_Complex_I, 0.100842588600 + 0.110482009478*_Complex_I, -0.125927976752 + 0.054480687277*_Complex_I, -0.020084532983 + -0.082864071477*_Complex_I, 0.031724080774 + -0.219039642975*_Complex_I, -0.048991766271 + -0.080798818403*_Complex_I, -0.051508440449 + 0.079624596487*_Complex_I, 0.079700844111 + 0.120292888480*_Complex_I, -0.042922860897 + -0.142995288222*_Complex_I, -0.066949342662 + 0.135970774477*_Complex_I, 0.019060475689 + 0.089390846898*_Complex_I, -0.050687616475 + 0.060447837252*_Complex_I, 0.032012337624 + -0.039188802723*_Complex_I, -0.076316420307 + -0.055316484097*_Complex_I, 0.066550049652 + 0.021107378195*_Complex_I, -0.136321433622 + 0.150816889613*_Complex_I, -0.111846218504 + -0.006277547874*_Complex_I, -0.162278498147 + 0.091756441800*_Complex_I, -0.169150340863 + 0.165920997781*_Complex_I, 0.031684008666 + -0.124705259988*_Complex_I, 0.142337877021 + -0.055397634380*_Complex_I, 0.008471585352 + 0.093647831898*_Complex_I, 0.056572323420 + 0.087500434149*_Complex_I, 0.028450731692 + -0.096199543245*_Complex_I, 0.239170762991 + 0.094782640689*_Complex_I, 0.004312922000 + -0.031035272406*_Complex_I, 0.020341098638 + -0.131272589643*_Complex_I, -0.037882757496 + 0.067034671078*_Complex_I}; float complex iirfilt_cccf_data_h5x64_y[] = { -0.000673921110 + -0.000040925418*_Complex_I, -0.003398473742 + -0.002947141586*_Complex_I, -0.002922206681 + -0.013825603768*_Complex_I, 0.011351930937 + -0.025613672702*_Complex_I, 0.033720704702 + -0.021360914845*_Complex_I, 0.044875076203 + -0.000783873348*_Complex_I, 0.038233094284 + 0.020787564602*_Complex_I, 0.020600577348 + 0.033987306418*_Complex_I, -0.002864320304 + 0.035531578366*_Complex_I, -0.022888054681 + 0.018549029265*_Complex_I, -0.019307396550 + -0.009888096688*_Complex_I, 0.008180046532 + -0.019679894883*_Complex_I, 0.026199927267 + 0.001599932018*_Complex_I, 0.012556168826 + 0.025757319931*_Complex_I, -0.012290310862 + 0.024840701409*_Complex_I, -0.017818483865 + 0.008876391685*_Complex_I, -0.003397754549 + 0.006239299921*_Complex_I, 0.005174089802 + 0.027426334643*_Complex_I, -0.014436018353 + 0.050414195091*_Complex_I, -0.048944405480 + 0.042237569566*_Complex_I, -0.061143399567 + 0.001943733440*_Complex_I, -0.031290087686 + -0.037546290383*_Complex_I, 0.024191792032 + -0.037281132537*_Complex_I, 0.055994057347 + 0.009484372596*_Complex_I, 0.035113320604 + 0.053950125645*_Complex_I, -0.000319184066 + 0.053553543859*_Complex_I, -0.003748044735 + 0.033707721402*_Complex_I, 0.009722926629 + 0.040553199336*_Complex_I, -0.006989849521 + 0.066477615272*_Complex_I, -0.055424307952 + 0.061810233374*_Complex_I, -0.086421338855 + 0.011297407459*_Complex_I, -0.068414816046 + -0.045801400009*_Complex_I, -0.020384923008 + -0.067735377613*_Complex_I, 0.019283433521 + -0.051755804853*_Complex_I, 0.034417002461 + -0.021893955948*_Complex_I, 0.031236415488 + 0.004272156915*_Complex_I, 0.019138535253 + 0.021319083228*_Complex_I, 0.004038232283 + 0.030041100664*_Complex_I, -0.013714706258 + 0.032179049891*_Complex_I, -0.035521139667 + 0.023369946120*_Complex_I, -0.050537187534 + -0.006832451226*_Complex_I, -0.030529075574 + -0.049682114778*_Complex_I, 0.029567916254 + -0.061475046317*_Complex_I, 0.079914850669 + -0.013639694885*_Complex_I, 0.066420597833 + 0.056057061117*_Complex_I, 0.001313278909 + 0.079337579523*_Complex_I, -0.048412140007 + 0.039309365767*_Complex_I, -0.044229246054 + -0.013111052841*_Complex_I, -0.014299116501 + -0.031757251195*_Complex_I, 0.001458230817 + -0.025843774220*_Complex_I, 0.003668689756 + -0.024816091795*_Complex_I, 0.013579943623 + -0.028642603348*_Complex_I, 0.025561989594 + -0.017704337809*_Complex_I, 0.013826559239 + -0.002285027652*_Complex_I, -0.012918803263 + -0.015966285682*_Complex_I, -0.016572881084 + -0.058389357048*_Complex_I, 0.019617042366 + -0.094896571757*_Complex_I, 0.080139425197 + -0.089945804958*_Complex_I, 0.120711490363 + -0.029113736905*_Complex_I, 0.094470811623 + 0.049975768139*_Complex_I, 0.016348380400 + 0.077528800177*_Complex_I, -0.038765003010 + 0.039996085676*_Complex_I, -0.035736567857 + -0.000694897676*_Complex_I, -0.015553151187 + -0.003464831303*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_cccf_data_h7x64.c000066400000000000000000000204651474751757600244740ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_cccf_data_h7x64.c: autotest iirfilt data // #include float complex iirfilt_cccf_data_h7x64_b[] = { 0.000275500748 + 0.000200163010*_Complex_I, 0.000631391531 + 0.001943223322*_Complex_I, -0.001578478829 + 0.004858058305*_Complex_I, -0.005510014966 + 0.004003260202*_Complex_I, -0.005108064791 + 0.000000000000*_Complex_I, -0.001653004490 + -0.001200978061*_Complex_I, -0.000105231922 + -0.000323870554*_Complex_I}; float complex iirfilt_cccf_data_h7x64_a[] = { 0.809016994375 + 0.587785252292*_Complex_I, -1.106106182941 + -3.404244789607*_Complex_I, -1.748624319785 + 5.381712281707*_Complex_I, 4.017105304210 + -2.918597842985*_Complex_I, -2.529494905841 + 0.000000000000*_Complex_I, 0.570578744331 + 0.414549723333*_Complex_I, -0.025882175591 + -0.079657145723*_Complex_I}; float complex iirfilt_cccf_data_h7x64_x[] = { -0.098550426609 + -0.003621212634*_Complex_I, -0.016756220318 + 0.048451159934*_Complex_I, 0.128559901552 + -0.175906398240*_Complex_I, 0.042354962510 + 0.175294582513*_Complex_I, 0.044042909613 + -0.033981151417*_Complex_I, 0.096167707817 + 0.043304738718*_Complex_I, 0.008843481666 + 0.157764101243*_Complex_I, 0.047946611970 + 0.072647112324*_Complex_I, -0.005116789209 + 0.027119998834*_Complex_I, 0.056600964002 + 0.277180066672*_Complex_I, -0.038103339311 + -0.158209538469*_Complex_I, -0.190286655252 + -0.175199843166*_Complex_I, 0.046655418918 + 0.117071622909*_Complex_I, -0.040116383719 + 0.003741131243*_Complex_I, 0.106707347270 + -0.131096478967*_Complex_I, 0.156218986693 + -0.053370165924*_Complex_I, 0.049386533650 + 0.102352649704*_Complex_I, -0.035443738919 + -0.092876336588*_Complex_I, -0.061253027039 + -0.061242620775*_Complex_I, -0.225771811818 + -0.034350311320*_Complex_I, -0.010532720169 + 0.007358131605*_Complex_I, 0.030330062576 + 0.124193458018*_Complex_I, 0.141406666457 + -0.078752149635*_Complex_I, -0.145791273156 + 0.023246728519*_Complex_I, -0.011541061424 + -0.152743782535*_Complex_I, -0.068198003148 + -0.062679366340*_Complex_I, 0.073619746128 + 0.013331230908*_Complex_I, 0.092211502182 + 0.096482943911*_Complex_I, -0.038021973216 + -0.031446557366*_Complex_I, -0.008559170319 + -0.023697838529*_Complex_I, 0.004944119278 + -0.073417141786*_Complex_I, 0.110759757286 + 0.145622092402*_Complex_I, 0.087582530761 + -0.051117071597*_Complex_I, -0.104346081702 + -0.129040232033*_Complex_I, 0.013296100000 + 0.043301334280*_Complex_I, 0.106655262054 + -0.084832308563*_Complex_I, 0.036672357213 + -0.108439057934*_Complex_I, -0.072605878689 + -0.074457714998*_Complex_I, -0.070446103747 + -0.090753818960*_Complex_I, -0.043844178551 + -0.001965788736*_Complex_I, 0.074808520578 + -0.029341850412*_Complex_I, -0.029417618007 + -0.105379562333*_Complex_I, -0.084718140076 + 0.065078236549*_Complex_I, 0.006736811174 + 0.057115610089*_Complex_I, 0.128294037265 + 0.016598548472*_Complex_I, 0.056536504992 + 0.095386541532*_Complex_I, -0.180675222360 + 0.073501707373*_Complex_I, 0.075621856422 + -0.019260447414*_Complex_I, -0.123616785095 + 0.040307567607*_Complex_I, 0.231558123335 + -0.162832384201*_Complex_I, -0.215960867581 + -0.007986024628*_Complex_I, 0.128200674463 + -0.048905384561*_Complex_I, -0.024701418483 + -0.022333678059*_Complex_I, 0.168095436407 + 0.021880796886*_Complex_I, -0.053661700721 + 0.138981768476*_Complex_I, -0.085052752996 + 0.061710282625*_Complex_I, -0.070265421254 + 0.003218384541*_Complex_I, 0.078160292681 + -0.023479825626*_Complex_I, -0.039515617329 + 0.098596493423*_Complex_I, 0.024455660290 + 0.059965817173*_Complex_I, -0.054708570486 + -0.041259730433*_Complex_I, 0.014136360877 + -0.049081577540*_Complex_I, 0.076788203575 + 0.031140443013*_Complex_I, 0.140726220651 + -0.116220629853*_Complex_I}; float complex iirfilt_cccf_data_h7x64_y[] = { -0.000033560131 + -0.000001233159*_Complex_I, -0.000258851151 + -0.000182022816*_Complex_I, -0.000494649917 + -0.001373362038*_Complex_I, 0.001394642558 + -0.004175303248*_Complex_I, 0.008554931816 + -0.004804359573*_Complex_I, 0.016796138686 + 0.005120290566*_Complex_I, 0.010932000560 + 0.024911804007*_Complex_I, -0.017061529751 + 0.034832808964*_Complex_I, -0.049761088897 + 0.015264433783*_Complex_I, -0.059020207327 + -0.027171699378*_Complex_I, -0.036205994556 + -0.064624947209*_Complex_I, 0.000601917126 + -0.076588962383*_Complex_I, 0.028262998034 + -0.068260421645*_Complex_I, 0.044537214577 + -0.058361858676*_Complex_I, 0.064596876978 + -0.048925217761*_Complex_I, 0.088128996753 + -0.021843906515*_Complex_I, 0.089856452956 + 0.026332726109*_Complex_I, 0.054471127041 + 0.068223976540*_Complex_I, -0.000290875094 + 0.076123105710*_Complex_I, -0.044282578145 + 0.048889124487*_Complex_I, -0.059353580762 + 0.004067442508*_Complex_I, -0.041761212642 + -0.036859569919*_Complex_I, -0.000561785939 + -0.053116743086*_Complex_I, 0.040104448371 + -0.032897900323*_Complex_I, 0.050619601896 + 0.011940322017*_Complex_I, 0.021768243925 + 0.046287205351*_Complex_I, -0.019213577363 + 0.040918226497*_Complex_I, -0.030599821708 + 0.006207948813*_Complex_I, -0.002845413304 + -0.013157003063*_Complex_I, 0.024556915659 + 0.011232088898*_Complex_I, 0.007350619475 + 0.051864253016*_Complex_I, -0.044765635147 + 0.053713175283*_Complex_I, -0.073600260113 + 0.004656138635*_Complex_I, -0.044922245023 + -0.043553047795*_Complex_I, 0.005045527096 + -0.039432366427*_Complex_I, 0.016567161506 + 0.001409186000*_Complex_I, -0.014892968732 + 0.020249556494*_Complex_I, -0.038020558990 + -0.003690764330*_Complex_I, -0.020379281032 + -0.029896511388*_Complex_I, 0.009911763020 + -0.018485013558*_Complex_I, 0.009213285286 + 0.015408996809*_Complex_I, -0.020607967078 + 0.028064347058*_Complex_I, -0.040072285887 + 0.009103845685*_Complex_I, -0.029633824328 + -0.009491108934*_Complex_I, -0.012674711398 + -0.002412590925*_Complex_I, -0.017757155057 + 0.015724298695*_Complex_I, -0.039259428540 + 0.015648709858*_Complex_I, -0.050519151856 + -0.005459876230*_Complex_I, -0.042568847598 + -0.027243436178*_Complex_I, -0.027047977959 + -0.039658949321*_Complex_I, -0.008598155325 + -0.047768931278*_Complex_I, 0.018620409918 + -0.047826408941*_Complex_I, 0.046696907915 + -0.025513963561*_Complex_I, 0.051035872527 + 0.016271017736*_Complex_I, 0.021627412575 + 0.048969234788*_Complex_I, -0.020027138727 + 0.049506949727*_Complex_I, -0.046847717023 + 0.024846966173*_Complex_I, -0.053679844164 + -0.005914224145*_Complex_I, -0.045675563357 + -0.036479785730*_Complex_I, -0.018483743745 + -0.062516165506*_Complex_I, 0.025991231714 + -0.064521736503*_Complex_I, 0.058934016585 + -0.030613923443*_Complex_I, 0.051235943856 + 0.012914473925*_Complex_I, 0.016853513686 + 0.024980258409*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_crcf_data_h3x64.c000066400000000000000000000173411474751757600245060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_crcf_data_h3x64.c: autotest iirfilt data // #include float iirfilt_crcf_data_h3x64_b[] = { 0.067455273889, 0.134910547778, 0.067455273889}; float iirfilt_crcf_data_h3x64_a[] = { 1.000000000000, -1.142980502540, 0.412801598096}; float complex iirfilt_crcf_data_h3x64_x[] = { 0.157714921372 + 0.096933651372*_Complex_I, 0.112931825396 + 0.063629523666*_Complex_I, 0.036350589338 + 0.126527528681*_Complex_I, -0.131639758916 + 0.002850582881*_Complex_I, 0.124813993717 + -0.161564813627*_Complex_I, 0.055810697081 + -0.079984015750*_Complex_I, -0.113597866433 + 0.059629208365*_Complex_I, -0.081276130300 + -0.032884892886*_Complex_I, 0.189206432747 + 0.151230084280*_Complex_I, 0.046653973791 + 0.039106242827*_Complex_I, 0.062707370238 + 0.114770667926*_Complex_I, -0.005370634420 + -0.115131667770*_Complex_I, -0.042638922558 + -0.133249195976*_Complex_I, -0.036786574989 + -0.119823837652*_Complex_I, 0.086588872188 + 0.012335566540*_Complex_I, 0.162897246678 + 0.076457627729*_Complex_I, -0.046976140791 + 0.024454556465*_Complex_I, 0.037224871206 + 0.005544202178*_Complex_I, -0.106866213474 + -0.004556655371*_Complex_I, 0.112442348190 + -0.043675611175*_Complex_I, -0.139836308260 + -0.165558641382*_Complex_I, -0.124475577909 + 0.044150412760*_Complex_I, -0.112036331740 + 0.092938383030*_Complex_I, 0.004665562144 + 0.077748113050*_Complex_I, -0.016082143750 + -0.159087937039*_Complex_I, -0.122649745886 + 0.169674782967*_Complex_I, -0.059903644318 + -0.028174007533*_Complex_I, -0.135926561418 + 0.161939672399*_Complex_I, 0.058515792150 + -0.092207684338*_Complex_I, -0.001328847093 + -0.044399214544*_Complex_I, 0.148659720963 + -0.189463417484*_Complex_I, -0.026581782415 + 0.095051513873*_Complex_I, 0.031890698003 + -0.042421129272*_Complex_I, -0.122306862234 + 0.005962301978*_Complex_I, -0.061265177784 + 0.106033789898*_Complex_I, 0.261292757319 + -0.214947283935*_Complex_I, 0.103799428426 + 0.080318756697*_Complex_I, -0.049679368664 + 0.150833170036*_Complex_I, 0.042691894941 + 0.069350178325*_Complex_I, -0.046630189152 + -0.062689469185*_Complex_I, -0.012129146913 + 0.031853481774*_Complex_I, 0.020440626886 + 0.011527708526*_Complex_I, 0.048482096955 + 0.129990980549*_Complex_I, 0.042635428860 + -0.223911417035*_Complex_I, -0.010964205149 + -0.143631009428*_Complex_I, 0.065181991532 + -0.058004538996*_Complex_I, -0.000090077953 + -0.081470015783*_Complex_I, 0.011047855650 + 0.146709286197*_Complex_I, -0.114534249385 + 0.131496385737*_Complex_I, 0.071234677078 + 0.077433138944*_Complex_I, 0.200723551597 + 0.001379408486*_Complex_I, -0.026760201597 + 0.140751935283*_Complex_I, 0.047450662078 + -0.024838330640*_Complex_I, 0.013847228689 + -0.209058524164*_Complex_I, 0.093422613814 + 0.012081621105*_Complex_I, 0.136809870406 + -0.145382142602*_Complex_I, 0.009187149051 + 0.116724633427*_Complex_I, 0.136993412455 + 0.031913868005*_Complex_I, 0.000837449944 + -0.080964662247*_Complex_I, -0.060279791907 + -0.040256932738*_Complex_I, 0.037791227194 + -0.030926237571*_Complex_I, -0.041416454010 + -0.072873679453*_Complex_I, -0.022768793380 + -0.030601437534*_Complex_I, 0.108180951121 + 0.069467116791*_Complex_I}; float complex iirfilt_crcf_data_h3x64_y[] = { 0.010638703218 + 0.006538686002*_Complex_I, 0.041055083998 + 0.024843109564*_Complex_I, 0.070859923453 + 0.049353938820*_Complex_I, 0.067686035774 + 0.067709646463*_Complex_I, 0.041224538648 + 0.055038544970*_Complex_I, 0.030901594293 + 0.007957479174*_Complex_I, 0.026588402992 + -0.031291537326*_Complex_I, 0.000590470547 + -0.038619471159*_Complex_I, -0.016165649635 + -0.021437053514*_Complex_I, 0.004469726906 + 0.012262241589*_Complex_I, 0.035069044446 + 0.046083751239*_Complex_I, 0.049482788267 + 0.057966414042*_Complex_I, 0.042710472013 + 0.030452084359*_Complex_I, 0.019794496184 + -0.022948199659*_Complex_I, 0.002995531001 + -0.063121775432*_Complex_I, 0.015441215948 + -0.063934986641*_Complex_I, 0.041061093206 + -0.034223045125*_Complex_I, 0.047719585714 + -0.003893175152*_Complex_I, 0.032237020788 + 0.011767694149*_Complex_I, 0.012826028856 + 0.011870448387*_Complex_I, -0.000119320177 + -0.008657506452*_Complex_I, -0.025108083598 + -0.037099080266*_Complex_I, -0.062432000766 + -0.037771955955*_Complex_I, -0.084190602890 + -0.007096982968*_Complex_I, -0.078469021221 + 0.013507514859*_Complex_I, -0.065062852144 + 0.013595810519*_Complex_I, -0.063645820627 + 0.020222934773*_Complex_I, -0.071411851802 + 0.036070220963*_Complex_I, -0.073780802600 + 0.046606489405*_Complex_I, -0.056215295888 + 0.033869398399*_Complex_I, -0.020000348431 + -0.005517294981*_Complex_I, 0.018518800909 + -0.042431351088*_Complex_I, 0.038015719300 + -0.049039042613*_Complex_I, 0.030065702572 + -0.037444083204*_Complex_I, 0.000189612796 + -0.017459075006*_Complex_I, -0.011084433416 + -0.004290467457*_Complex_I, 0.025372744806 + -0.014124980335*_Complex_I, 0.061854301275 + -0.007862452949*_Complex_I, 0.063403692253 + 0.027289128630*_Complex_I, 0.046198628950 + 0.049738403126*_Complex_I, 0.022401700824 + 0.043954279075*_Complex_I, 0.003130865455 + 0.030553031785*_Complex_I, -0.000459085357 + 0.029249594984*_Complex_I, 0.008978406999 + 0.024030129591*_Complex_I, 0.018734404042 + -0.015736413767*_Complex_I, 0.023500424489 + -0.066300146201*_Complex_I, 0.027175003553 + -0.092293433110*_Complex_I, 0.026489439187 + -0.083128349690*_Complex_I, 0.012817484482 + -0.033748033571*_Complex_I, -0.006186235518 + 0.028602009338*_Complex_I, 0.003062407634 + 0.066032501481*_Complex_I, 0.036133722347 + 0.078570737258*_Complex_I, 0.053166399461 + 0.079952991289*_Complex_I, 0.051382646333 + 0.050991991806*_Complex_I, 0.048152970882 + -0.003786577505*_Complex_I, 0.056593380224 + -0.047656514100*_Complex_I, 0.070186171051 + -0.063832284508*_Complex_I, 0.076568506010 + -0.045193020750*_Complex_I, 0.077701414291 + -0.018586956449*_Complex_I, 0.062491319025 + -0.014074548285*_Complex_I, 0.033824419480 + -0.021392925087*_Complex_I, 0.011102622655 + -0.030445232324*_Complex_I, -0.005846867304 + -0.039949067467*_Complex_I, -0.009834168653 + -0.037451411970*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_crcf_data_h5x64.c000066400000000000000000000174611474751757600245130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_crcf_data_h5x64.c: autotest iirfilt data // #include float iirfilt_crcf_data_h5x64_b[] = { 0.004824343358, 0.019297373431, 0.028946060146, 0.019297373431, 0.004824343358}; float iirfilt_crcf_data_h5x64_a[] = { 1.000000000000, -2.369513007182, 2.313988414416, -1.054665405879, 0.187379492368}; float complex iirfilt_crcf_data_h5x64_x[] = { 0.034816486087 + -0.057435933225*_Complex_I, -0.138922686034 + 0.002487157060*_Complex_I, 0.002168200782 + 0.075752631688*_Complex_I, 0.110645778286 + 0.097973148283*_Complex_I, -0.062999498912 + 0.034473236147*_Complex_I, 0.030513585484 + 0.108486942526*_Complex_I, 0.130905798224 + -0.206952317034*_Complex_I, 0.104557822758 + -0.049326363722*_Complex_I, 0.175995475228 + -0.040903480637*_Complex_I, 0.263382017202 + 0.007386489593*_Complex_I, 0.075401623113 + 0.034346157974*_Complex_I, -0.004787311774 + 0.050323428781*_Complex_I, 0.039595621673 + -0.013034423002*_Complex_I, 0.289435339135 + 0.004887226549*_Complex_I, 0.000109192613 + -0.098143317718*_Complex_I, 0.218628727322 + 0.045783638022*_Complex_I, 0.011357280346 + 0.060469524704*_Complex_I, -0.005462153874 + 0.011440185961*_Complex_I, 0.086903581383 + 0.054667638583*_Complex_I, 0.009197661173 + -0.006158688411*_Complex_I, 0.082244960567 + -0.138538495472*_Complex_I, 0.078074527675 + -0.110054617600*_Complex_I, -0.071517687777 + -0.053281282254*_Complex_I, 0.050695873651 + 0.049035186418*_Complex_I, -0.064011859850 + 0.057026886508*_Complex_I, 0.002187309591 + 0.247199024244*_Complex_I, 0.177910643270 + 0.036260952778*_Complex_I, -0.133404966159 + 0.007272659425*_Complex_I, 0.104545832232 + 0.100374198245*_Complex_I, 0.152937259249 + -0.006345268825*_Complex_I, -0.089893987831 + -0.066730853350*_Complex_I, -0.031614665144 + -0.108199665873*_Complex_I, -0.019945023665 + -0.036637064501*_Complex_I, 0.035423077805 + -0.084251698103*_Complex_I, -0.045559909198 + -0.065683835690*_Complex_I, 0.082043588708 + -0.073113783286*_Complex_I, 0.146363247845 + -0.313133192986*_Complex_I, 0.163657926540 + 0.035668446628*_Complex_I, -0.133126328934 + -0.033221937410*_Complex_I, -0.041582597083 + 0.060780541288*_Complex_I, -0.102136662865 + 0.064174466409*_Complex_I, 0.129371455827 + -0.122309646349*_Complex_I, 0.081072163867 + 0.121012321373*_Complex_I, 0.035429837296 + 0.040975877524*_Complex_I, 0.047403447509 + 0.014166128441*_Complex_I, 0.081667476778 + 0.117576764934*_Complex_I, 0.142529344063 + -0.015788307193*_Complex_I, 0.107269994778 + 0.039678416397*_Complex_I, -0.189638285144 + -0.025105560583*_Complex_I, 0.127449393546 + -0.026105377201*_Complex_I, 0.051057729361 + -0.029706326528*_Complex_I, 0.095342091161 + -0.221870514334*_Complex_I, 0.033077914989 + -0.078421433242*_Complex_I, 0.139326073519 + 0.176520418207*_Complex_I, 0.180222947875 + -0.140485235948*_Complex_I, -0.092080231794 + 0.044423535254*_Complex_I, -0.116184788790 + -0.081712392283*_Complex_I, -0.015159814021 + -0.253655296232*_Complex_I, -0.165572835614 + 0.032968825997*_Complex_I, -0.018186027637 + 0.146030996176*_Complex_I, -0.081743534837 + 0.046764387177*_Complex_I, -0.163907916201 + 0.000894565796*_Complex_I, 0.066507006426 + 0.153027239112*_Complex_I, -0.093381553000 + 0.004333390574*_Complex_I}; float complex iirfilt_crcf_data_h5x64_y[] = { 0.000167966683 + -0.000277090663*_Complex_I, 0.000399655237 + -0.001752933682*_Complex_I, -0.001104267382 + -0.004761506250*_Complex_I, -0.006137988749 + -0.006620307024*_Complex_I, -0.012217626919 + -0.002445090386*_Complex_I, -0.014480238497 + 0.010330691717*_Complex_I, -0.010763861323 + 0.028395668560*_Complex_I, -0.000501503170 + 0.042087127701*_Complex_I, 0.017677520131 + 0.040492499282*_Complex_I, 0.044775392784 + 0.020918790830*_Complex_I, 0.079868253591 + -0.007890790986*_Complex_I, 0.117333468546 + -0.032191317082*_Complex_I, 0.145332483454 + -0.041696063730*_Complex_I, 0.153450768495 + -0.034623789141*_Complex_I, 0.143091173002 + -0.017649460381*_Complex_I, 0.125440207813 + -0.001185301267*_Complex_I, 0.110781054574 + 0.007694330137*_Complex_I, 0.102309442381 + 0.009525121208*_Complex_I, 0.096424656974 + 0.009467240886*_Complex_I, 0.087905819414 + 0.011472932774*_Complex_I, 0.075351746332 + 0.015189934128*_Complex_I, 0.061539619627 + 0.015371965161*_Complex_I, 0.050238103007 + 0.005354811389*_Complex_I, 0.042392909138 + -0.015692162843*_Complex_I, 0.035487235197 + -0.039320795693*_Complex_I, 0.026683183579 + -0.051939223046*_Complex_I, 0.016086735480 + -0.042351028087*_Complex_I, 0.007718993110 + -0.009467148500*_Complex_I, 0.005371191435 + 0.034876269506*_Complex_I, 0.009169183447 + 0.073622002790*_Complex_I, 0.018251989832 + 0.094472386300*_Complex_I, 0.030162933688 + 0.092028482193*_Complex_I, 0.038047814129 + 0.066731638129*_Complex_I, 0.035763727219 + 0.025446392854*_Complex_I, 0.023934856252 + -0.020176728351*_Complex_I, 0.008437472733 + -0.058844376262*_Complex_I, -0.003244989715 + -0.085035950076*_Complex_I, -0.003390870214 + -0.101037326348*_Complex_I, 0.012003956420 + -0.111181202859*_Complex_I, 0.036474465180 + -0.114015132267*_Complex_I, 0.054397129333 + -0.103816397690*_Complex_I, 0.053458816959 + -0.078552582252*_Complex_I, 0.035502609681 + -0.044222383504*_Complex_I, 0.014265637465 + -0.010619069148*_Complex_I, 0.003101144454 + 0.016085677224*_Complex_I, 0.006286890891 + 0.034538795527*_Complex_I, 0.020824414839 + 0.045682197348*_Complex_I, 0.042111099700 + 0.051038175528*_Complex_I, 0.064730289486 + 0.051165119231*_Complex_I, 0.079924238054 + 0.045642918872*_Complex_I, 0.080081550492 + 0.034340023196*_Complex_I, 0.067180942535 + 0.017458189468*_Complex_I, 0.051064446907 + -0.005688909571*_Complex_I, 0.040695417558 + -0.033996511064*_Complex_I, 0.040715290376 + -0.059379363759*_Complex_I, 0.051739083738 + -0.071274663107*_Complex_I, 0.067460869459 + -0.066847437344*_Complex_I, 0.074610717895 + -0.053096308826*_Complex_I, 0.062263741557 + -0.042094216632*_Complex_I, 0.029932249437 + -0.041388946019*_Complex_I, -0.013495205238 + -0.045430267433*_Complex_I, -0.055715901366 + -0.041773963667*_Complex_I, -0.087248260391 + -0.024536503294*_Complex_I, -0.103228307102 + 0.002973369704*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_crcf_data_h7x64.c000066400000000000000000000176011474751757600245110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_crcf_data_h7x64.c: autotest iirfilt data // #include float iirfilt_crcf_data_h7x64_b[] = { 0.000340537653, 0.002043225916, 0.005108064791, 0.006810753054, 0.005108064791, 0.002043225916, 0.000340537653}; float iirfilt_crcf_data_h7x64_a[] = { 1.000000000000, -3.579434798331, 5.658667165934, -4.965415228779, 2.529494905841, -0.705274114510, 0.083756479619}; float complex iirfilt_crcf_data_h7x64_x[] = { 0.004233635522 + 0.032166672422*_Complex_I, -0.157552590267 + 0.250368602921*_Complex_I, 0.054267060665 + -0.005044027264*_Complex_I, 0.051025281222 + 0.067245838231*_Complex_I, -0.027078112717 + -0.126549310903*_Complex_I, 0.035527067912 + 0.084082095013*_Complex_I, -0.045166037588 + 0.117512061237*_Complex_I, -0.170543036494 + -0.210138171552*_Complex_I, 0.122017191616 + 0.083315021977*_Complex_I, 0.087665380573 + -0.113419352152*_Complex_I, -0.020592340496 + 0.051461184327*_Complex_I, 0.005438907415 + -0.034203108407*_Complex_I, -0.004238610906 + -0.010875374856*_Complex_I, 0.014448167389 + 0.140297619530*_Complex_I, 0.023037852846 + 0.147634578106*_Complex_I, 0.039831512515 + 0.117367316573*_Complex_I, -0.049079756276 + -0.134214287084*_Complex_I, -0.081369646592 + -0.123999271543*_Complex_I, -0.060778482772 + -0.005943225227*_Complex_I, 0.060096536726 + 0.110619062414*_Complex_I, -0.029590602066 + 0.069542558264*_Complex_I, 0.276694153680 + 0.033847635389*_Complex_I, -0.069801585631 + -0.024433292968*_Complex_I, 0.103527771239 + 0.043047059964*_Complex_I, 0.052392266919 + 0.106611921459*_Complex_I, 0.047921013690 + 0.144591771640*_Complex_I, -0.100885260679 + 0.085422512163*_Complex_I, 0.023817071089 + 0.007631681829*_Complex_I, -0.103520290629 + 0.065084699549*_Complex_I, 0.141218652175 + 0.181817618913*_Complex_I, 0.091918916526 + 0.090132723783*_Complex_I, 0.073412476081 + -0.185654057154*_Complex_I, 0.064690355167 + -0.154617720920*_Complex_I, -0.141562424619 + -0.078498890176*_Complex_I, -0.089061791163 + -0.089972135569*_Complex_I, 0.061285035005 + -0.042181313189*_Complex_I, 0.011648008082 + 0.030075451872*_Complex_I, -0.050030705016 + 0.044231269056*_Complex_I, 0.055904020426 + -0.100086776348*_Complex_I, 0.067035512200 + 0.110427319881*_Complex_I, 0.112195729535 + -0.159140605014*_Complex_I, -0.008321783937 + -0.074224475191*_Complex_I, 0.124554695470 + -0.000035276105*_Complex_I, 0.178233609860 + -0.241786527172*_Complex_I, 0.013428861272 + 0.019929110617*_Complex_I, 0.106814998943 + 0.061446999514*_Complex_I, -0.087662510082 + -0.142756477357*_Complex_I, 0.005116389200 + 0.004875226134*_Complex_I, -0.082163710392 + -0.003854447463*_Complex_I, 0.055960629067 + 0.147529880141*_Complex_I, 0.104198321794 + 0.047973142904*_Complex_I, -0.092852806707 + -0.088517198490*_Complex_I, 0.008453380604 + 0.016712253059*_Complex_I, -0.168237622832 + 0.182661482388*_Complex_I, -0.003676740087 + 0.067558336540*_Complex_I, 0.083397702670 + 0.084971378309*_Complex_I, 0.105858021404 + 0.040735314366*_Complex_I, -0.117228290082 + -0.024601874801*_Complex_I, -0.158931397897 + -0.101660731802*_Complex_I, -0.079872460607 + -0.030609694665*_Complex_I, -0.070191072161 + 0.183132157615*_Complex_I, -0.187191287439 + -0.013144361324*_Complex_I, -0.097352654114 + -0.073775329625*_Complex_I, -0.160782253378 + 0.108482062513*_Complex_I}; float complex iirfilt_crcf_data_h7x64_y[] = { 0.000001441712 + 0.000010953963*_Complex_I, -0.000039841800 + 0.000190192712*_Complex_I, -0.000432579170 + 0.001292948964*_Complex_I, -0.001963477446 + 0.005116752194*_Complex_I, -0.005460987213 + 0.013853437396*_Complex_I, -0.010691848048 + 0.028003970363*_Complex_I, -0.015829219307 + 0.044636043744*_Complex_I, -0.018444702482 + 0.058202478955*_Complex_I, -0.017385042715 + 0.063522217409*_Complex_I, -0.013852978602 + 0.058220061227*_Complex_I, -0.010372120290 + 0.043135943082*_Complex_I, -0.008386259332 + 0.021557712213*_Complex_I, -0.007057894617 + -0.001756678543*_Complex_I, -0.004462600311 + -0.021708921739*_Complex_I, 0.000413860784 + -0.033985730231*_Complex_I, 0.006867599715 + -0.035636537512*_Complex_I, 0.013151792937 + -0.025207996188*_Complex_I, 0.017581663360 + -0.003488920494*_Complex_I, 0.018987594562 + 0.024903700370*_Complex_I, 0.016476110032 + 0.051134067764*_Complex_I, 0.009459018773 + 0.065241189212*_Complex_I, -0.001441469538 + 0.061675106678*_Complex_I, -0.013298737003 + 0.042982674038*_Complex_I, -0.020975009992 + 0.018439112600*_Complex_I, -0.019171489571 + -0.001220893708*_Complex_I, -0.005478667970 + -0.008887635676*_Complex_I, 0.017790116314 + -0.002906881750*_Complex_I, 0.044167796652 + 0.014155489246*_Complex_I, 0.065318293362 + 0.037562815973*_Complex_I, 0.073959143834 + 0.061781091547*_Complex_I, 0.066724360261 + 0.081615483562*_Complex_I, 0.046102292983 + 0.093697367755*_Complex_I, 0.020214021152 + 0.097173425139*_Complex_I, -0.000316969804 + 0.092297203234*_Complex_I, -0.007456572181 + 0.078335403968*_Complex_I, -0.000109513959 + 0.053648935265*_Complex_I, 0.015245116502 + 0.018291043433*_Complex_I, 0.028507759029 + -0.023453077073*_Complex_I, 0.031847159216 + -0.063005523552*_Complex_I, 0.023465571027 + -0.090337797990*_Complex_I, 0.007593101686 + -0.098277994324*_Complex_I, -0.008080860379 + -0.085900545160*_Complex_I, -0.015861382531 + -0.059241419647*_Complex_I, -0.011151330660 + -0.029092859925*_Complex_I, 0.006066947770 + -0.006896796239*_Complex_I, 0.031921995818 + -0.000519982404*_Complex_I, 0.060475303064 + -0.011467885217*_Complex_I, 0.085275600399 + -0.034448894253*_Complex_I, 0.100389600600 + -0.059802028892*_Complex_I, 0.101457128362 + -0.077810326455*_Complex_I, 0.087090251053 + -0.082216982388*_Complex_I, 0.060162530535 + -0.071286280151*_Complex_I, 0.027739822472 + -0.047336780803*_Complex_I, -0.001368012589 + -0.016047415915*_Complex_I, -0.020598333225 + 0.014978961236*_Complex_I, -0.028528780470 + 0.039136270897*_Complex_I, -0.028450797573 + 0.053688158765*_Complex_I, -0.024993006862 + 0.060174099568*_Complex_I, -0.020853885213 + 0.062097322569*_Complex_I, -0.016606097058 + 0.061833377745*_Complex_I, -0.013052589087 + 0.058990818175*_Complex_I, -0.012808887831 + 0.051482609352*_Complex_I, -0.019272140076 + 0.038484586328*_Complex_I, -0.034383553960 + 0.022386350903*_Complex_I}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_rrrf_data_h3x64.c000066400000000000000000000076731474751757600245530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_rrrf_data_h3x64.c: autotest iirfilt data // float iirfilt_rrrf_data_h3x64_b[] = { 0.067455273889, 0.134910547778, 0.067455273889}; float iirfilt_rrrf_data_h3x64_a[] = { 1.000000000000, -1.142980502540, 0.412801598096}; float iirfilt_rrrf_data_h3x64_x[] = { -0.028895214542, -0.069021825021, 0.030604896335, -0.028355924919, 0.116559552929, 0.143033796152, 0.034240066758, 0.245754661028, -0.085048302237, 0.037276632441, -0.027971098990, 0.028792388017, 0.061299546415, 0.019217231932, -0.068210516011, -0.030965552175, -0.104543256906, -0.219154025020, -0.060076982615, 0.175962646540, 0.111681770625, 0.038846767797, -0.074493060382, -0.068437932045, -0.210154533613, -0.059543914700, -0.003275225407, 0.027794772921, 0.001988917543, -0.065169452924, 0.076196405886, -0.110895781816, -0.193987624818, -0.048983036631, -0.057777317818, -0.273728284279, 0.139583588189, -0.048520445612, 0.038028122617, 0.142317597668, 0.006158624121, 0.094921369690, 0.106674550704, -0.007693480844, 0.009150091523, -0.124420550406, -0.048419736980, 0.074400545011, -0.007592916601, -0.023547687981, 0.086672380799, 0.052067890613, 0.134684497125, 0.051380348106, -0.007288328205, -0.053065747221, -0.029240930355, -0.010101089710, -0.143148550970, -0.025032159897, -0.067586830823, 0.279800929422, 0.176230712305, -0.021010061898}; float iirfilt_rrrf_data_h3x64_y[] = { -0.001949134611, -0.010781978190, -0.020715430137, -0.021666234384, -0.010111215930, 0.020847673860, 0.057471408279, 0.087927924056, 0.106503226141, 0.093052363747, 0.059797591762, 0.030618424605, 0.016444297289, 0.017664634020, 0.015528526008, 0.000462009068, -0.021712865669, -0.055983972836, -0.095696176666, -0.097287095541, -0.044473486551, 0.018885017236, 0.047693346170, 0.034670819807, -0.008493798786, -0.061005530002, -0.088651942626, -0.078727771165, -0.049725604069, -0.026589239497, -0.013382207683, -0.005916351681, -0.024144727506, -0.062110319563, -0.084615103632, -0.100637524633, -0.111508046878, -0.088814270452, -0.050047352820, -0.009082968266, 0.032458745755, 0.057683060225, 0.072948677736, 0.079842760097, 0.067920438561, 0.036995173732, -0.005187492618, -0.031107316161, -0.027154581221, -0.015790078206, -0.004680801567, 0.014784961041, 0.040787361040, 0.065664391433, 0.073741325675, 0.056081570347, 0.024036384207, -0.003883289580, -0.027352105314, -0.051342067332, -0.064984304437, -0.045014384740, 0.020451760070, 0.083190163742}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_rrrf_data_h5x64.c000066400000000000000000000100131474751757600245330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_rrrf_data_h5x64.c: autotest iirfilt data // float iirfilt_rrrf_data_h5x64_b[] = { 0.004824343358, 0.019297373431, 0.028946060146, 0.019297373431, 0.004824343358}; float iirfilt_rrrf_data_h5x64_a[] = { 1.000000000000, -2.369513007182, 2.313988414416, -1.054665405879, 0.187379492368}; float iirfilt_rrrf_data_h5x64_x[] = { -0.071435037288, -0.013824638625, 0.000604766808, -0.157245338765, -0.148499909731, 0.036854467235, -0.092170127241, -0.030750688358, -0.256687046040, -0.011293794477, -0.152735111898, -0.039350864050, -0.026481755383, 0.026344708916, -0.165804900216, 0.075110855166, 0.169733039664, 0.112960857425, 0.102855045747, -0.058065586616, -0.019482689014, -0.069631526814, 0.080391768879, -0.148962611101, -0.063224959929, 0.177207853044, 0.064119106525, 0.182006292285, 0.032851335390, 0.025859709218, 0.012249245529, 0.020538703403, -0.010050632447, 0.157918073531, 0.155799289392, 0.161618591338, -0.061931920946, -0.002480403144, -0.080860681406, -0.119527652190, 0.041981586004, 0.049388453948, -0.119534817516, -0.004446996769, -0.010415835934, 0.070065217532, 0.016956615378, 0.196554086088, -0.089159910224, 0.005262040310, 0.025380561695, -0.190719045717, -0.137704432243, -0.012169688901, -0.072683558269, 0.115787622162, -0.013755488460, 0.060139162368, 0.002047451288, 0.123978241358, 0.006962698789, -0.019071948553, -0.062140245356, -0.111724700578}; float iirfilt_rrrf_data_h5x64_y[] = { -0.000344627148, -0.002261801903, -0.006893530299, -0.013989605147, -0.023862607597, -0.038312044528, -0.056089194368, -0.071280615399, -0.079550560246, -0.083028835474, -0.086748998983, -0.092533693567, -0.097949600919, -0.098429082259, -0.090466124573, -0.075337575372, -0.056782281433, -0.034261954387, -0.004056342067, 0.032512857031, 0.065692345386, 0.082703529450, 0.076861903089, 0.052102523397, 0.018224928933, -0.015275405731, -0.038407046800, -0.040894489472, -0.018910631091, 0.020295410235, 0.061246521124, 0.088475490616, 0.094228350367, 0.080859234115, 0.059352937798, 0.044593577702, 0.046274753880, 0.061145236873, 0.075354763624, 0.074888924042, 0.054105775368, 0.018945116326, -0.016551695165, -0.040692464489, -0.050718972892, -0.049083944974, -0.038287527306, -0.019928604327, 0.004267855964, 0.029703630925, 0.048181600553, 0.052618134862, 0.039776735477, 0.010021908144, -0.029959006998, -0.066860943714, -0.086821708742, -0.082569377253, -0.056991021236, -0.020344296462, 0.016435506907, 0.045346639362, 0.060576452509, 0.058193434336}; liquid-dsp-1.7.0/src/filter/tests/data/iirfilt_rrrf_data_h7x64.c000066400000000000000000000101331474751757600245400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // iirfilt_rrrf_data_h7x64.c: autotest iirfilt data // float iirfilt_rrrf_data_h7x64_b[] = { 0.000340537653, 0.002043225916, 0.005108064791, 0.006810753054, 0.005108064791, 0.002043225916, 0.000340537653}; float iirfilt_rrrf_data_h7x64_a[] = { 1.000000000000, -3.579434798331, 5.658667165934, -4.965415228779, 2.529494905841, -0.705274114510, 0.083756479619}; float iirfilt_rrrf_data_h7x64_x[] = { 0.014320460019, -0.048569878607, -0.028557745674, -0.034174525472, 0.041246019674, 0.176001687252, 0.069536678145, 0.085964825944, -0.085126074719, -0.107634084553, 0.014274481662, -0.086938201253, 0.041217197713, -0.012812412897, 0.112987870327, -0.147787754865, 0.049941237222, 0.088160959037, 0.142541502659, -0.024664403921, 0.087433714309, -0.131271281366, -0.101343790061, -0.095899142873, 0.077515723928, -0.128215021128, -0.085076363355, 0.019632244375, -0.024601764309, 0.135464981990, -0.096554438720, -0.055332193061, 0.107799859774, 0.016856032152, -0.133717866605, 0.107909223614, -0.000321585843, -0.040614549926, -0.065576753282, 0.080916136192, -0.062112903973, 0.097792565904, 0.053573189262, 0.101970184507, 0.007522028461, -0.110691703882, 0.182044058589, -0.040926270512, -0.092754193263, -0.034827070696, -0.046124677770, 0.127874701414, 0.085875818987, -0.157133769105, -0.116516897741, -0.217687959211, 0.111806530552, -0.053629641350, -0.117298829882, 0.008546053824, -0.015153030008, -0.012695501670, -0.154176199014, -0.055346850979}; float iirfilt_rrrf_data_h7x64_y[] = { 0.000004876656, 0.000030175734, 0.000044602316, -0.000207441342, -0.001316715725, -0.003834371001, -0.007275018208, -0.009225570706, -0.005882384450, 0.005486878229, 0.023590162522, 0.042219969073, 0.052802355644, 0.049012293557, 0.030431004460, 0.003094166085, -0.023276941451, -0.039861135430, -0.042388322400, -0.031669690474, -0.011613377381, 0.012796864675, 0.036227386395, 0.053027192148, 0.057804353706, 0.047254362471, 0.022407095078, -0.010858715211, -0.043986796642, -0.068957103048, -0.080449888307, -0.076669122221, -0.059625824351, -0.034801293799, -0.009374291628, 0.010427870419, 0.021114523610, 0.022335161439, 0.016423814986, 0.007136897293, -0.002051012043, -0.008952563583, -0.012527673359, -0.012220519177, -0.007483592886, 0.002024488272, 0.015481250523, 0.030132672907, 0.041993092794, 0.047610337377, 0.045176156453, 0.034600601261, 0.017674973347, -0.001466118954, -0.017059538441, -0.024634672249, -0.024401342427, -0.021654066688, -0.023062032857, -0.031927019266, -0.046389502559, -0.061179016193, -0.070675753063, -0.071539050622}; liquid-dsp-1.7.0/src/filter/tests/dds_cccf_autotest.c000066400000000000000000000165651474751757600227000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // check direct digital synthesis, both interpolator and decimator void testbench_dds_cccf(unsigned int _num_stages, // number of half-band stages float _fc, // filter cut-off float _as) // stop-band suppression { float tol = 1; // error tolerance [dB] float bw = 0.1f; // original pulse bandwidth unsigned int m = 40; // pulse semi-length unsigned int r=1<<_num_stages; // resampling rate (output/input) // create resampler dds_cccf q = dds_cccf_create(_num_stages,_fc,bw,_as); dds_cccf_set_scale(q, 1.0f/r); if (liquid_autotest_verbose) dds_cccf_print(q); unsigned int delay_interp = dds_cccf_get_delay_interp(q); float delay_decim = dds_cccf_get_delay_decim (q); unsigned int h_len = 2*r*m+1; // pulse length unsigned int num_samples = h_len + delay_interp + (unsigned int) delay_decim + 8; unsigned int i; float complex * buf_0 = (float complex*) malloc(num_samples *sizeof(float complex)); // input float complex * buf_1 = (float complex*) malloc(num_samples*r*sizeof(float complex)); // interpolated float complex * buf_2 = (float complex*) malloc(num_samples *sizeof(float complex)); // decimated // generate the baseband signal (filter pulse) float h[h_len]; float w = 0.36f * bw; // pulse bandwidth liquid_firdes_kaiser(h_len,w,_as,0.0f,h); for (i=0; i #include "autotest/autotest.h" #include "liquid.internal.h" // test setting filter delay void testbench_fdelay_rrrf(unsigned int _nmax, unsigned int _m, unsigned int _npfb, float _delay) { float tol = 0.01f; unsigned int num_samples = _nmax + 2*_m; // number of samples to run // create delay object and split delay between set and adjust methods fdelay_rrrf q = fdelay_rrrf_create(_nmax, _m, _npfb); fdelay_rrrf_set_delay (q, _delay*0.7f); fdelay_rrrf_adjust_delay(q, _delay*0.3f); // ensure object is configured properly CONTEND_EQUALITY(fdelay_rrrf_get_nmax (q), _nmax); CONTEND_EQUALITY(fdelay_rrrf_get_m (q), _m); CONTEND_EQUALITY(fdelay_rrrf_get_npfb (q), _npfb); CONTEND_DELTA (fdelay_rrrf_get_delay(q), _delay, 1e-6f); // generate impulse and propagate through object float x[num_samples]; float y[num_samples]; unsigned int i; // generate input for (i=0; i #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper function // _h : filter coefficients // _h_len : filter coefficients length // _x : input array // _x_len : input array length // _y : output array // _y_len : output array length void fftfilt_rrrf_test(float * _h, unsigned int _h_len, float * _x, unsigned int _x_len, float * _y, unsigned int _y_len) { float tol = 0.001f; // determine appropriate block size // NOTE: this number can be anything at least _h_len-1 unsigned int n = 1 << liquid_nextpow2(_h_len-1); // determine number of blocks div_t d = div(_x_len, n); unsigned int num_blocks = d.quot + (d.rem ? 1 : 0); if (liquid_autotest_verbose) { printf("fftfilt_rrrf_test(), h_len: %3u, x_len: %3u (%3u blocks @ %3u samples, %3u remaining)\n", _h_len, _x_len, n, d.quot, d.rem); } // load filter coefficients externally fftfilt_rrrf q = fftfilt_rrrf_create(_h, _h_len, n); // allocate memory for output float y_test[n*num_blocks]; unsigned int i; // compute output in blocks of size 'n' for (i=0; i= nfft/2 ? -1.0f : 0.0f); float complex H; liquid_freqrespf(h, h_len, fc, &H); CONTEND_DELTA(crealf(buf_freq[i]), crealf(H), tol); CONTEND_DELTA(cimagf(buf_freq[i]), cimagf(H), tol); } } // check frequency response (complex-valued coefficients) void autotest_liquid_freqrespcf() { // design filter and apply complex phasor unsigned int i, h_len = 41; float hf[h_len]; liquid_firdes_kaiser(h_len, 0.27f, 80.0f, 0.3f, hf); float complex h[h_len]; for (i=0; i= nfft/2 ? -1.0f : 0.0f); float complex H; liquid_freqrespcf(h, h_len, fc, &H); CONTEND_DELTA(crealf(buf_freq[i]), crealf(H), tol); CONTEND_DELTA(cimagf(buf_freq[i]), cimagf(H), tol); } } liquid-dsp-1.7.0/src/filter/tests/firdespm_autotest.c000066400000000000000000000331501474751757600227460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // References: // [McClellan:1973] J. H. McClellan, T. W. Parks, L. R. Rabiner, "A // Computer Program for Designing Optimum FIR Linear Phase // Digital Filters," IEEE Transactions on Audio and // Electroacoustics, vol. AU-21, No. 6, December 1973. #include "autotest/autotest.h" #include "liquid.h" void autotest_firdespm_bandpass_n24() { // [McClellan:1973], Figure 7. // Initialize variables unsigned int n=24; unsigned int num_bands=2; float bands[4] = {0.0f,0.08f,0.16f,0.50f}; float des[2] = {1.0f,0.0f}; float weights[2]= {1.0f,1.0f}; liquid_firdespm_btype btype = LIQUID_FIRDESPM_BANDPASS; float tol = 1e-4f; // Initialize pre-determined coefficient array float h0[24] = { 0.33740917e-2f, 0.14938299e-1f, 0.10569360e-1f, 0.25415067e-2f, -0.15929392e-1f, -0.34085343e-1f, -0.38112177e-1f, -0.14629169e-1f, 0.40089541e-1f, 0.11540713e-0f, 0.18850752e-0f, 0.23354606e-0f, // symmetry 0.23354606e-0f, 0.18850752e-0f, 0.11540713e-0f, 0.40089541e-1f, -0.14629169e-1f, -0.38112177e-1f, -0.34085343e-1f, -0.15929392e-1f, 0.25415067e-2f, 0.10569360e-1f, 0.14938299e-1f, 0.33740917e-2f }; // Create filter float h[n]; firdespm_run(n,num_bands,bands,des,weights,NULL,btype,h); // Ensure data are equal unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small void firfilt_cccf_notch_test_harness(unsigned int _m, float _as, float _f0) { unsigned int num_samples = 600; // number of samples unsigned int h_len = 2*_m+1; // filter length // design filter from prototype firfilt_cccf q = firfilt_cccf_create_notch(_m,_as,_f0); // generate input signal unsigned int i; float x2 = 0.0f; float y2 = 0.0f; for (i=0; i= h_len) { x2 += cabsf(x)*cabsf(x); y2 += cabsf(y)*cabsf(y); } } // compare result x2 = sqrtf(x2 / (float)num_samples); y2 = sqrtf(y2 / (float)num_samples); if (liquid_autotest_verbose) { firfilt_cccf_print(q); printf("f0 = %.8f, x2: %f, y2: %f\n", _f0, x2, y2); } float tol = 1e-3f; CONTEND_DELTA(x2, 1.0f, tol); CONTEND_DELTA(y2, 0.0f, tol); // destroy filter object firfilt_cccf_destroy(q); } // AUTOTESTS: void autotest_firfilt_cccf_notch_0() { firfilt_cccf_notch_test_harness(20,60.0f, 0.000f); } void autotest_firfilt_cccf_notch_1() { firfilt_cccf_notch_test_harness(20,60.0f, 0.100f); } void autotest_firfilt_cccf_notch_2() { firfilt_cccf_notch_test_harness(20,60.0f, 0.456f); } void autotest_firfilt_cccf_notch_3() { firfilt_cccf_notch_test_harness(20,60.0f, 0.500f); } void autotest_firfilt_cccf_notch_4() { firfilt_cccf_notch_test_harness(20,60.0f,-0.250f); } void autotest_firfilt_cccf_notch_5() { firfilt_cccf_notch_test_harness(20,60.0f,-0.389f); } liquid-dsp-1.7.0/src/filter/tests/firfilt_coefficients_autotest.c000066400000000000000000000047001474751757600253140ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" void autotest_firfilt_cccf_coefficients_test() { // create filter coefficients (semi-random) unsigned int h_len = 71; float complex * h0 = (float complex*) malloc(h_len*sizeof(float complex)); float complex * h1 = (float complex*) malloc(h_len*sizeof(float complex)); unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // check square-root Nyquist filter design and response void testbench_firfilt_rnyquist(int _ftype,// filter type unsigned int _k, // samples/symbol unsigned int _m, // semi-length float _beta, // excess bandwidth factor float _dt) // fractional delay { // derived values unsigned int i; unsigned int h_len = 2*_k*_m+1; // transmit/receive filter length unsigned int hc_len = 4*_k*_m+1; // composite filter length // arrays float ht[h_len]; // transmit filter float hr[h_len]; // receive filter (different for GMSK) float hc[hc_len]; // composite filter // design the filter(s) liquid_firdes_prototype(_ftype, _k, _m, _beta, _dt, ht); // special case for GMSK if (_ftype == LIQUID_FIRFILT_GMSKTX) liquid_firdes_prototype(LIQUID_FIRFILT_GMSKRX, _k, _m, _beta, _dt, hr); else memcpy(hr, ht, h_len*sizeof(float)); // TODO: check group delay // compute composite filter response (auto-correlation) for (i=0; i {%12.8f, %12.8f}, {%12.8f, %12.8f}\n", i, crealf(x), cimagf(x), y0[0], y0[1], y1[0], y1[1]); } CONTEND_EQUALITY(y0[0], y1[0]); CONTEND_EQUALITY(y0[1], y1[1]); } // destroy objects firhilbf_destroy(q0); firhilbf_destroy(q1); } void autotest_firhilbf_copy_decim() { firhilbf q0 = firhilbf_create(12,120.0f); // run interpolator on random data unsigned int i; float x[2]; float complex y0, y1; for (i=0; i<80; i++) { x[0] = randnf(); x[1] = randnf(); firhilbf_decim_execute(q0, x, &y0); } // copy object firhilbf q1 = firhilbf_copy(q0); for (i=0; i<80; i++) { x[0] = randnf(); x[1] = randnf(); firhilbf_decim_execute(q0, x, &y0); firhilbf_decim_execute(q1, x, &y1); if (liquid_autotest_verbose) { printf("%3u : {%12.8f %12.8f} > %12.8f +j%12.8f, %12.8f +j%12.8f\n", i, x[0], x[1], crealf(y0), cimagf(y0), crealf(y1), cimagf(y1)); } CONTEND_EQUALITY(y0, y1); } // destroy objects firhilbf_destroy(q0); firhilbf_destroy(q1); } liquid-dsp-1.7.0/src/filter/tests/firinterp_autotest.c000066400000000000000000000212751474751757600231440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" void autotest_firinterp_rrrf_common() { firinterp_rrrf interp = firinterp_rrrf_create_kaiser(17, 4, 60.0f); CONTEND_EQUALITY(firinterp_rrrf_get_interp_rate(interp), 17); firinterp_rrrf_destroy(interp); } void autotest_firinterp_crcf_common() { firinterp_crcf interp = firinterp_crcf_create_kaiser(7, 4, 60.0f); CONTEND_EQUALITY(firinterp_crcf_get_interp_rate(interp), 7); firinterp_crcf_destroy(interp); } // // AUTOTEST: // void autotest_firinterp_rrrf_generic() { float h[9] = { -0.2762293319046737, 1.4757679031218007, 0.1432569489572376, -0.2142368750177835, 1.3471241294836864, 0.1166010284926269, 0.0536534505390281, 0.1412672462812405, -0.0991854372394269}; unsigned int M = 4; // firinterp factor firinterp_rrrf q = firinterp_rrrf_create(M,h,9); float x[] = {1.0, -1.0, 1.0, 1.0}; float y[16]; float test[16] = { -0.2762293319046737, 1.4757679031218007, 0.1432569489572376, -0.2142368750177835, 1.6233534613883602, -1.3591668746291738, -0.0896034984182095, 0.3555041212990241, -1.7225388986277870, 1.3591668746291738, 0.0896034984182095, -0.3555041212990241, 1.1700802348184398, 1.5923689316144276, 0.1969103994962658, -0.0729696287365430}; float tol = 1e-6; unsigned int i; for (i=0; i<4; i++) firinterp_rrrf_execute(q, x[i], &y[i*M]); for (i=0; i<16; i++) { CONTEND_DELTA(y[i], test[i], tol); if (liquid_autotest_verbose) printf(" y(%u) = %8.4f;\n", i+1, y[i]); } if (liquid_autotest_verbose) firinterp_rrrf_print(q); // destroy interpolator object firinterp_rrrf_destroy(q); } void autotest_firinterp_crcf_generic() { // h = [0, 0.25, 0.5, 0.75, 1.0, 0.75, 0.5, 0.25, 0]; float h[9] = { -0.7393353832652201, 0.1909821993029451, -1.7013834621383086, -0.6157406339062349, 0.5806218191269317, 0.0576963976148674, -1.0958217797368455, -0.6379821629743743, 0.7019489165905530}; unsigned int M = 4; // firinterp factor firinterp_crcf q = firinterp_crcf_create(M,h,9); // x = [1+j*0.2, -0.2+j*1.3, 0.5+j*0.3, 1.1-j*0.2] float complex x[4] = { 1.0000e+00+ 2.0000e-01*_Complex_I, -2.0000e-01+ 1.3000e+00*_Complex_I, 5.0000e-01+ 3.0000e-01*_Complex_I, 1.1000e+00+ -2.0000e-01*_Complex_I }; float complex y[16]; // z = [x(1) 0 0 0 x(2) 0 0 0 x(3) 0 0 0 x(4) 0 0 0]; // test = filter(h,1,z) float complex test[16] = { -0.7393353832652201 - 0.1478670766530440*_Complex_I, 0.1909821993029451 + 0.0381964398605890*_Complex_I, -1.7013834621383086 - 0.3402766924276617*_Complex_I, -0.6157406339062349 - 0.1231481267812470*_Complex_I, 0.7284888957799757 - 0.8450116344193997*_Complex_I, 0.0194999577542784 + 0.2598161386168021*_Complex_I, -0.7555450873091838 - 2.4309628567271702*_Complex_I, -0.5148340361931273 - 0.9280592566729803*_Complex_I, 0.2161568611325566 + 0.6733975332035558*_Complex_I, 0.0839518201284991 + 0.1322999766902112*_Complex_I, -0.6315273751217851 - 1.9349833522993918*_Complex_I, -0.1802738843582426 - 1.0140990020385570*_Complex_I, -0.6633477953463869 + 1.2345872139588425*_Complex_I, 0.2389286180406733 - 0.0208875205761288*_Complex_I, -2.4194326982205623 + 0.0115301585066081*_Complex_I, -0.9963057787840456 - 0.0682465221110653*_Complex_I }; float tol = 1e-6; unsigned int i; for (i=0; i<4; i++) firinterp_crcf_execute(q, x[i], &y[i*M]); for (i=0; i<16; i++) { CONTEND_DELTA( crealf(y[i]), crealf(test[i]), tol); CONTEND_DELTA( cimagf(y[i]), cimagf(test[i]), tol); if (liquid_autotest_verbose) printf(" y(%u) = %8.4f + j%8.4f;\n", i+1, crealf(y[i]), cimagf(y[i])); } if (liquid_autotest_verbose) firinterp_crcf_print(q); // destroy interpolator object firinterp_crcf_destroy(q); } // test Nyquist filter void testbench_firinterp_crcf_nyquist(int _ftype, unsigned int _M, unsigned int _m, float _beta) { float tol = 1e-6; // create interpolator object firinterp_crcf q = firinterp_crcf_create_prototype(_ftype, _M, _m, _beta, 0); // create input buffer of symbols to interpolate unsigned int num_symbols = _m+16; // float complex x[num_symbols]; // input symbols float complex y[_M]; // output interp buffer unsigned int i; for (i=0; i= _m) { CONTEND_DELTA( crealf(x[i-_m]), crealf(y[0]), tol); CONTEND_DELTA( cimagf(x[i-_m]), cimagf(y[0]), tol); if (liquid_autotest_verbose) { printf("%3u: x=%8.4f + j%8.4f, y=%8.4f + j%8.4f;\n", i+1, crealf(x[i-_m]), cimagf(x[i-_m]), crealf(y[ 0]), cimagf(y[ 0])); } } } // destroy interpolator object firinterp_crcf_destroy(q); } // add specific tests void autotest_firinterp_crcf_rnyquist_0() { testbench_firinterp_crcf_nyquist(LIQUID_FIRFILT_KAISER, 2, 9,0.3f); } void autotest_firinterp_crcf_rnyquist_1() { testbench_firinterp_crcf_nyquist(LIQUID_FIRFILT_KAISER, 3, 9,0.3f); } void autotest_firinterp_crcf_rnyquist_2() { testbench_firinterp_crcf_nyquist(LIQUID_FIRFILT_KAISER, 7, 9,0.3f); } void autotest_firinterp_crcf_rnyquist_3() { testbench_firinterp_crcf_nyquist(LIQUID_FIRFILT_RCOS, 2, 9,0.3f); } // test copy method void autotest_firinterp_copy() { // create base object firinterp_crcf q0 = firinterp_crcf_create_kaiser(3, 7, 60.0f); firinterp_crcf_set_scale(q0, 0.12345f); // run samples through filter unsigned int i; float complex buf_0[3], buf_1[3]; for (i=0; i<20; i++) { float complex v = randnf() + _Complex_I*randnf(); firinterp_crcf_execute(q0, v, buf_0); } // copy object firinterp_crcf q1 = firinterp_crcf_copy(q0); // run samples through both filters in parallel for (i=0; i<60; i++) { float complex v = randnf() + _Complex_I*randnf(); firinterp_crcf_execute(q0, v, buf_0); firinterp_crcf_execute(q1, v, buf_1); CONTEND_SAME_DATA( buf_0, buf_1, 3*sizeof(float complex) ); } // destroy objects firinterp_crcf_destroy(q0); firinterp_crcf_destroy(q1); } // test flush method(s) void autotest_firinterp_flush() { // create base object unsigned int m = 7; firinterp_crcf q = firinterp_crcf_create_kaiser(3, m, 60.0f); // run samples through filter unsigned int i; float complex buf[3]; for (i=0; i<20; i++) { float complex v = randnf() + _Complex_I*randnf(); firinterp_crcf_execute(q, v, buf); } // ensure buffer does not contain zeros CONTEND_GREATER_THAN( liquid_sumsqcf(buf,3), 0.0f ); // flush buffer for (i=0; i<2*m; i++) firinterp_crcf_flush(q, buf); // ensure buffer contains only zeros CONTEND_EQUALITY( liquid_sumsqcf(buf,3), 0.0f ); // destroy objects firinterp_crcf_destroy(q); } liquid-dsp-1.7.0/src/filter/tests/firpfb_autotest.c000066400000000000000000000073061474751757600224110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" void autotest_firpfb_impulse_response() { // Initialize variables float tol=1e-4f; // k=2, m=3, beta=0.3, npfb=4; // h=rrcos(k*npfb,m,beta); float h[48] = { -0.033116, -0.024181, -0.006284, 0.018261, 0.045016, 0.068033, 0.080919, 0.078177, 0.056597, 0.016403, -0.038106, -0.098610, -0.153600, -0.189940, -0.194900, -0.158390, -0.075002, 0.054511, 0.222690, 0.415800, 0.615340, 0.800390, 0.950380, 1.048100, 1.082000, 1.048100, 0.950380, 0.800390, 0.615340, 0.415800, 0.222690, 0.054511, -0.075002, -0.158390, -0.194900, -0.189940, -0.153600, -0.098610, -0.038106, 0.016403, 0.056597, 0.078177, 0.080919, 0.068033, 0.045016, 0.018261, -0.006284, -0.024181 }; // filter input float noise[12] = { 0.438310, 1.001900, 0.200600, 0.790040, 1.134200, 1.592200, -0.702980, -0.937560, -0.511270, -1.684700, 0.328940, -0.387780 }; // expected filter outputs float test[4] = { 2.05558467194397f, 1.56922189602661f, 0.998479744645138, 0.386125857849177 }; // Load filter coefficients externally firpfb_rrrf f = firpfb_rrrf_create(4, h, 48); unsigned int i; for (i=0; i<12; i++) firpfb_rrrf_push(f,noise[i]); float y; for (i=0; i<4; i++) { firpfb_rrrf_execute(f,i,&y); CONTEND_DELTA(test[i],y,tol); } firpfb_rrrf_destroy(f); } void autotest_firpfb_crcf_copy() { // create base object with irregular parameters unsigned int M = 13, m = 7; firpfb_crcf q0 = firpfb_crcf_create_default(M, m); // run random samples through filter unsigned int i, num_samples = 80; for (i=0; i {%12.8f, %12.8f}, {%12.8f, %12.8f}\n", i, crealf(x), cimagf(x), y0[0], y0[1], y1[0], y1[1]); } CONTEND_EQUALITY(y0[0], y1[0]); CONTEND_EQUALITY(y0[1], y1[1]); } // destroy objects iirhilbf_destroy(q0); iirhilbf_destroy(q1); } void autotest_iirhilbf_copy_decim() { // create base object iirhilbf q0 = iirhilbf_create(LIQUID_IIRDES_ELLIP,7,0.1f,80.0f); // run interpolator on random data unsigned int i; float x[2]; float complex y0, y1; for (i=0; i<80; i++) { x[0] = randnf(); x[1] = randnf(); iirhilbf_decim_execute(q0, x, &y0); } // copy object and run samples through each in parallel iirhilbf q1 = iirhilbf_copy(q0); for (i=0; i<80; i++) { x[0] = randnf(); x[1] = randnf(); iirhilbf_decim_execute(q0, x, &y0); iirhilbf_decim_execute(q1, x, &y1); if (liquid_autotest_verbose) { printf("%3u : {%12.8f %12.8f} > %12.8f +j%12.8f, %12.8f +j%12.8f\n", i, x[0], x[1], crealf(y0), cimagf(y0), crealf(y1), cimagf(y1)); } CONTEND_EQUALITY(y0, y1); } // destroy filter objects iirhilbf_destroy(q0); iirhilbf_destroy(q1); } liquid-dsp-1.7.0/src/filter/tests/iirinterp_autotest.c000066400000000000000000000106771474751757600231530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // test rational-rate resampler void test_iirinterp_crcf(const char * _method, unsigned int _interp, unsigned int _order) { // options unsigned int n = 800000; // number of output samples to analyze float bw = 0.2f; // target output bandwidth unsigned int nfft = 800; // number of bins in transform float As = 60.0f; // error tolerance [dB] float tol = 0.5f; // error tolerance [dB] // create resampler with rate _interp/_decim iirinterp_crcf interp = iirinterp_crcf_create_default(_interp, _order); // create and configure objects spgramcf q = spgramcf_create(nfft, LIQUID_WINDOW_HANN, nfft/2, nfft/4); symstreamrcf gen = symstreamrcf_create_linear(LIQUID_FIRFILT_KAISER,bw*_interp,25,0.2f,LIQUID_MODEM_QPSK); symstreamrcf_set_gain(gen, sqrtf(bw)); // generate samples and push through spgram object unsigned int block_size = 10; float complex buf_0[block_size]; // input buffer float complex buf_1[block_size*_interp]; // output buffer while (spgramcf_get_num_samples_total(q) < n) { // generate block of samples symstreamrcf_write_samples(gen, buf_0, block_size); // interpolate iirinterp_crcf_execute_block(interp, buf_0, block_size, buf_1); // run samples through the spgram object spgramcf_write(q, buf_1, block_size*_interp); } // verify result float psd[nfft]; spgramcf_get_psd(q, psd); autotest_psd_s regions[] = { {.fmin=-0.5f, .fmax=-0.6f*bw, .pmin=0, .pmax=-As+tol, .test_lo=0, .test_hi=1}, {.fmin=-0.4f*bw, .fmax=+0.4f*bw, .pmin=0-tol, .pmax= 0+tol, .test_lo=1, .test_hi=1}, {.fmin=+0.6f*bw, .fmax=+0.5f, .pmin=0, .pmax=-As+tol, .test_lo=0, .test_hi=1}, }; char filename[256]; sprintf(filename,"autotest/logs/iirinterp_crcf_M%u_O%u.m", _interp, _order); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, liquid_autotest_verbose ? filename : NULL); // destroy objects iirinterp_crcf_destroy(interp); spgramcf_destroy(q); symstreamrcf_destroy(gen); } // baseline tests using create_kaiser() method void autotest_iirinterp_crcf_M2_O9() { test_iirinterp_crcf("baseline", 2, 9); } void autotest_iirinterp_crcf_M3_O9() { test_iirinterp_crcf("baseline", 3, 9); } void autotest_iirinterp_crcf_M4_O9() { test_iirinterp_crcf("baseline", 4, 9); } // test copy method void autotest_iirinterp_copy() { // create base object iirinterp_crcf q0 = iirinterp_crcf_create_default(3, 7); //iirinterp_crcf_set_scale(q0, 0.12345f); // run samples through filter unsigned int i; float complex buf_0[3], buf_1[3]; for (i=0; i<20; i++) { float complex v = randnf() + _Complex_I*randnf(); iirinterp_crcf_execute(q0, v, buf_0); } // copy object iirinterp_crcf q1 = iirinterp_crcf_copy(q0); // run samples through both filters in parallel for (i=0; i<60; i++) { float complex v = randnf() + _Complex_I*randnf(); iirinterp_crcf_execute(q0, v, buf_0); iirinterp_crcf_execute(q1, v, buf_1); CONTEND_SAME_DATA( buf_0, buf_1, 3*sizeof(float complex) ); } // destroy objects iirinterp_crcf_destroy(q0); iirinterp_crcf_destroy(q1); } liquid-dsp-1.7.0/src/filter/tests/lpc_autotest.c000066400000000000000000000101711474751757600217110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2019 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small // _n : input sample size // _p : order // _fc : filter cut-off frequency // _tol : RMS error tolerance (dB) void lpc_test_harness(unsigned int _n, unsigned int _p, float _fc, float _tol) { // create low-pass filter object iirfilt_rrrf lowpass = iirfilt_rrrf_create_lowpass(7,_fc); // allocate memory for data arrays float y[_n]; // input signal (filtered noise) float a_hat[_p+1]; // lpc output float g_hat[_p+1]; // lpc output // generate input signal (filtered noise) unsigned int i; msequence ms = msequence_create_default(15); for (i=0; i<_n; i++) { // rough, but simple uniform random variable float v = (float)msequence_generate_symbol(ms,10)/1023.0f - 0.5f; // filter result iirfilt_rrrf_execute(lowpass, v, &y[i]); } // run linear prediction algorithm liquid_lpc(y,_n,_p,a_hat,g_hat); // create linear prediction filter float a_lpc[_p+1]; float b_lpc[_p+1]; for (i=0; i<_p+1; i++) { a_lpc[i] = (i==0) ? 1.0f : 0.0f; b_lpc[i] = (i==0) ? 0.0f : -a_hat[i]; } iirfilt_rrrf lpc = iirfilt_rrrf_create(b_lpc,_p+1, a_lpc,_p+1); // compute prediction error over random sequence // NOTE: no need to reset objects here float rmse = 0.0f; unsigned int n_error = 5000; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // test rational-rate resampler void test_rresamp_crcf(const char * _method, unsigned int _interp, unsigned int _decim, unsigned int _m, float _bw, float _as) { // options unsigned int n = 800000; // number of output samples to analyze float bw = 0.2f; // target output bandwidth unsigned int nfft = 800; // number of bins in transform float tol = 0.5f; // error tolerance [dB] // create resampler with rate _interp/_decim rresamp_crcf resamp = NULL; if (strcmp(_method,"baseline")==0) { resamp = rresamp_crcf_create_kaiser(_interp, _decim, _m, _bw, _as); } else if (strcmp(_method,"default")==0) { resamp = rresamp_crcf_create_default(_interp, _decim); } else { //printf("creating resampler using %s\n", _method); int ftype = liquid_getopt_str2firfilt(_method); float beta = _bw; // rename to avoid confusion resamp = rresamp_crcf_create_prototype(ftype, _interp, _decim, _m, beta); } if (resamp == NULL) { liquid_autotest_failed(); return; } float r = rresamp_crcf_get_rate(resamp); // create and configure objects spgramcf q = spgramcf_create(nfft, LIQUID_WINDOW_HANN, nfft/2, nfft/4); symstreamrcf gen = symstreamrcf_create_linear(LIQUID_FIRFILT_KAISER,r*bw,25,0.2f,LIQUID_MODEM_QPSK); symstreamrcf_set_gain(gen, sqrtf(bw*r)); // generate samples and push through spgram object float complex buf_0[_decim]; // input buffer float complex buf_1[_interp]; // output buffer while (spgramcf_get_num_samples_total(q) < n) { // generate block of samples symstreamrcf_write_samples(gen, buf_0, _decim); // resample rresamp_crcf_execute(resamp, buf_0, buf_1); // run samples through the spgram object spgramcf_write(q, buf_1, _interp); } // verify result float psd[nfft]; spgramcf_get_psd(q, psd); autotest_psd_s regions[] = { {.fmin=-0.5f, .fmax=-0.6f*bw, .pmin=0, .pmax=-_as+tol, .test_lo=0, .test_hi=1}, {.fmin=-0.4f*bw, .fmax=+0.4f*bw, .pmin=0-tol, .pmax= 0 +tol, .test_lo=1, .test_hi=1}, {.fmin=+0.6f*bw, .fmax=+0.5f, .pmin=0, .pmax=-_as+tol, .test_lo=0, .test_hi=1}, }; char filename[256]; sprintf(filename,"autotest/logs/rresamp_crcf_%s_P%u_Q%u.m", _method, _interp, _decim); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, liquid_autotest_verbose ? filename : NULL); // destroy objects rresamp_crcf_destroy(resamp); spgramcf_destroy(q); symstreamrcf_destroy(gen); } // baseline tests using create_kaiser() method void autotest_rresamp_crcf_baseline_P1_Q5() { test_rresamp_crcf("baseline", 1, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_baseline_P2_Q5() { test_rresamp_crcf("baseline", 2, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_baseline_P3_Q5() { test_rresamp_crcf("baseline", 3, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_baseline_P6_Q5() { test_rresamp_crcf("baseline", 6, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_baseline_P8_Q5() { test_rresamp_crcf("baseline", 8, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_baseline_P9_Q5() { test_rresamp_crcf("baseline", 9, 5, 15, -1, 60.0f); } // tests using create_default() method void autotest_rresamp_crcf_default_P1_Q5() { test_rresamp_crcf("default", 1, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_default_P2_Q5() { test_rresamp_crcf("default", 2, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_default_P3_Q5() { test_rresamp_crcf("default", 3, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_default_P6_Q5() { test_rresamp_crcf("default", 6, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_default_P8_Q5() { test_rresamp_crcf("default", 8, 5, 15, -1, 60.0f); } void autotest_rresamp_crcf_default_P9_Q5() { test_rresamp_crcf("default", 9, 5, 15, -1, 60.0f); } // tests using create_prototype() method void autotest_rresamp_crcf_arkaiser_P3_Q5() { test_rresamp_crcf("arkaiser", 3, 5, 40, 0.2, 50.0f); } void autotest_rresamp_crcf_arkaiser_P5_Q3() { test_rresamp_crcf("arkaiser", 5, 3, 40, 0.2, 50.0f); } void autotest_rresamp_crcf_rrcos_P3_Q5() { test_rresamp_crcf("rrcos", 3, 5, 40, 0.2, 50.0f); } void autotest_rresamp_crcf_rrcos_P5_Q3() { test_rresamp_crcf("rrcos", 5, 3, 40, 0.2, 50.0f); } // test copy method void autotest_rresamp_copy() { // create resampler with rate P/Q unsigned int i, P = 17, Q = 23, m = 12; rresamp_crcf q0 = rresamp_crcf_create_kaiser(P, Q, m, 0.4f, 60.0f); rresamp_crcf_set_scale(q0, 0.12345f); // create generator with default parameters symstreamrcf gen = symstreamrcf_create(); // generate samples and push through resampler float complex buf [Q]; // input buffer float complex buf_0[P]; // output buffer (orig) float complex buf_1[P]; // output buffer (copy) for (i=0; i<10; i++) { // generate block of samples symstreamrcf_write_samples(gen, buf, Q); // resample rresamp_crcf_execute(q0, buf, buf_0); } // copy object rresamp_crcf q1 = rresamp_crcf_copy(q0); // run samples through both resamplers in parallel for (i=0; i<60; i++) { // generate block of samples symstreamrcf_write_samples(gen, buf, Q); // resample rresamp_crcf_execute(q0, buf, buf_0); rresamp_crcf_execute(q1, buf, buf_1); // compare output CONTEND_SAME_DATA(buf_0, buf_1, P*sizeof(float complex)); } // destroy objects rresamp_crcf_destroy(q0); rresamp_crcf_destroy(q1); symstreamrcf_destroy(gen); } // test errors and invalid configuration void autotest_rresamp_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping rresamp config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // test copying/creating invalid objects CONTEND_ISNULL( rresamp_crcf_copy(NULL) ); CONTEND_ISNULL( rresamp_crcf_create(0, 5, 20, NULL) ); // interp is 0 CONTEND_ISNULL( rresamp_crcf_create(3, 0, 20, NULL) ); // decim is 0 CONTEND_ISNULL( rresamp_crcf_create(3, 5, 0, NULL) ); // filter length is 0 CONTEND_ISNULL( rresamp_crcf_create_kaiser(3,5,20,99.0f,60) ); // bandwidth > 0.5 // create valid object rresamp_crcf resamp = rresamp_crcf_create_kaiser(30, 50, 20, 0.3f, 60.0f); CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_print(resamp) ); CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_set_scale(resamp, 7.22f) ); float scale; CONTEND_EQUALITY( LIQUID_OK, rresamp_crcf_get_scale(resamp, &scale) ); CONTEND_EQUALITY( scale, 7.22f ); // get properties CONTEND_EQUALITY( 20, rresamp_crcf_get_delay (resamp) ); CONTEND_EQUALITY( 10, rresamp_crcf_get_block_len(resamp) ); CONTEND_EQUALITY( 0.6f, rresamp_crcf_get_rate (resamp) ); CONTEND_EQUALITY( 30, rresamp_crcf_get_P (resamp) ); CONTEND_EQUALITY( 3, rresamp_crcf_get_interp (resamp) ); CONTEND_EQUALITY( 50, rresamp_crcf_get_Q (resamp) ); CONTEND_EQUALITY( 5, rresamp_crcf_get_decim (resamp) ); rresamp_crcf_destroy(resamp); } liquid-dsp-1.7.0/src/filter/tests/rresamp_crcf_partition_autotest.c000066400000000000000000000074641474751757600257050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // AUTOTEST : test partitioning rational-rate resampler void test_harness_rresamp_crcf_part(unsigned int _P, // output size unsigned int _Q, // input size unsigned int _m, // filter semi-length unsigned int _n) // number of blocks { // semi-fixed options float tol = 1e-12f; // error tolerance (should be basically zero) float bw = 0.5f; // resampling filter bandwidth float As = 60.0f; // resampling filter stop-band attenuation [dB] // create two identical resampler objects rresamp_crcf q0 = rresamp_crcf_create_kaiser(_P,_Q,_m,bw,As); rresamp_crcf q1 = rresamp_crcf_create_kaiser(_P,_Q,_m,bw,As); // full input, output buffers float complex buf_in [2*_Q*_n]; // input buffer float complex buf_out_0[2*_P*_n]; // output, normal resampling operation float complex buf_out_1[2*_P*_n]; // output, partitioned into 2 blocks // generate input signal (pulse, but can really be anything) unsigned int i; for (i=0; i<2*_Q*_n; i++) buf_in[i] = liquid_hamming(i,2*_Q*_n) * cexpf(_Complex_I*2*M_PI*0.037f*i); // run resampler normally in one large block (2*_Q*n inputs, 2*_P*n outputs) rresamp_crcf_execute_block(q0, buf_in, 2*_n, buf_out_0); // reset and run with separate resamplers (e.g. in two threads) rresamp_crcf_reset(q0); // first block runs as normal rresamp_crcf_execute_block(q0, buf_in, _n, buf_out_1); // initialize second block with _Q*m samples to account for delay for (i=0; i<_m; i++) rresamp_crcf_write(q1, buf_in + _Q*_n - (_m-i)*_Q); // run remainder of second block as normal rresamp_crcf_execute_block(q1, buf_in + _Q*_n, _n, buf_out_1 + _P*_n); // clean up allocated objects rresamp_crcf_destroy(q0); rresamp_crcf_destroy(q1); // compare output buffers between normal and partitioned operation for (i=0; i<2*_P*_n; i++) { CONTEND_DELTA( crealf(buf_out_0[i]), crealf(buf_out_1[i]), tol ); CONTEND_DELTA( cimagf(buf_out_0[i]), cimagf(buf_out_1[i]), tol ); } } // actual tests void autotest_rresamp_crcf_part_P1_Q5() { test_harness_rresamp_crcf_part( 1, 5, 15, 20); } void autotest_rresamp_crcf_part_P2_Q5() { test_harness_rresamp_crcf_part( 2, 5, 15, 20); } void autotest_rresamp_crcf_part_P3_Q5() { test_harness_rresamp_crcf_part( 3, 5, 15, 20); } void autotest_rresamp_crcf_part_P6_Q5() { test_harness_rresamp_crcf_part( 6, 5, 15, 20); } void autotest_rresamp_crcf_part_P8_Q5() { test_harness_rresamp_crcf_part( 8, 5, 15, 20); } void autotest_rresamp_crcf_part_P9_Q5() { test_harness_rresamp_crcf_part( 9, 5, 15, 20); } liquid-dsp-1.7.0/src/filter/tests/symsync_copy_autotest.c000066400000000000000000000111441474751757600236730ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // test copying object void autotest_symsync_copy() { // create base object symsync_crcf q0 = symsync_crcf_create_rnyquist( LIQUID_FIRFILT_ARKAISER, 5, 7, 0.25, 64); symsync_crcf_set_lf_bw(q0,0.02f); // run samples through filter // NOTE: we don't care that the input is noise; just that both objects // produce the same output unsigned int i, nw_0, nw_1, buf_len = 640; float complex buf [buf_len]; float complex buf_0[buf_len]; float complex buf_1[buf_len]; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // void symsync_crcf_test(const char * _method, unsigned int _k, unsigned int _m, float _beta, float _tau, float _rate) { // options float tol = 0.2f; // error tolerance unsigned int k = _k; // samples/symbol (input) unsigned int m = _m; // filter delay (symbols) float beta = _beta; // filter excess bandwidth factor unsigned int num_filters= 32; // number of filters in the bank unsigned int num_symbols_init=200; // number of initial symbols unsigned int num_symbols_test=100; // number of testing symbols // transmit filter type liquid_firfilt_type ftype_tx = strcmp(_method,"rnyquist")==0 ? LIQUID_FIRFILT_ARKAISER : LIQUID_FIRFILT_KAISER; float bt = 0.02f; // loop filter bandwidth float tau = _tau; // fractional symbol offset float rate = _rate; // resampled rate // derived values unsigned int num_symbols = num_symbols_init + num_symbols_test; unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*rate*1.1f) + 4; // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset if (dt > 0.5f) { // force dt to be in [0.5,0.5] dt -= 1.0f; ds++; } unsigned int i; // allocate arrays float complex s[num_symbols]; // data symbols float complex x[num_samples]; // interpolated samples float complex y[num_samples_resamp];// resampled data (resamp_crcf) float complex z[num_symbols + 64]; // synchronized symbols // generate pseudo-random QPSK symbols // NOTE: by using an m-sequence generator this sequence will be identical // each time this test is run msequence ms = msequence_create_default(10); for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // void symsync_rrrf_test(const char * _method, unsigned int _k, unsigned int _m, float _beta, float _tau, float _rate) { // options float tol = 0.20f; // error tolerance unsigned int k = _k; // samples/symbol (input) unsigned int m = _m; // filter delay (symbols) float beta = _beta; // filter excess bandwidth factor unsigned int num_filters= 32; // number of filters in the bank unsigned int num_symbols_init=400; // number of initial symbols unsigned int num_symbols_test=100; // number of testing symbols // transmit filter type liquid_firfilt_type ftype_tx = strcmp(_method,"rnyquist")==0 ? LIQUID_FIRFILT_ARKAISER : LIQUID_FIRFILT_KAISER; float bt = 0.01f; // loop filter bandwidth float tau = _tau; // fractional symbol offset float rate = _rate; // resampled rate // derived values unsigned int num_symbols = num_symbols_init + num_symbols_test; unsigned int num_samples = k*num_symbols; unsigned int num_samples_resamp = (unsigned int) ceilf(num_samples*rate*1.1f) + 4; // compute delay while (tau < 0) tau += 1.0f; // ensure positive tau float g = k*tau; // number of samples offset int ds=floorf(g); // additional symbol delay float dt = (g - (float)ds); // fractional sample offset if (dt > 0.5f) { // force dt to be in [0.5,0.5] dt -= 1.0f; ds++; } unsigned int i; // allocate arrays float s[num_symbols]; // data symbols float x[num_samples]; // interpolated samples float y[num_samples_resamp]; // resampled data (resamp_rrrf) float z[num_symbols + 64]; // synchronized symbols // generate pseudo-random BPSK symbols // NOTE: by using an m-sequence generator this sequence will be identical // each time this test is run msequence ms = msequence_create_default(10); for (i=0; i #include #include #include #include "liquid.internal.h" // callback function static int bpacketsync_benchmark_callback(unsigned char * _payload, int _payload_valid, unsigned int _payload_len, framesyncstats_s _stats, void * _userdata) { if (!_payload_valid) return 0; // increment number of packets found and return unsigned int * num_packets_found = (unsigned int *) _userdata; *num_packets_found += 1; return 0; } void benchmark_bpacketsync(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // adjust number of iterations *_num_iterations *= 4; // options unsigned int dec_msg_len = 64; // original data message length crc_scheme check = LIQUID_CRC_NONE; // data integrity check fec_scheme fec0 = LIQUID_FEC_NONE; // inner code fec_scheme fec1 = LIQUID_FEC_NONE; // outer code // create packet generator bpacketgen pg = bpacketgen_create(0, dec_msg_len, check, fec0, fec1); // compute packet length unsigned int enc_msg_len = bpacketgen_get_packet_len(pg); // initialize arrays unsigned char msg_org[dec_msg_len]; // original message unsigned char msg_enc[enc_msg_len]; // encoded message unsigned int num_packets_found=0; // create packet synchronizer bpacketsync ps = bpacketsync_create(0, bpacketsync_benchmark_callback, (void*)&num_packets_found); unsigned long int i; // initialize original data message for (i=0; i #include #include #include #include "liquid.internal.h" // Helper function to keep code base small void bpresync_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n, unsigned int _m) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; *_num_iterations /= _m; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer bpresync_cccf q = bpresync_cccf_create(h, _n, 0.1f, _m); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } float complex rxy; float dphi_hat; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer bpresync_cccf_push(q, x[0]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[1]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[2]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[3]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[4]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[5]); bpresync_cccf_execute(q, &rxy, &dphi_hat); bpresync_cccf_push(q, x[6]); bpresync_cccf_execute(q, &rxy, &dphi_hat); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects bpresync_cccf_destroy(q); } #define BPRESYNC_CCCF_BENCHMARK_API(N,M) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { bpresync_cccf_bench(_start, _finish, _num_iterations, N, M); } void benchmark_bpresync_cccf_16 BPRESYNC_CCCF_BENCHMARK_API(16, 6); void benchmark_bpresync_cccf_32 BPRESYNC_CCCF_BENCHMARK_API(32, 6); void benchmark_bpresync_cccf_64 BPRESYNC_CCCF_BENCHMARK_API(64, 6); void benchmark_bpresync_cccf_128 BPRESYNC_CCCF_BENCHMARK_API(128, 6); void benchmark_bpresync_cccf_256 BPRESYNC_CCCF_BENCHMARK_API(256, 6); liquid-dsp-1.7.0/src/framing/bench/bsync_benchmark.c000066400000000000000000000062461474751757600224160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // Helper function to keep code base small void bsync_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer bsync_cccf q = bsync_cccf_create(_n,h); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } float complex rxy; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer bsync_cccf_correlate(q, x[0], &rxy); bsync_cccf_correlate(q, x[1], &rxy); bsync_cccf_correlate(q, x[2], &rxy); bsync_cccf_correlate(q, x[3], &rxy); bsync_cccf_correlate(q, x[4], &rxy); bsync_cccf_correlate(q, x[5], &rxy); bsync_cccf_correlate(q, x[6], &rxy); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects bsync_cccf_destroy(q); } #define BSYNC_CCCF_BENCHMARK_API(N) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { bsync_cccf_bench(_start, _finish, _num_iterations, N); } void benchmark_bsync_cccf_16 BSYNC_CCCF_BENCHMARK_API(16) void benchmark_bsync_cccf_32 BSYNC_CCCF_BENCHMARK_API(32) void benchmark_bsync_cccf_64 BSYNC_CCCF_BENCHMARK_API(64) void benchmark_bsync_cccf_128 BSYNC_CCCF_BENCHMARK_API(128) void benchmark_bsync_cccf_256 BSYNC_CCCF_BENCHMARK_API(256) liquid-dsp-1.7.0/src/framing/bench/detector_benchmark.c000066400000000000000000000073431474751757600231100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // Helper function to keep code base small void detector_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer float threshold = 0.5f; float dphi_max = 0.07f; detector_cccf q = detector_cccf_create(h, _n, threshold, dphi_max); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } float tau_hat; float dphi_hat; float gamma_hat; // start trials getrusage(RUSAGE_SELF, _start); int detected = 0; for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer detected ^= detector_cccf_correlate(q, x[0], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[1], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[2], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[3], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[4], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[5], &tau_hat, & dphi_hat, &gamma_hat); detected ^= detector_cccf_correlate(q, x[6], &tau_hat, & dphi_hat, &gamma_hat); // randomize input x[0] += detected > 2 ? -1e-3f : 1e-3f; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects detector_cccf_destroy(q); } #define DETECTOR_CCCF_BENCHMARK_API(N) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { detector_cccf_bench(_start, _finish, _num_iterations, N); } void benchmark_detector_cccf_16 DETECTOR_CCCF_BENCHMARK_API(16); void benchmark_detector_cccf_32 DETECTOR_CCCF_BENCHMARK_API(32); void benchmark_detector_cccf_64 DETECTOR_CCCF_BENCHMARK_API(64); void benchmark_detector_cccf_128 DETECTOR_CCCF_BENCHMARK_API(128); void benchmark_detector_cccf_256 DETECTOR_CCCF_BENCHMARK_API(256); liquid-dsp-1.7.0/src/framing/bench/flexframesync_benchmark.c000066400000000000000000000052051474751757600241400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.h" // Helper function to keep code base small void benchmark_flexframesync( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { *_num_iterations /= 128; unsigned long int i; // create flexframegen object flexframegenprops_s fgprops; flexframegenprops_init_default(&fgprops); fgprops.check = LIQUID_CRC_32; fgprops.fec0 = LIQUID_FEC_NONE; fgprops.fec1 = LIQUID_FEC_NONE; fgprops.mod_scheme = LIQUID_MODEM_QPSK; flexframegen fg = flexframegen_create(&fgprops); // generate the frame unsigned int payload_len = 8; unsigned char header[14]; unsigned char payload[payload_len]; flexframegen_assemble(fg, header, payload, payload_len); unsigned int frame_len = flexframegen_getframelen(fg); float complex frame[frame_len]; flexframegen_write_samples(fg, frame, frame_len); // add some noise for (i=0; i #include #include #include #include "liquid.h" typedef struct { unsigned int num_frames_tx; // number of transmitted frames unsigned int num_frames_detected; // number of received frames (detected) unsigned int num_frames_valid; // number of valid payloads } framedata; static int callback(unsigned char * _header, int _header_valid, unsigned char * _payload, unsigned int _payload_len, int _payload_valid, framesyncstats_s _stats, void * _userdata) { framedata * fd = (framedata*) _userdata; fd->num_frames_detected += 1; fd->num_frames_valid += _payload_valid ? 1 : 0; return 0; } // Helper function to keep code base small void benchmark_framesync64( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { *_num_iterations /= 128; unsigned long int i; framegen64 fg = framegen64_create(); // frame data unsigned char header[8] = {0, 1, 2, 3, 4, 5, 6, 7}; unsigned char payload[64]; // initialize payload for (i=0; i<64; i++) payload[i] = rand() & 0xff; framedata fd = {0, 0, 0}; // create framesync64 object framesync64 fs = framesync64_create(callback,(void*)&fd); // generate the frame //unsigned int frame_len = framegen64_getframelen(fg); unsigned int frame_len = LIQUID_FRAME64_LEN; float complex frame[frame_len]; framegen64_execute(fg, header, payload, frame); // add some noise for (i=0; i #include #include #include #include #include "liquid.h" // benchmark regular frame synchronizer with short frames; effectively // test acquisition complexity void benchmark_gmskframesync(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { *_num_iterations /= 128; unsigned long int i; // options unsigned int k = 2; // samples/symbol unsigned int m = 3; // filter delay (symbols) float BT = 0.5f; // filter bandwidth-time product unsigned int payload_len = 8; // length of payload (bytes) float SNRdB = 30.0f; // SNR // derived values float nstd = powf(10.0f, -SNRdB/20.0f); // create gmskframegen object and assemble the frame gmskframegen fg = gmskframegen_create_set(k, m, BT); gmskframegen_assemble(fg, NULL, NULL, payload_len, LIQUID_CRC_NONE, LIQUID_FEC_NONE, LIQUID_FEC_NONE); unsigned int frame_len = gmskframegen_getframelen(fg); float complex frame[frame_len]; gmskframegen_write(fg, frame, frame_len); // add some noise for (i=0; i #include #include #include #include "liquid.internal.h" // Helper function to keep code base small void presync_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n, unsigned int _m) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; *_num_iterations /= _m; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer presync_cccf q = presync_cccf_create(h, _n, 0.1f, _m); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } float complex rxy; float dphi_hat; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer presync_cccf_push(q, x[0]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[1]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[2]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[3]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[4]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[5]); presync_cccf_execute(q, &rxy, &dphi_hat); presync_cccf_push(q, x[6]); presync_cccf_execute(q, &rxy, &dphi_hat); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects presync_cccf_destroy(q); } #define PRESYNC_CCCF_BENCHMARK_API(N,M) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { presync_cccf_bench(_start, _finish, _num_iterations, N, M); } void benchmark_presync_cccf_16 PRESYNC_CCCF_BENCHMARK_API(16, 6); void benchmark_presync_cccf_32 PRESYNC_CCCF_BENCHMARK_API(32, 6); void benchmark_presync_cccf_64 PRESYNC_CCCF_BENCHMARK_API(64, 6); void benchmark_presync_cccf_128 PRESYNC_CCCF_BENCHMARK_API(128, 6); void benchmark_presync_cccf_256 PRESYNC_CCCF_BENCHMARK_API(256, 6); liquid-dsp-1.7.0/src/framing/bench/qdetector_benchmark.c000066400000000000000000000104301474751757600232600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // Helper function to keep code base small void qdetector_cccf_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // adjust number of iterations *_num_iterations *= 4; *_num_iterations /= _n; // generate sequence (random) float complex h[_n]; unsigned long int i; for (i=0; i<_n; i++) { h[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // generate synchronizer int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int k = 2; // samples/symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor float threshold = 0.5f; // threshold for detection float range = 0.05f; // carrier offset search range [radians/sample] qdetector_cccf q = qdetector_cccf_create_linear(h, _n, ftype, k, m, beta); qdetector_cccf_set_threshold(q,threshold); qdetector_cccf_set_range (q, range); // input sequence (random) float complex x[7]; for (i=0; i<7; i++) { x[i] = (rand() % 2 ? 1.0f : -1.0f) + (rand() % 2 ? 1.0f : -1.0f)*_Complex_I; } // start trials getrusage(RUSAGE_SELF, _start); int detected = 0; for (i=0; i<(*_num_iterations); i++) { // push input sequence through synchronizer detected ^= qdetector_cccf_execute(q, x[0]) != NULL; detected ^= qdetector_cccf_execute(q, x[1]) != NULL; detected ^= qdetector_cccf_execute(q, x[2]) != NULL; detected ^= qdetector_cccf_execute(q, x[3]) != NULL; detected ^= qdetector_cccf_execute(q, x[4]) != NULL; detected ^= qdetector_cccf_execute(q, x[5]) != NULL; detected ^= qdetector_cccf_execute(q, x[6]) != NULL; // randomize input x[0] += detected > 2 ? -1e-3f : 1e-3f; } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 7; // clean up allocated objects qdetector_cccf_destroy(q); } #define QDETECTOR_CCCF_BENCHMARK_API(N) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { qdetector_cccf_bench(_start, _finish, _num_iterations, N); } void benchmark_qdetector_cccf_16 QDETECTOR_CCCF_BENCHMARK_API(16); void benchmark_qdetector_cccf_32 QDETECTOR_CCCF_BENCHMARK_API(32); void benchmark_qdetector_cccf_64 QDETECTOR_CCCF_BENCHMARK_API(64); void benchmark_qdetector_cccf_128 QDETECTOR_CCCF_BENCHMARK_API(128); void benchmark_qdetector_cccf_256 QDETECTOR_CCCF_BENCHMARK_API(256); void benchmark_qdetector_cccf_512 QDETECTOR_CCCF_BENCHMARK_API(512); void benchmark_qdetector_cccf_1024 QDETECTOR_CCCF_BENCHMARK_API(1024); void benchmark_qdetector_cccf_2048 QDETECTOR_CCCF_BENCHMARK_API(2048); void benchmark_qdetector_cccf_4096 QDETECTOR_CCCF_BENCHMARK_API(4096); void benchmark_qdetector_cccf_8192 QDETECTOR_CCCF_BENCHMARK_API(8192); liquid-dsp-1.7.0/src/framing/src/000077500000000000000000000000001474751757600166225ustar00rootroot00000000000000liquid-dsp-1.7.0/src/framing/src/bpacketgen.c000066400000000000000000000225001474751757600210700ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // bpacketgen // // binary packet generator/encoder // #include #include #include #include #include "liquid.internal.h" // bpacketgen object structure struct bpacketgen_s { // options unsigned int g; // p/n sequence genpoly unsigned int pnsequence_len; // p/n sequence length (bytes) unsigned int dec_msg_len; // payload length crc_scheme crc; // payload check fec_scheme fec0; // payload fec (inner) fec_scheme fec1; // payload fec (outer) // derived values unsigned int enc_msg_len; // encoded message length unsigned int header_len; // header length (12 bytes encoded) unsigned int packet_len; // total packet length // arrays unsigned char * pnsequence; // p/n sequence // bpacket header // 0 : version number // 1 : crc // 2 : fec0 // 3 : fec1 // 4:5 : payload length unsigned char header_dec[6]; // uncoded bytes unsigned char header_enc[12]; // 12 = 6 + crc16 at hamming(12,8) // objects msequence ms; packetizer p_header; packetizer p_payload; }; // create bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_create(unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1) { // validate input // create bpacketgen object bpacketgen q = (bpacketgen) malloc(sizeof(struct bpacketgen_s)); q->dec_msg_len = _dec_msg_len; q->crc = _crc; q->fec0 = _fec0; q->fec1 = _fec1; // implied values q->g = 0; q->pnsequence_len = 8; // derived values q->enc_msg_len = packetizer_compute_enc_msg_len(q->dec_msg_len, q->crc, q->fec0, q->fec1); q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); bpacketgen_compute_packet_len(q); // arrays q->pnsequence = (unsigned char*) malloc((q->pnsequence_len)*sizeof(unsigned char)); // create m-sequence generator // TODO : configure sequence from generator polynomial q->ms = msequence_create_default(6); // create header packet encoder q->p_header = packetizer_create(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); assert(q->header_len == packetizer_get_enc_msg_len(q->p_header)); // create payload packet encoder q->p_payload = packetizer_create(q->dec_msg_len, q->crc, q->fec0, q->fec1); // assemble semi-static framing structures bpacketgen_assemble_header(q); bpacketgen_assemble_pnsequence(q); return q; } // re-create bpacketgen object from old object // _q : old bpacketgen object // _m : p/n sequence length (ignored) // _dec_msg_len : decoded message length (original uncoded data) // _crc : data validity check (e.g. cyclic redundancy check) // _fec0 : inner forward error-correction code scheme // _fec1 : outer forward error-correction code scheme bpacketgen bpacketgen_recreate(bpacketgen _q, unsigned int _m, unsigned int _dec_msg_len, int _crc, int _fec0, int _fec1) { // validate input // re-create internal packetizer object _q->dec_msg_len = _dec_msg_len; _q->crc = _crc; _q->fec0 = _fec0; _q->fec1 = _fec1; // derived values _q->enc_msg_len = packetizer_compute_enc_msg_len(_q->dec_msg_len, _q->crc, _q->fec0, _q->fec1); _q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); bpacketgen_compute_packet_len(_q); // arrays _q->g = 0; _q->pnsequence_len = 8; _q->pnsequence = (unsigned char*) realloc(_q->pnsequence, (_q->pnsequence_len)*sizeof(unsigned char)); // re-create m-sequence generator // TODO : configure sequence from generator polynomial msequence_destroy(_q->ms); _q->ms = msequence_create_default(6); // re-create payload packet encoder _q->p_payload = packetizer_recreate(_q->p_payload, _q->dec_msg_len, _q->crc, _q->fec0, _q->fec1); // assemble semi-static framing structures bpacketgen_assemble_header(_q); bpacketgen_assemble_pnsequence(_q); return _q; } // destroy bpacketgen object, freeing all internally-allocated memory void bpacketgen_destroy(bpacketgen _q) { // free arrays free(_q->pnsequence); // destroy internal objects msequence_destroy(_q->ms); packetizer_destroy(_q->p_header); packetizer_destroy(_q->p_payload); // free main object memory free(_q); } // print bpacketgen internals void bpacketgen_print(bpacketgen _q) { printf("g); printf(", pn_len%u", _q->pnsequence_len); printf(", header=%u", _q->header_len); printf(", payload=%u", _q->dec_msg_len); printf(", crc=\"%s\"", crc_scheme_str[_q->crc][0]); printf(", fec_0=\"%s\"", fec_scheme_str[_q->fec0][0]); printf(", fec_1=\"%s\"", fec_scheme_str[_q->fec1][0]); printf(", packet=%u", _q->packet_len); printf(", efficiency=%g", (float)_q->dec_msg_len/(float)_q->packet_len); printf(">\n"); } // return length of full packet unsigned int bpacketgen_get_packet_len(bpacketgen _q) { return _q->packet_len; } // encode packet void bpacketgen_encode(bpacketgen _q, unsigned char * _msg_dec, unsigned char * _packet) { // output byte index counter unsigned int n=0; // copy p/n sequence memmove(&_packet[n], _q->pnsequence, _q->pnsequence_len*sizeof(unsigned char)); n += _q->pnsequence_len; // copy header memmove(&_packet[n], _q->header_enc, _q->header_len*sizeof(unsigned char)); n += _q->header_len; // encode payload packetizer_encode(_q->p_payload, _msg_dec, &_packet[n]); n += _q->enc_msg_len; // verify length is correct assert(n == _q->packet_len); } // // internal methods // // compute packet length void bpacketgen_compute_packet_len(bpacketgen _q) { _q->packet_len = _q->pnsequence_len + _q->header_len + _q->enc_msg_len; } // generate p/n sequence void bpacketgen_assemble_pnsequence(bpacketgen _q) { // reset m-sequence generator msequence_reset(_q->ms); unsigned int i; unsigned int j; for (i=0; i<_q->pnsequence_len; i++) { unsigned char byte = 0; for (j=0; j<8; j++) { byte <<= 1; byte |= msequence_advance(_q->ms); } _q->pnsequence[i] = byte; } } // assemble packet header void bpacketgen_assemble_header(bpacketgen _q) { _q->header_dec[0] = BPACKET_VERSION; _q->header_dec[1] = (unsigned char) _q->crc; _q->header_dec[2] = (unsigned char) _q->fec0; _q->header_dec[3] = (unsigned char) _q->fec1; _q->header_dec[4] = (unsigned char) (_q->dec_msg_len >> 8) & 0xff; _q->header_dec[5] = (unsigned char) (_q->dec_msg_len ) & 0xff; // encode header packetizer_encode(_q->p_header, _q->header_dec, _q->header_enc); } liquid-dsp-1.7.0/src/framing/src/bpacketsync.c000066400000000000000000000357641474751757600213130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // binary packet synchronizer/decoder #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_BPACKETSYNC 0 // bpacketsync object structure struct bpacketsync_s { // options unsigned int g; // p/n sequence genpoly unsigned int pnsequence_len; // p/n sequence length (bytes) unsigned int dec_msg_len; // payload length crc_scheme crc; // payload check fec_scheme fec0; // payload fec (inner) fec_scheme fec1; // payload fec (outer) // derived values unsigned int enc_msg_len; // encoded message length unsigned int header_len; // header length (12 bytes encoded) unsigned int packet_len; // total packet length // arrays unsigned char * pnsequence; // p/n sequence unsigned char * payload_enc; // payload (encoded) unsigned char * payload_dec; // payload (decoded) // bpacket header // 0 : version number // 1 : crc // 2 : fec0 // 3 : fec1 // 4:5 : payload length unsigned char header_dec[6]; // uncoded bytes unsigned char header_enc[12]; // 12 = 6 + crc16 at hamming(12,8) // objects msequence ms; packetizer p_header; packetizer p_payload; bsequence bpn; // binary p/n sequence bsequence brx; // binary received sequence // status variables enum { BPACKETSYNC_STATE_SEEKPN=0, // seek p/n sequence BPACKETSYNC_STATE_RXHEADER, // receive header data BPACKETSYNC_STATE_RXPAYLOAD // receive payload data } state; // counters unsigned int num_bytes_received; unsigned int num_bits_received; unsigned char byte_rx; unsigned char byte_mask; // flags int header_valid; int payload_valid; // user-defined parameters bpacketsync_callback callback; void * userdata; framesyncstats_s framestats; }; // internal methods int bpacketsync_assemble_pnsequence(bpacketsync _q); int bpacketsync_execute_seekpn (bpacketsync _q, unsigned char _bit); int bpacketsync_execute_rxheader (bpacketsync _q, unsigned char _bit); int bpacketsync_execute_rxpayload (bpacketsync _q, unsigned char _bit); int bpacketsync_decode_header (bpacketsync _q); int bpacketsync_decode_payload (bpacketsync _q); int bpacketsync_reconfig (bpacketsync _q); bpacketsync bpacketsync_create(unsigned int _m, bpacketsync_callback _callback, void * _userdata) { // create bpacketsync object bpacketsync q = (bpacketsync) malloc(sizeof(struct bpacketsync_s)); q->callback = _callback; q->userdata = _userdata; // default values q->dec_msg_len = 1; q->crc = LIQUID_CRC_NONE; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; // implied values q->g = 0; q->pnsequence_len = 8; // derived values q->enc_msg_len = packetizer_compute_enc_msg_len(q->dec_msg_len, q->crc, q->fec0, q->fec1); q->header_len = packetizer_compute_enc_msg_len(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); // arrays q->pnsequence = (unsigned char*) malloc((q->pnsequence_len)*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc((q->enc_msg_len)*sizeof(unsigned char)); q->payload_dec = (unsigned char*) malloc((q->dec_msg_len)*sizeof(unsigned char)); // create m-sequence generator // TODO : configure sequence from generator polynomial q->ms = msequence_create_default(6); // create header packet encoder q->p_header = packetizer_create(6, LIQUID_CRC_16, LIQUID_FEC_NONE, LIQUID_FEC_HAMMING128); assert(q->header_len == packetizer_get_enc_msg_len(q->p_header)); // create payload packet encoder q->p_payload = packetizer_create(q->dec_msg_len, q->crc, q->fec0, q->fec1); // create binary sequence objects q->bpn = bsequence_create(q->pnsequence_len*8); q->brx = bsequence_create(q->pnsequence_len*8); // assemble semi-static framing structures bpacketsync_assemble_pnsequence(q); // reset synchronizer bpacketsync_reset(q); return q; } int bpacketsync_destroy(bpacketsync _q) { // free arrays free(_q->pnsequence); free(_q->payload_enc); free(_q->payload_dec); // destroy internal objects msequence_destroy(_q->ms); packetizer_destroy(_q->p_header); packetizer_destroy(_q->p_payload); bsequence_destroy(_q->bpn); bsequence_destroy(_q->brx); // free main object memory free(_q); return LIQUID_OK; } int bpacketsync_print(bpacketsync _q) { printf("g); printf(", pn_len%u", _q->pnsequence_len); printf(", header=%u", _q->header_len); printf(", payload=%u", _q->dec_msg_len); printf(", crc=\"%s\"", crc_scheme_str[_q->crc][0]); printf(", fec_0=\"%s\"", fec_scheme_str[_q->fec0][0]); printf(", fec_1=\"%s\"", fec_scheme_str[_q->fec1][0]); printf(", packet=%u", _q->packet_len); printf(", efficiency=%g", (float)_q->dec_msg_len/(float)_q->packet_len); printf(">\n"); return LIQUID_OK; } int bpacketsync_reset(bpacketsync _q) { // clear received sequence buffer bsequence_reset(_q->brx); // reset counters _q->num_bytes_received = 0; _q->num_bits_received = 0; _q->byte_rx = 0; _q->byte_mask = 0x00; // reset state _q->state = BPACKETSYNC_STATE_SEEKPN; return LIQUID_OK; } // run synchronizer on array of input bytes // _q : bpacketsync object // _bytes : input data array [size: _n x 1] // _n : input array size int bpacketsync_execute(bpacketsync _q, unsigned char * _bytes, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) bpacketsync_execute_byte(_q, _bytes[i]); return LIQUID_OK; } // run synchronizer on input byte // _q : bpacketsync object // _byte : input byte int bpacketsync_execute_byte(bpacketsync _q, unsigned char _byte) { unsigned int j; for (j=0; j<8; j++) { // strip bit from byte unsigned char bit = (_byte >> (8-j-1)) & 1; // run synchronizer on bit bpacketsync_execute_bit(_q, bit); } return LIQUID_OK; } // run synchronizer on input symbol // _q : bpacketsync object // _sym : input symbol with _bps significant bits // _bps : number of bits in input symbol int bpacketsync_execute_sym(bpacketsync _q, unsigned char _sym, unsigned int _bps) { // validate input if (_bps > 8) return liquid_error(LIQUID_EICONFIG,"bpacketsync_execute_sym(), bits per symbol must be in [0,8]"); unsigned int j; for (j=0; j<_bps; j++) { // strip bit from byte unsigned char bit = (_sym >> (_bps-j-1)) & 1; // run synchronizer on bit bpacketsync_execute_bit(_q, bit); } return LIQUID_OK; } // execute one bit at a time int bpacketsync_execute_bit(bpacketsync _q, unsigned char _bit) { // mask input to ensure one bit of resolution _bit = _bit & 0x01; // execute state-specific methods switch (_q->state) { case BPACKETSYNC_STATE_SEEKPN: bpacketsync_execute_seekpn(_q, _bit); break; case BPACKETSYNC_STATE_RXHEADER: bpacketsync_execute_rxheader(_q, _bit); break; case BPACKETSYNC_STATE_RXPAYLOAD: bpacketsync_execute_rxpayload(_q, _bit); break; default: return liquid_error(LIQUID_EICONFIG,"bpacketsync_execute(), invalid state"); } return LIQUID_OK; } // // internal methods // int bpacketsync_assemble_pnsequence(bpacketsync _q) { // reset m-sequence generator msequence_reset(_q->ms); unsigned int i; for (i=0; i<8*_q->pnsequence_len; i++) bsequence_push(_q->bpn, msequence_advance(_q->ms)); return LIQUID_OK; } int bpacketsync_execute_seekpn(bpacketsync _q, unsigned char _bit) { // push bit into correlator bsequence_push(_q->brx, _bit); // compute p/n sequence correlation int rxy = bsequence_correlate(_q->bpn, _q->brx); float r = 2.0f*(float)rxy / (float)(_q->pnsequence_len*8) - 1.0f; // check threshold if ( fabsf(r) > 0.8f ) { #if DEBUG_BPACKETSYNC printf("p/n sequence found!, rxy = %8.4f\n", r); #endif // flip polarity of bits if correlation is negative _q->byte_mask = r > 0 ? 0x00 : 0xff; // switch operational mode _q->state = BPACKETSYNC_STATE_RXHEADER; } return LIQUID_OK; } int bpacketsync_execute_rxheader(bpacketsync _q, unsigned char _bit) { // push bit into accumulated byte _q->byte_rx <<= 1; _q->byte_rx |= (_bit & 1); _q->num_bits_received++; if (_q->num_bits_received == 8) { // append byte to encoded header array _q->header_enc[_q->num_bytes_received] = _q->byte_rx ^ _q->byte_mask; _q->num_bits_received=0; _q->num_bytes_received++; if (_q->num_bytes_received == _q->header_len) { _q->num_bits_received = 0; _q->num_bytes_received = 0; // decode header bpacketsync_decode_header(_q); // TODO : invoke header callback now if (_q->header_valid) { // re-allocate memory for arrays bpacketsync_reconfig(_q); // switch operational mode _q->state = BPACKETSYNC_STATE_RXPAYLOAD; } else { // reset synchronizer bpacketsync_reset(_q); } } } return LIQUID_OK; } int bpacketsync_execute_rxpayload(bpacketsync _q, unsigned char _bit) { // push bit into accumulated byte _q->byte_rx <<= 1; _q->byte_rx |= (_bit & 1); _q->num_bits_received++; if (_q->num_bits_received == 8) { // append byte to encoded payload array _q->payload_enc[_q->num_bytes_received] = _q->byte_rx ^ _q->byte_mask; _q->num_bits_received=0; _q->num_bytes_received++; if (_q->num_bytes_received == _q->enc_msg_len) { _q->num_bits_received = 0; _q->num_bytes_received = 0; // decode payload data bpacketsync_decode_payload(_q); // invoke callback if (_q->callback != NULL) { // set frame stats framesyncstats_init_default(&_q->framestats); _q->framestats.check = _q->crc; _q->framestats.fec0 = _q->fec0; _q->framestats.fec1 = _q->fec1; _q->callback(_q->payload_dec, _q->payload_valid, _q->dec_msg_len, _q->framestats, _q->userdata); } // reset synchronizer bpacketsync_reset(_q); } } return LIQUID_OK; } int bpacketsync_decode_header(bpacketsync _q) { // decode header array _q->header_valid = packetizer_decode(_q->p_header, _q->header_enc, _q->header_dec); // return unconditionally if header failed if (!_q->header_valid) return LIQUID_OK; // strip header info int version = _q->header_dec[0]; _q->crc = (crc_scheme) _q->header_dec[1]; _q->fec0 = (fec_scheme) _q->header_dec[2]; _q->fec1 = (fec_scheme) _q->header_dec[3]; _q->dec_msg_len = (_q->header_dec[4] << 8) | (_q->header_dec[5] ); // check version number if (version != BPACKET_VERSION) return liquid_error(LIQUID_EICONFIG,"bpacketsync, version mismatch (received %d, expected %d)",version, BPACKET_VERSION); if (_q->crc == LIQUID_CRC_UNKNOWN || _q->crc >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported crc: %u", _q->crc); if (_q->fec0 == LIQUID_FEC_UNKNOWN || _q->fec0 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported fec (inner): %u", _q->fec0); if (_q->fec1 == LIQUID_FEC_UNKNOWN || _q->fec1 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"bpacketsync, invalid/unsupported fec (outer): %u", _q->fec1); return LIQUID_OK; } int bpacketsync_decode_payload(bpacketsync _q) { // decode payload _q->payload_valid = packetizer_decode(_q->p_payload, _q->payload_enc, _q->payload_dec); return LIQUID_OK; } int bpacketsync_reconfig(bpacketsync _q) { // reconfigure packetizer _q->p_payload = packetizer_recreate(_q->p_payload, _q->dec_msg_len, _q->crc, _q->fec0, _q->fec1); // re-compute encoded message (packet) length _q->enc_msg_len = packetizer_get_enc_msg_len(_q->p_payload); // re-allocate memory for encoded packet _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->enc_msg_len*sizeof(unsigned char)); // re-allocate memory for decoded packet _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, _q->dec_msg_len*sizeof(unsigned char)); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/bpresync.proto.c000066400000000000000000000175461474751757600217720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Binary pre-demod synchronizer // #include #include #include #include #include "liquid.internal.h" struct BPRESYNC(_s) { unsigned int n; // sequence length unsigned int m; // number of binary synchronizers bsequence rx_i; // received pattern (in-phase) bsequence rx_q; // received pattern (quadrature) float * dphi; // array of frequency offsets [size: m x 1] bsequence * sync_i; // synchronization pattern (in-phase) bsequence * sync_q; // synchronization pattern (quadrature) float * rxy; // output correlation [size: m x 1] float n_inv; // 1/n (pre-computed for speed) }; // correlate input sequence with particular sequence index // _q : pre-demod synchronizer object // _id : sequence index // _rxy0 : positive frequency correlation output (non-conjugated) // _rxy1 : negative frequency correlation output (conjugated) int BPRESYNC(_correlatex)(BPRESYNC() _q, unsigned int _id, float complex * _rxy0, float complex * _rxy1); // create binary pre-demod synchronizer // _v : baseband sequence // _n : baseband sequence length // _dphi_max : maximum absolute frequency deviation // _m : number of correlators BPRESYNC() BPRESYNC(_create)(TC * _v, unsigned int _n, float _dphi_max, unsigned int _m) { // validate input if (_n < 1) return liquid_error_config("bpresync_%s_create(), invalid input length", EXTENSION_FULL); if (_m == 0) return liquid_error_config("bpresync_%s_create(), number of correlators must be at least 1", EXTENSION_FULL); // allocate main object memory and initialize BPRESYNC() _q = (BPRESYNC()) malloc(sizeof(struct BPRESYNC(_s))); _q->n = _n; _q->m = _m; _q->n_inv = 1.0f / (float)(_q->n); unsigned int i; // create internal receive buffers _q->rx_i = bsequence_create(_q->n); _q->rx_q = bsequence_create(_q->n); // create internal array of frequency offsets _q->dphi = (float*) malloc( _q->m*sizeof(float) ); // create internal synchronizers _q->sync_i = (bsequence*) malloc( _q->m*sizeof(bsequence) ); _q->sync_q = (bsequence*) malloc( _q->m*sizeof(bsequence) ); for (i=0; i<_q->m; i++) { _q->sync_i[i] = bsequence_create(_q->n); _q->sync_q[i] = bsequence_create(_q->n); // generate signal with frequency offset _q->dphi[i] = (float)i / (float)(_q->m-1)*_dphi_max; unsigned int k; for (k=0; k<_q->n; k++) { TC v_prime = _v[k] * cexpf(-_Complex_I*k*_q->dphi[i]); bsequence_push(_q->sync_i[i], crealf(v_prime)>0); bsequence_push(_q->sync_q[i], cimagf(v_prime)>0); } } // allocate memory for cross-correlation _q->rxy = (float*) malloc( _q->m*sizeof(float) ); // reset object BPRESYNC(_reset)(_q); return _q; } int BPRESYNC(_destroy)(BPRESYNC() _q) { unsigned int i; // free received symbol buffers bsequence_destroy(_q->rx_i); bsequence_destroy(_q->rx_q); // free internal syncrhonizer objects for (i=0; i<_q->m; i++) { bsequence_destroy(_q->sync_i[i]); bsequence_destroy(_q->sync_q[i]); } free(_q->sync_i); free(_q->sync_q); // free internal frequency offset array free(_q->dphi); // free internal cross-correlation array free(_q->rxy); // free main object memory free(_q); return LIQUID_OK; } int BPRESYNC(_print)(BPRESYNC() _q) { printf("\n", EXTENSION_FULL, _q->n); return LIQUID_OK; } int BPRESYNC(_reset)(BPRESYNC() _q) { unsigned int i; for (i=0; i<_q->n; i++) { bsequence_push(_q->rx_i, (i+0) % 2); bsequence_push(_q->rx_q, (i+1) % 2); } return LIQUID_OK; } /* push input sample into pre-demod synchronizer */ /* _q : pre-demod synchronizer object */ /* _x : input sample */ int BPRESYNC(_push)(BPRESYNC() _q, TI _x) { // push symbol into buffers bsequence_push(_q->rx_i, REAL(_x)>0); bsequence_push(_q->rx_q, IMAG(_x)>0); return LIQUID_OK; } /* correlate input sequence */ /* _q : pre-demod synchronizer object */ /* _rxy : output cross correlation */ /* _dphi_hat : output frequency offset estimate */ int BPRESYNC(_execute)(BPRESYNC() _q, TO * _rxy, float * _dphi_hat) { unsigned int i; float complex rxy_max = 0; // maximum cross-correlation float abs_rxy_max = 0; // absolute value of rxy_max float complex rxy0; float complex rxy1; float dphi_hat = 0.0f; for (i=0; i<_q->m; i++) { BPRESYNC(_correlatex)(_q, i, &rxy0, &rxy1); // check non-conjugated value if ( ABS(rxy0) > abs_rxy_max ) { rxy_max = rxy0; abs_rxy_max = ABS(rxy0); dphi_hat = _q->dphi[i]; } // check conjugated value if ( ABS(rxy1) > abs_rxy_max ) { rxy_max = rxy1; abs_rxy_max = ABS(rxy1); dphi_hat = -_q->dphi[i]; } } *_rxy = rxy_max; *_dphi_hat = dphi_hat; return LIQUID_OK; } // // internal methods // // correlate input sequence with particular sequence index // _q : pre-demod synchronizer object // _id : sequence index // _rxy0 : positive frequency correlation output (non-conjugated) // _rxy1 : negative frequency correlation output (conjugated) int BPRESYNC(_correlatex)(BPRESYNC() _q, unsigned int _id, float complex * _rxy0, float complex * _rxy1) { // validate input... if (_id >= _q->m) return liquid_error(LIQUID_EICONFIG,"bpresync_%s_correlatex(), invalid id", EXTENSION_FULL); // compute correlations int rxy_ii = 2*bsequence_correlate(_q->sync_i[_id], _q->rx_i) - (int)(_q->n); int rxy_qq = 2*bsequence_correlate(_q->sync_q[_id], _q->rx_q) - (int)(_q->n); int rxy_iq = 2*bsequence_correlate(_q->sync_i[_id], _q->rx_q) - (int)(_q->n); int rxy_qi = 2*bsequence_correlate(_q->sync_q[_id], _q->rx_i) - (int)(_q->n); // non-conjugated int rxy_i0 = rxy_ii - rxy_qq; int rxy_q0 = rxy_iq + rxy_qi; *_rxy0 = (rxy_i0 + rxy_q0 * _Complex_I) * _q->n_inv; // conjugated int rxy_i1 = rxy_ii + rxy_qq; int rxy_q1 = rxy_iq - rxy_qi; *_rxy1 = (rxy_i1 + rxy_q1 * _Complex_I) * _q->n_inv; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/bsync.proto.c000066400000000000000000000116741474751757600212570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // P/N synchronizer // #include #include #include #include #include "liquid.internal.h" struct BSYNC(_s) { unsigned int n; // sequence length bsequence sync_i; // synchronization pattern (in-phase) bsequence sym_i; // received symbols (in-phase) //#if TC_COMPLEX==1 bsequence sync_q; // synchronization pattern (quadrature) //#endif //#if TI_COMPLEX==1 bsequence sym_q; // received symbols (quadrature) //#endif TO rxy; // cross correlation }; BSYNC() BSYNC(_create)(unsigned int _n, TC * _v) { BSYNC() fs = (BSYNC()) malloc(sizeof(struct BSYNC(_s))); fs->n = _n; fs->sync_i = bsequence_create(fs->n); #if TC_COMPLEX==1 fs->sync_q = bsequence_create(fs->n); #endif fs->sym_i = bsequence_create(fs->n); #if TI_COMPLEX==1 fs->sym_q = bsequence_create(fs->n); #endif unsigned int i; for (i=0; in; i++) { bsequence_push(fs->sync_i, crealf(_v[i])>0); #if TC_COMPLEX==1 bsequence_push(fs->sync_q, cimagf(_v[i])>0); #endif } return fs; } // TODO : test this method BSYNC() BSYNC(_create_msequence)(unsigned int _g, unsigned int _k) { // validate input if (_k == 0) return liquid_error_config("bsync_xxxt_create_msequence(), samples/symbol must be greater than zero"); unsigned int m = liquid_msb_index(_g) - 1; // create/initialize msequence msequence ms = msequence_create(m, _g, 1); BSYNC() fs = (BSYNC()) malloc(sizeof(struct BSYNC(_s))); unsigned int n = msequence_get_length(ms); fs->sync_i = bsequence_create(n * _k); #if TC_COMPLEX==1 fs->sync_q = bsequence_create(n * _k); #endif fs->sym_i = bsequence_create(n * _k); #if TI_COMPLEX==1 fs->sym_q = bsequence_create(n * _k); #endif msequence_reset(ms); #if 0 bsequence_init_msequence(fs->sync_i,ms); #if TC_COMPLEX==1 msequence_reset(ms); bsequence_init_msequence(fs->sync_q,ms); #endif #else unsigned int i; unsigned int j; for (i=0; isync_i, bit); #if TC_COMPLEX==1 bsequence_push(fs->sync_q, bit); #endif } } #endif msequence_destroy(ms); fs->n = _k*n; return fs; } int BSYNC(_destroy)(BSYNC() _fs) { bsequence_destroy(_fs->sync_i); #if TC_COMPLEX==1 bsequence_destroy(_fs->sync_q); #endif bsequence_destroy(_fs->sym_i); #if TI_COMPLEX==1 bsequence_destroy(_fs->sym_q); #endif free(_fs); return LIQUID_OK; } int BSYNC(_print)(BSYNC() _fs) { printf("\n", EXTENSION_FULL, _fs->n); return LIQUID_OK; } int BSYNC(_correlate)(BSYNC() _fs, TI _sym, TO *_y) { // push symbol into buffers bsequence_push(_fs->sym_i, crealf(_sym)>0.0 ? 1 : 0); #if TI_COMPLEX==1 bsequence_push(_fs->sym_q, cimagf(_sym)>0.0 ? 1 : 0); #endif // compute dotprod #if TC_COMPLEX==1 && TI_COMPLEX==1 // cccx TO rxy_ii = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_i) - (float)(_fs->n); TO rxy_qq = 2.*bsequence_correlate(_fs->sync_q, _fs->sym_q) - (float)(_fs->n); TO rxy_iq = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_q) - (float)(_fs->n); TO rxy_qi = 2.*bsequence_correlate(_fs->sync_q, _fs->sym_i) - (float)(_fs->n); _fs->rxy = (rxy_ii - rxy_qq) + _Complex_I*(rxy_iq + rxy_qi); #elif TI_COMPLEX==1 // crcx float rxy_ii = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_i) - (float)(_fs->n); float rxy_iq = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_q) - (float)(_fs->n); _fs->rxy = rxy_ii + _Complex_I * rxy_iq; #else // rrrx _fs->rxy = 2.*bsequence_correlate(_fs->sync_i, _fs->sym_i) - (float)(_fs->n); #endif // divide by sequence length *_y = _fs->rxy / (float)(_fs->n); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/detector_cccf.c000066400000000000000000000413351474751757600215630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // detector_cccf.c // // Pre-demodulation detector // #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_DETECTOR 0 #define DEBUG_DETECTOR_PRINT 0 #define DEBUG_DETECTOR_BUFFER_LEN (1600) #define DEBUG_DETECTOR_FILENAME "detector_cccf_debug.m" // // internal method declarations // // update sum{ |x|^2 } void detector_cccf_update_sumsq(detector_cccf _q, float complex _x); // compute all dot product outputs void detector_cccf_compute_dotprods(detector_cccf _q); // estimate carrier and timing offsets void detector_cccf_estimate_offsets(detector_cccf _q, float * _tau_hat, float * _dphi_hat); // print debugging information int detector_cccf_debug_print(detector_cccf _q, const char * _filename); struct detector_cccf_s { float complex * s; // sequence unsigned int n; // sequence length float threshold; // detection threshold // derived values float n_inv; // 1/n (pre-computed for speed) windowcf buffer; // input buffer // internal correlators dotprod_cccf * dp; // vector dot products (pre-spun) unsigned int m; // number of correlators float dphi_step; // step size for each correlator float dphi_max; // maximum carrier offset float * dphi; // correlator frequencies [size: m x 1] float * rxy; // correlator outputs [size: m x 1] float * rxy0; // buffered correlator outputs [size: m x 1] float * rxy1; // buffered correlator outputs [size: m x 1] unsigned int imax; // index of maximum unsigned int idetect; // index of detection // estimation of E{|x|^2} wdelayf x2; // buffer of |x|^2 values float x2_sum; // sum{ |x|^2 } float x2_hat; // estimate of E{|x|^2} // counters/states enum { DETECTOR_STATE_SEEK=0, // seek sequence DETECTOR_STATE_FINDMAX, // find maximum } state; unsigned int timer; // sample timer #if DEBUG_DETECTOR windowcf debug_x; windowf debug_x2; windowf debug_rxy; #endif }; // create detector_cccf object // _s : sequence // _n : sequence length // _threshold : detection threshold (default: 0.7) // _dphi_max : maximum carrier offset detector_cccf detector_cccf_create(float complex * _s, unsigned int _n, float _threshold, float _dphi_max) { // validate input if (_n == 0) return liquid_error_config("detector_cccf_create(), sequence length cannot be zero"); if (_threshold <= 0.0f) return liquid_error_config("detector_cccf_create(), threshold must be greater than zero (0.6 recommended)"); // allocate memory for main object detector_cccf q = (detector_cccf) malloc(sizeof(struct detector_cccf_s)); unsigned int i; // set internal properties q->n = _n; q->threshold = _threshold; q->dphi_max = _dphi_max; // derived values q->n_inv = 1.0f / (float)(q->n); // 1/n for faster processing q->dphi_step = 0.8f * M_PI / (float)(q->n); // compute number of correlators q->m = (int) ceilf( fabsf(_dphi_max / q->dphi_step) ); // ensure at least two correlators if (q->m < 2) q->m = 2; // re-compute maximum carrier offset q->dphi_max = q->m * q->dphi_step; // allocate memory for sequence and copy q->s = (float complex*) malloc((q->n)*sizeof(float complex)); memmove(q->s, _s, q->n*sizeof(float complex)); // create internal buffer q->buffer = windowcf_create(q->n); q->x2 = wdelayf_create(q->n); // create internal correlators (dot products) q->dp = (dotprod_cccf*) malloc((q->m)*sizeof(dotprod_cccf)); q->dphi = (float*) malloc((q->m)*sizeof(float)); q->rxy0 = (float*) malloc((q->m)*sizeof(float)); q->rxy1 = (float*) malloc((q->m)*sizeof(float)); q->rxy = (float*) malloc((q->m)*sizeof(float)); unsigned int k; float complex sconj[q->n]; for (k=0; km; k++) { // pre-spin sequence (slightly over-sampled in frequency) q->dphi[k] = ((float)k - (float)(q->m-1)/2) * q->dphi_step; for (i=0; in; i++) sconj[i] = conjf(q->s[i]) * cexpf(-_Complex_I*q->dphi[k]*i); q->dp[k] = dotprod_cccf_create(sconj, q->n); } // reset state detector_cccf_reset(q); #if DEBUG_DETECTOR q->debug_x = windowcf_create(DEBUG_DETECTOR_BUFFER_LEN); q->debug_x2 = windowf_create(DEBUG_DETECTOR_BUFFER_LEN); q->debug_rxy = windowf_create(DEBUG_DETECTOR_BUFFER_LEN); #endif // return object return q; } void detector_cccf_destroy(detector_cccf _q) { #if DEBUG_DETECTOR detector_cccf_debug_print(_q, DEBUG_DETECTOR_FILENAME); windowcf_destroy(_q->debug_x); windowf_destroy(_q->debug_x2); windowf_destroy(_q->debug_rxy); #endif // destroy input buffer windowcf_destroy(_q->buffer); // destroy internal correlators (dot products) unsigned int k; for (k=0; k<_q->m; k++) dotprod_cccf_destroy(_q->dp[k]); free(_q->dp); free(_q->dphi); free(_q->rxy); free(_q->rxy0); free(_q->rxy1); // destroy |x|^2 buffer wdelayf_destroy(_q->x2); // free internal buffers/arrays free(_q->s); // free main object memory free(_q); } void detector_cccf_print(detector_cccf _q) { printf("n); printf(", thresh=%g", _q->threshold); printf(", dphi_max=%8.4f", _q->dphi_max); printf(", ncorrs=%u", _q->m); printf(">\n"); } void detector_cccf_reset(detector_cccf _q) { // reset internal state windowcf_reset(_q->buffer); wdelayf_reset(_q->x2); // reset internal state _q->timer = _q->n; // reset timer _q->state = DETECTOR_STATE_SEEK; // set state to seek threshold _q->imax = 0; // index of maximum rxy value _q->idetect = 0; // index of detected maximum _q->x2_sum = 0.0f; // sum{ |x|^2 } // clear cross-correlator outputs //memset(_q->rxy, 0x00, sizeof(_q->rxy)); memset(_q->rxy0, 0x00, _q->m*sizeof(float)); memset(_q->rxy1, 0x00, _q->m*sizeof(float)); } // Run sample through pre-demod detector's correlator. // Returns '1' if signal was detected, '0' otherwise // _q : pre-demod detector // _x : input sample // _tau_hat : fractional sample offset estimate (set when detected) // _dphi_hat : carrier frequency offset estimate (set when detected) // _gamma_hat : channel gain estimate (set when detected) int detector_cccf_correlate(detector_cccf _q, float complex _x, float * _tau_hat, float * _dphi_hat, float * _gamma_hat) { // push sample into buffer windowcf_push(_q->buffer, _x); // update sum{|x|^2} detector_cccf_update_sumsq(_q, _x); #if DEBUG_DETECTOR windowcf_push(_q->debug_x, _x); windowf_push(_q->debug_x2, _q->x2_hat); #endif // return if no timeout if (_q->timer) { // hasn't timed out yet //printf("timer = %u\n", _q->timer); _q->timer--; #if DEBUG_DETECTOR windowf_push(_q->debug_rxy, 0.0f); #endif return 0; } // save previous correlator outputs memmove(_q->rxy0, _q->rxy1, _q->m*sizeof(float)); memmove(_q->rxy1, _q->rxy, _q->m*sizeof(float)); // compute vector dot products detector_cccf_compute_dotprods(_q); // find max{rxy} float rxy_abs = _q->rxy[ _q->imax ]; #if DEBUG_DETECTOR windowf_push(_q->debug_rxy, rxy_abs); #endif if (_q->state == DETECTOR_STATE_SEEK) { // check to see if value exceeds threshold if (rxy_abs > _q->threshold) { #if DEBUG_DETECTOR_PRINT printf("threshold exceeded: rxy = %8.4f\n", rxy_abs); #endif _q->idetect = _q->imax; _q->state = DETECTOR_STATE_FINDMAX; } } else if (_q->state == DETECTOR_STATE_FINDMAX) { // see if this new value exceeds maximum if ( _q->rxy[_q->imax] > _q->rxy1[_q->idetect] ) { #if DEBUG_DETECTOR_PRINT printf("maximum not yet reached: rxy = %8.4f\n", rxy_abs); #endif // set new index of maximum _q->idetect = _q->imax; } else { // peak was found last time; run estimates, reset values, // and return #if DEBUG_DETECTOR_PRINT printf("maximum found: rxy = %8.4f\n", rxy_abs); #endif // estimate timing and carrier offsets detector_cccf_estimate_offsets(_q, _tau_hat, _dphi_hat); *_gamma_hat = sqrtf(_q->x2_hat); // soft state reset _q->state = DETECTOR_STATE_SEEK; // set timer to allow signal to settle _q->timer = _q->n/4; return 1; } } else { liquid_error(LIQUID_EINT,"detector_cccf_correlate(), unknown/unsupported internal state"); return 0; } return 0; } // // internal methods // // compute sum{ |x|^2 } void detector_cccf_update_sumsq(detector_cccf _q, float complex _x) { // update estimate of signal magnitude float x2_n = crealf(_x * conjf(_x)); // |x[n-1]|^2 (input sample) float x2_0; // |x[0] |^2 (oldest sample) wdelayf_push(_q->x2, x2_n); // push newest sample wdelayf_read(_q->x2, &x2_0); // read oldest sample _q->x2_sum = _q->x2_sum + x2_n - x2_0; // update sum( |x|^2 ) of last 'n' input samples if (_q->x2_sum < FLT_EPSILON) { _q->x2_sum = FLT_EPSILON; } #if 0 // filtered estimate of E{ |x|^2 } _q->x2_hat = 0.8f*_q->x2_hat + 0.2f*_q->x2_sum*_q->n_inv; #else // unfiltered estimate of E{ |x|^2 } _q->x2_hat = _q->x2_sum * _q->n_inv; #endif } // compute all dot product outputs void detector_cccf_compute_dotprods(detector_cccf _q) { // read buffer float complex * r; windowcf_read(_q->buffer, &r); // compute dot products // TODO: compute conjugate as well unsigned int k; float complex rxy; #if DEBUG_DETECTOR_PRINT printf(" rxy : "); #endif float rxy_max = 0; // TODO: peridically re-compute scaling factor) for (k=0; k<_q->m; k++) { // execute vector dot product dotprod_cccf_execute(_q->dp[k], r, &rxy); // save scaled magnitude // TODO: compute scaled squared magnitude so as not to have // to compute square root _q->rxy[k] = cabsf(rxy) * _q->n_inv / sqrtf(_q->x2_hat); #if DEBUG_DETECTOR_PRINT printf("%6.4f (%6.4f) ", _q->rxy[k], _q->dphi[k]); #endif // find index of maximum if (_q->rxy[k] > rxy_max) { rxy_max = _q->rxy[k]; _q->imax = k; } } #if DEBUG_DETECTOR_PRINT printf("\n"); #endif } // estimate carrier and timing offsets void detector_cccf_estimate_offsets(detector_cccf _q, float * _tau_hat, float * _dphi_hat) { // check length of... if (_q->m == 1) { // compute carrier offset //*_dphi_hat = _q->dphi[_q->idetect]; *_dphi_hat = 0.0f; // interpolate to find timing offset //*_tau_hat = 0.5f*(_q->rxy2 - _q->rxy0) / (_q->rxy2 + _q->rxy0 - 2*_q->rxy1); *_tau_hat = 0.0f; return; } // _q->rxy0: [rm0] // | // | // | // _q->rxy1: [r0m]---[r00]---[r0p]-->freq // | // | // | // [rp0] // | // _q->rxy V time // float rm0 = _q->rxy0[_q->idetect]; float r0m = _q->idetect==0 ? _q->rxy1[_q->idetect+1] : _q->rxy1[_q->idetect-1]; float r00 = _q->rxy1[_q->idetect]; float r0p = _q->idetect==_q->m-1 ? _q->rxy1[_q->idetect-1] : _q->rxy1[_q->idetect+1]; float rp0 = _q->rxy[_q->idetect]; #if DEBUG_DETECTOR_PRINT // print values for interpolation printf("idetect : %u\n", _q->idetect); printf(" [%8.5f]\n", rm0); printf(" |\n"); printf(" |\n"); printf("[%8.5f]---[%8.5f]----[%8.5f]--> freq\n", r0m, r00, r0p); printf(" %8.5f\n", _q->dphi[_q->idetect]); printf(" |\n"); printf(" [%8.5f]\n", rp0); printf(" |\n"); printf(" V time\n"); #endif // interpolate frequency offset estimate float dphi_detect = _q->dphi[_q->idetect]; // frequency from detection *_dphi_hat = dphi_detect - _q->dphi_step * 0.5f*(r0p - r0m) / (r0p + r0m - 2*r00); // interpolate timing offset estimate *_tau_hat = 0.5f*(rp0 - rm0) / (rp0 + rm0 - 2*r00); // force result to be in proper range if (*_tau_hat < -0.499f) *_tau_hat = -0.499f; if (*_tau_hat > 0.499f) *_tau_hat = 0.499f; } #if 0 float detector_cccf_estimate_dphi(detector_cccf _q) { // read buffer... float complex * r; windowcf_read(_q->buffer, &r); // float complex r0 = 0.0f; float complex r1 = 0.0f; float complex metric = 0.0f; unsigned int i; for (i=0; i<_q->n; i++) { r0 = r1; r1 = r[i] * conjf(_q->s[i]); metric += r1 * conjf(r0); } return cargf(metric); } #endif int detector_cccf_debug_print(detector_cccf _q, const char * _filename) { #if DEBUG_DETECTOR FILE * fid = fopen(_filename,"w"); if (!fid) return liquid_error(LIQUID_EIO,"detector_cccf_debug_print(), could not open '%s' for writing", _filename); fprintf(fid,"%% %s : auto-generated file\n", DEBUG_DETECTOR_FILENAME); fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"N = %u;\n", DEBUG_DETECTOR_BUFFER_LEN); unsigned int i; float complex * rc; float * r; fprintf(fid,"x = zeros(1,N);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; idebug_rxy, &r); for (i=0; idebug_x2, &r); for (i=0; i #include #include #include #include #include #include "liquid.internal.h" // write samples to buffer int dsssframe64gen_write(dsssframe64gen _q, float complex * _buf); struct dsssframe64gen_s { unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor unsigned int sf; // spreading factor (fixed) // objects qpacketmodem enc; // packet encoder/modulator qpilotgen pilotgen; // pilot symbol generator msequence ms; // spreading sequence generator firinterp_crcf interp; // pulse-shaping filter/interpolator // buffers float complex preamble_pn[1024]; // 1024-symbol p/n sequence unsigned char payload_dec[ 150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol float complex payload_sym[ 600]; // modulated payload symbols float complex payload_tx [ 650]; // modulated payload symbols with pilots }; // create dsssframe64gen object dsssframe64gen dsssframe64gen_create() { dsssframe64gen q = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); q->m = 15; q->beta = 0.20f; q->sf = 80; // spreading factor unsigned int i; // generate p/n sequence q->ms = msequence_create(11, 0x0500, 1); for (i=0; i<1024; i++) { q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } // create payload encoder/modulator object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_QPSK; q->enc = qpacketmodem_create(); qpacketmodem_configure(q->enc, 72, check, fec0, fec1, mod_scheme); //qpacketmodem_print(q->enc); assert( qpacketmodem_get_frame_len(q->enc)==600 ); // create pilot generator q->pilotgen = qpilotgen_create(600, 13); assert( qpilotgen_get_frame_len(q->pilotgen)==650 ); // create pulse-shaping filter (k=2) q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,2,q->m,q->beta,0); // return main object return q; } // copy object dsssframe64gen dsssframe64gen_copy(dsssframe64gen q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dsssframe64gen_copy(), object cannot be NULL"); // create filter object and copy base parameters dsssframe64gen q_copy = (dsssframe64gen) malloc(sizeof(struct dsssframe64gen_s)); memmove(q_copy, q_orig, sizeof(struct dsssframe64gen_s)); // copy objects q_copy->enc = qpacketmodem_copy (q_orig->enc ); q_copy->pilotgen = qpilotgen_copy (q_orig->pilotgen); q_copy->ms = msequence_copy (q_orig->ms ); q_copy->interp = firinterp_crcf_copy(q_orig->interp ); return q_copy; } // destroy dsssframe64gen object int dsssframe64gen_destroy(dsssframe64gen _q) { // destroy internal objects msequence_destroy (_q->ms); qpacketmodem_destroy (_q->enc); qpilotgen_destroy (_q->pilotgen); firinterp_crcf_destroy(_q->interp); // free main object memory free(_q); return LIQUID_OK; } // print dsssframe64gen object internals int dsssframe64gen_print(dsssframe64gen _q) { printf("\n", _q->m, _q->beta); return LIQUID_OK; } // get full frame length [samples] unsigned int dsssframe64gen_get_frame_len(dsssframe64gen _q) { // add a small amount of zero-padding to ensure entire frame gets pushed through synchronizer return 2*(1024 + 650*_q->sf + 2*_q->m) + 64; } // generate a frame // _q : frame generator object // _header : 8-byte header data, NULL for random // _payload : 64-byte payload data, NULL for random // _frame : output frame samples, [size: dsssframegen64gen_get_frame_len() x 1] int dsssframe64gen_execute(dsssframe64gen _q, const unsigned char * _header, const unsigned char * _payload, float complex * _buf) { unsigned int i; // concatenate header and payload for (i=0; i<8; i++) _q->payload_dec[i] = _header==NULL ? rand() & 0xff : _header[i]; for (i=0; i<64; i++) _q->payload_dec[i+8] = _payload==NULL ? rand() & 0xff : _payload[i]; // run packet encoder and modulator qpacketmodem_encode(_q->enc, _q->payload_dec, _q->payload_sym); // add pilot symbols qpilotgen_execute(_q->pilotgen, _q->payload_sym, _q->payload_tx); // reset objects firinterp_crcf_reset(_q->interp); msequence_reset(_q->ms); // write frame to buffer return dsssframe64gen_write(_q, _buf); } // write samples to buffer // _q : frame generator object // _buf : output frame samples (full frame) int dsssframe64gen_write(dsssframe64gen _q, float complex * _buf) { unsigned int i, j, n=0; // p/n sequence for (i=0; i<1024; i++) { firinterp_crcf_execute(_q->interp, _q->preamble_pn[i], &_buf[n]); n+=2; } // frame payload for (i=0; i<650; i++) { float complex sym = _q->payload_tx[i]; // strip out raw payload symbol for (j=0; j<_q->sf; j++) { // generate pseudo-random symbol unsigned int p = msequence_generate_symbol(_q->ms, 2); float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); firinterp_crcf_execute(_q->interp, sym*s, &_buf[n]); n+=2; } } // interpolator settling for (i=0; i<2*_q->m; i++) { firinterp_crcf_execute(_q->interp, 0.0f, &_buf[n]); n+=2; } // zero-pad end to ensure synchronizer can receive full payload while (n < dsssframe64gen_get_frame_len(_q)) _buf[n++] = 0; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/dsssframe64sync.c000066400000000000000000000317261474751757600220350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // basic direct sequence/spread spectrum frame synchronizer with 8 bytes header // and 64 bytes payload // * reliable frame detection (1% missed) down to -14 dB SNR // * reliable frame decoding (1% errors) down to -11 dB SNR #include #include #include #include #include #include #include "liquid.internal.h" // internal update int dsssframe64sync_step(dsssframe64sync _q, float complex * _buf, unsigned int _buf_len); // internal decode received frame, update statistics, invoke callback int dsssframe64sync_decode(dsssframe64sync _q); // internal synchronization callback, return 0:continue, 1:reset int dsssframe64sync_callback_internal(float complex * _buf, unsigned int _buf_len, void * _context) { return dsssframe64sync_step((dsssframe64sync) _context, _buf, _buf_len); } // dsssframe64sync object structure struct dsssframe64sync_s { // callback framesync_callback callback; // user-defined callback function void * context; // user-defined data structure unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor unsigned int sf; // spreading factor (fixed) framesyncstats_s framesyncstats;// frame statistic object (synchronizer) framedatastats_s framedatastats;// frame statistic object (packet statistics) // preamble float complex preamble_pn[1024];// known 1024-symbol p/n sequence float complex preamble_rx[1024];// received p/n symbols // payload decoder float complex payload_rx [650]; // received payload symbols with pilots float complex payload_sym[600]; // received payload symbols unsigned char payload_dec[ 72]; // decoded payload bytes qdsync_cccf detector; // frame detector msequence ms; // spreading sequence generator float complex sym_despread; // despread symbol qpacketmodem dec; // packet demodulator/decoder qpilotsync pilotsync; // pilot extraction, carrier recovery // status variables unsigned int preamble_counter; // counter: num of p/n syms received unsigned int chip_counter; // counter: num of payload chips received for a single symbol unsigned int payload_counter; // counter: num of payload syms received }; // create dsssframe64sync object // _callback : callback function invoked when frame is received // _context : user-defined data object passed to callback dsssframe64sync dsssframe64sync_create(framesync_callback _callback, void * _context) { dsssframe64sync q = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); q->callback = _callback; q->context = _context; q->m = 15; // filter delay (symbols) q->beta = 0.20f;// excess bandwidth factor q->sf = 80; // spreading factor unsigned int i; // generate p/n sequence q->ms = msequence_create(11, 0x0500, 1); for (i=0; i<1024; i++) { q->preamble_pn[i] = (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(q->ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } // create frame detector unsigned int k = 2; // samples/symbol q->detector = qdsync_cccf_create_linear(q->preamble_pn, 1024, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta, dsssframe64sync_callback_internal, (void*)q); qdsync_cccf_set_threshold(q->detector, 0.097f); // detection threshold qdsync_cccf_set_range (q->detector, 0.006f); // frequency offset search range [radians/sample] // create payload demodulator/decoder object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_QPSK; q->dec = qpacketmodem_create(); qpacketmodem_configure(q->dec, 72, check, fec0, fec1, mod_scheme); //qpacketmodem_print(q->dec); assert( qpacketmodem_get_frame_len(q->dec)==600 ); // create pilot synchronizer q->pilotsync = qpilotsync_create(600, 13); assert( qpilotsync_get_frame_len(q->pilotsync)==650); // reset global data counters dsssframe64sync_reset_framedatastats(q); // reset state and return dsssframe64sync_reset(q); return q; } // copy object dsssframe64sync dsssframe64sync_copy(dsssframe64sync q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("dsssframe64sync_copy(), object cannot be NULL"); // allocate memory for new object dsssframe64sync q_copy = (dsssframe64sync) malloc(sizeof(struct dsssframe64sync_s)); // copy entire memory space over and overwrite values as needed memmove(q_copy, q_orig, sizeof(struct dsssframe64sync_s)); // copy internal objects q_copy->detector = qdsync_cccf_copy (q_orig->detector); q_copy->ms = msequence_copy (q_orig->ms); q_copy->dec = qpacketmodem_copy(q_orig->dec); q_copy->pilotsync = qpilotsync_copy (q_orig->pilotsync); // update detector callback's context to use q_copy qdsync_cccf_set_context(q_copy->detector, (void*)q_copy); return q_copy; } // destroy frame synchronizer object, freeing all internal memory int dsssframe64sync_destroy(dsssframe64sync _q) { // destroy synchronization objects msequence_destroy (_q->ms); // pseudo-random sequence generator qdsync_cccf_destroy (_q->detector); // frame detector qpacketmodem_destroy(_q->dec); // payload demodulator qpilotsync_destroy (_q->pilotsync); // pilot synchronizer // free main object memory free(_q); return LIQUID_OK; } // print frame synchronizer object internals int dsssframe64sync_print(dsssframe64sync _q) { printf("\n", _q->preamble_counter, _q->chip_counter, _q->payload_counter); return LIQUID_OK; } // reset frame synchronizer object int dsssframe64sync_reset(dsssframe64sync _q) { // reset detector/synchronizer qdsync_cccf_reset(_q->detector); msequence_reset(_q->ms); // reset state _q->preamble_counter= 0; _q->chip_counter = 0; _q->payload_counter = 0; _q->sym_despread = 0; // reset frame statistics _q->framesyncstats.evm = 0.0f; return LIQUID_OK; } int dsssframe64sync_is_frame_open(dsssframe64sync _q) { return _q->preamble_counter > 0; } // set the callback function int dsssframe64sync_set_callback(dsssframe64sync _q, framesync_callback _callback) { _q->callback = _callback; return LIQUID_OK; } // set the user-defined data field (context) int dsssframe64sync_set_context(dsssframe64sync _q, void * _context) { _q->context= _context; return LIQUID_OK; } // execute frame synchronizer // _q : frame synchronizer object // _buf : input sample array, shape: (_buf_len,) // _buf_len : number of input samples int dsssframe64sync_execute(dsssframe64sync _q, float complex * _buf, unsigned int _buf_len) { // run detector/synchronizer, invoking internal callback as needed return qdsync_cccf_execute(_q->detector, _buf, _buf_len); } // set detection threshold int dsssframe64sync_set_threshold(dsssframe64sync _q, float _threshold) { return qdsync_cccf_set_threshold(_q->detector, _threshold); } // get detection threshold float dsssframe64sync_get_threshold(dsssframe64sync _q) { return qdsync_cccf_get_threshold(_q->detector); } // set carrier offset search range int dsssframe64sync_set_range(dsssframe64sync _q, float _dphi_max) { return qdsync_cccf_set_range(_q->detector, _dphi_max); } // get detection threshold float dsssframe64sync_get_range(dsssframe64sync _q) { return qdsync_cccf_get_range(_q->detector); } // reset frame data statistics int dsssframe64sync_reset_framedatastats(dsssframe64sync _q) { return framedatastats_reset(&_q->framedatastats); } // retrieve frame data statistics framedatastats_s dsssframe64sync_get_framedatastats(dsssframe64sync _q) { return _q->framedatastats; } // internal update int dsssframe64sync_step(dsssframe64sync _q, float complex * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // receive preamble (not currently used) if (_q->preamble_counter < 1024) { _q->preamble_rx[_q->preamble_counter++] = _buf[i]; continue; } // generate pseudo-random spreading symbol and de-spread chip unsigned int p = msequence_generate_symbol(_q->ms, 2); float complex s = cexpf(_Complex_I*2*M_PI*(float)p/(float)4); _q->sym_despread += _buf[i] * conjf(s); _q->chip_counter++; // accumulate if (_q->chip_counter == _q->sf) { _q->payload_rx[_q->payload_counter] = _q->sym_despread / (float)(_q->sf); _q->payload_counter++; _q->chip_counter = 0; _q->sym_despread = 0; if (_q->payload_counter == 650) { dsssframe64sync_decode(_q); msequence_reset(_q->ms); return 1; // reset qdsync } } } return 0; // need more data } // internal decode received frame, update statistics, invoke callback int dsssframe64sync_decode(dsssframe64sync _q) { // recover data symbols from pilots qpilotsync_execute(_q->pilotsync, _q->payload_rx, _q->payload_sym); // decode payload int crc_pass = qpacketmodem_decode(_q->dec, _q->payload_sym, _q->payload_dec); #if 0 // debug: export symbols to file unsigned int i; FILE * fid = fopen("dsssframe64sync_debug.m","w"); fprintf(fid,"clear all; close all; r=zeros(1,650); s=zeros(1,600);\n"); for (i=0; i<650; i++) fprintf(fid,"r(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_rx[i]), cimagf(_q->payload_rx[i])); for (i=0; i<600; i++) fprintf(fid,"s(%3u)=%12.4e + %12.4ej;\n", i+1, crealf(_q->payload_sym[i]), cimagf(_q->payload_sym[i])); fclose(fid); #endif // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid += crc_pass; _q->framedatastats.num_payloads_valid += crc_pass; _q->framedatastats.num_bytes_received += crc_pass ? 64 : 0; // invoke callback int rc = 0; if (_q->callback != NULL) { // offset estimates float dphi_hat = qdsync_cccf_get_dphi(_q->detector) + qpilotsync_get_dphi(_q->pilotsync) / (float)(_q->sf); // set framesyncstats internals _q->framesyncstats.evm = qpilotsync_get_evm(_q->pilotsync); _q->framesyncstats.rssi = 20*log10f(qdsync_cccf_get_gamma(_q->detector)); _q->framesyncstats.cfo = dphi_hat; _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = 600; _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; _q->framesyncstats.mod_bps = 2; _q->framesyncstats.check = LIQUID_CRC_24; _q->framesyncstats.fec0 = LIQUID_FEC_NONE; _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; // invoke callback method rc = _q->callback(&_q->payload_dec[0], // header is first 8 bytes crc_pass, &_q->payload_dec[8], // payload is last 64 bytes 64, crc_pass, _q->framesyncstats, _q->context); } // reset frame synchronizer and return dsssframe64sync_reset(_q); return rc; } liquid-dsp-1.7.0/src/framing/src/dsssframegen.c000066400000000000000000000353271474751757600214610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // dsssframegen.c // // dsss flexible frame generator // #include #include #include #include #include #include "liquid.internal.h" // reconfigure internal properties int dsssframegen_reconfigure (dsssframegen _q); int dsssframegen_reconfigure_header(dsssframegen _q); float complex dsssframegen_generate_symbol (dsssframegen _q); float complex dsssframegen_generate_preamble (dsssframegen _q); float complex dsssframegen_generate_header (dsssframegen _q); float complex dsssframegen_generate_payload (dsssframegen _q); float complex dsssframegen_generate_tail (dsssframegen _q); // default dsssframegen properties static dsssframegenprops_s dsssframegenprops_default = { LIQUID_CRC_16, // check LIQUID_FEC_NONE, // fec0 LIQUID_FEC_NONE, // fec1 }; static dsssframegenprops_s dsssframegenprops_header_default = { DSSSFRAME_H_CRC, DSSSFRAME_H_FEC0, DSSSFRAME_H_FEC1, }; enum state { STATE_PREAMBLE = 0, // write preamble p/n sequence STATE_HEADER, // write header symbols STATE_PAYLOAD, // write payload symbols STATE_TAIL, // tail symbols }; struct dsssframegen_s { // interpolator unsigned int k; // interp samples/symbol (fixed at 2) unsigned int m; // interp filter delay (symbols) float beta; // excess bandwidth factor firinterp_crcf interp; // interpolator object float complex buf_interp[2]; // output interpolator buffer [size: k x 1] dsssframegenprops_s props; // payload properties dsssframegenprops_s header_props; // header properties // preamble float complex * preamble_pn; // p/n sequence synth_crcf header_synth; synth_crcf payload_synth; // header unsigned char * header; // header data unsigned int header_user_len; // header user section length unsigned int header_dec_len; // header length (decoded) qpacketmodem header_encoder; // header encoder/modulator unsigned int header_mod_len; // header length float complex * header_mod; // payload unsigned int payload_dec_len; // length of decoded qpacketmodem payload_encoder; unsigned int payload_mod_len; float complex * payload_mod; // counters/states unsigned int symbol_counter; // output symbol number unsigned int sample_counter; // output sample number unsigned int bit_counter; // output bit number int bit_high; // current bit is 1 float complex sym; int frame_assembled; // frame assembled flag int frame_complete; // frame completed flag enum state state; // write state }; dsssframegen dsssframegen_create(dsssframegenprops_s * _fgprops) { dsssframegen q = (dsssframegen)calloc(1, sizeof(struct dsssframegen_s)); unsigned int i; // create pulse-shaping filter q->k = 2; q->m = 7; q->beta = 0.25f; q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER, q->k, q->m, q->beta, 0); // generate pn sequence q->preamble_pn = (float complex *)malloc(64 * sizeof(float complex)); msequence ms = msequence_create(7, 0x0089, 1); for (i = 0; i < 64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } msequence_destroy(ms); float complex * pn = (float complex *)malloc(64 * sizeof(float complex)); ms = msequence_create(7, 0x00cb, 0x53); for (i = 0; i < 64; i++) { pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } q->header_synth = synth_crcf_create(pn, 64); q->payload_synth = synth_crcf_create(pn, 64); free(pn); msequence_destroy(ms); dsssframegen_reset(q); q->header = NULL; q->header_user_len = DSSSFRAME_H_USER_DEFAULT; q->header_dec_len = DSSSFRAME_H_DEC + q->header_user_len; q->header_mod = NULL; q->header_encoder = qpacketmodem_create(); q->payload_encoder = qpacketmodem_create(); q->payload_dec_len = 0; q->payload_mod_len = 0; q->payload_mod = NULL; dsssframegen_setprops(q, _fgprops); dsssframegen_set_header_props(q, NULL); dsssframegen_set_header_len(q, q->header_user_len); return q; } int dsssframegen_destroy(dsssframegen _q) { if (_q == NULL) return liquid_error(LIQUID_EIOBJ,"dsssframegen_destroy(), NULL pointer passed"); firinterp_crcf_destroy(_q->interp); qpacketmodem_destroy(_q->header_encoder); qpacketmodem_destroy(_q->payload_encoder); synth_crcf_destroy(_q->header_synth); synth_crcf_destroy(_q->payload_synth); free(_q->preamble_pn); free(_q->header); free(_q->header_mod); free(_q->payload_mod); free(_q); return LIQUID_OK; } int dsssframegen_reset(dsssframegen _q) { // reset internal counters and state _q->symbol_counter = 0; _q->bit_counter = 0; _q->sample_counter = 0; _q->frame_assembled = 0; _q->frame_complete = 0; _q->state = STATE_PREAMBLE; return LIQUID_OK; } int dsssframegen_is_assembled(dsssframegen _q) { return _q->frame_assembled; } int dsssframegen_getprops(dsssframegen _q, dsssframegenprops_s * _props) { memmove(_props, &_q->props, sizeof(dsssframegenprops_s)); return LIQUID_OK; } int dsssframegen_setprops(dsssframegen _q, dsssframegenprops_s * _props) { if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"dsssframegen_setprops(), frame is already assembled; must reset() first"); if (_props == NULL) { dsssframegen_setprops(_q, &dsssframegenprops_default); return LIQUID_OK; } if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"dsssframegen_setprops(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"dsssframegen_setprops(), invalid/unsupported FEC scheme"); // copy properties to internal structure memmove(&_q->props, _props, sizeof(dsssframegenprops_s)); // reconfigure payload buffers (reallocate as necessary) return dsssframegen_reconfigure(_q); } int dsssframegen_set_header_len(dsssframegen _q, unsigned int _len) { if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"dsssframegen_set_header_len(), frame is already assembled; must reset() first"); _q->header_user_len = _len; _q->header_dec_len = DSSSFRAME_H_DEC + _q->header_user_len; _q->header = (unsigned char *)realloc(_q->header, _q->header_dec_len * sizeof(unsigned char)); return dsssframegen_reconfigure_header(_q); } int dsssframegen_set_header_props(dsssframegen _q, dsssframegenprops_s * _props) { if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"dsssframegen_set_header_props(), frame is already assembled; must reset() first"); if (_props == NULL) _props = &dsssframegenprops_header_default; if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EIMODE,"dsssframegen_set_header_props(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EIMODE,"dsssframegen_set_header_props(), invalid/unsupported FEC scheme"); memmove(&_q->header_props, _props, sizeof(dsssframegenprops_s)); return dsssframegen_reconfigure_header(_q); } unsigned int dsssframegen_getframelen(dsssframegen _q) { if (_q->frame_assembled) { liquid_error(LIQUID_EICONFIG,"dsssframegen_get_header_props(), frame is already assembled; must reset() first"); return 0; } unsigned int num_frame_symbols = 64 + // preamble _q->header_mod_len * synth_crcf_get_length(_q->header_synth) + _q->payload_mod_len * synth_crcf_get_length(_q->payload_synth) + 2 * _q->m; // tail return num_frame_symbols * _q->k; } int dsssframegen_assemble(dsssframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_dec_len) { dsssframegen_reset(_q); _q->payload_dec_len = _payload_dec_len; if (_header == NULL) memset(_q->header, 0x00, _q->header_user_len * sizeof(unsigned char)); else memmove(_q->header, _header, _q->header_user_len * sizeof(unsigned char)); unsigned int n = _q->header_user_len; _q->header[n + 0] = DSSSFRAME_PROTOCOL; _q->header[n + 1] = (_q->payload_dec_len >> 8) & 0xff; _q->header[n + 2] = (_q->payload_dec_len) & 0xff; _q->header[n + 3] = (_q->props.check & 0x07) << 5; _q->header[n + 3] |= (_q->props.fec0) & 0x1f; _q->header[n + 4] = (_q->props.fec1) & 0x1f; qpacketmodem_encode(_q->header_encoder, _q->header, _q->header_mod); _q->payload_dec_len = _payload_dec_len; dsssframegen_reconfigure(_q); qpacketmodem_encode(_q->payload_encoder, _payload, _q->payload_mod); _q->frame_assembled = 1; return LIQUID_OK; } int dsssframegen_write_samples(dsssframegen _q, float complex * _buffer, unsigned int _buffer_len) { unsigned int i; for (i = 0; i < _buffer_len; ++i) { if (_q->sample_counter == 0) { float complex sym = dsssframegen_generate_symbol(_q); firinterp_crcf_execute(_q->interp, sym, _q->buf_interp); } _buffer[i] = _q->buf_interp[_q->sample_counter]; // apply ramping window to first 'm' symbols if (_q->symbol_counter < _q->m && _q->state == STATE_PREAMBLE) { _buffer[i] *= liquid_hamming(_q->symbol_counter * _q->k + _q->sample_counter, 2 * _q->m * _q->k); } _q->sample_counter = (_q->sample_counter + 1) % _q->k; } return _q->frame_complete; } int dsssframegen_reconfigure(dsssframegen _q) { qpacketmodem_configure(_q->payload_encoder, _q->payload_dec_len, _q->props.check, _q->props.fec0, _q->props.fec1, LIQUID_MODEM_BPSK); _q->payload_mod_len = qpacketmodem_get_frame_len(_q->payload_encoder); _q->payload_mod = (float complex *)realloc( _q->payload_mod, _q->payload_mod_len * sizeof(float complex)); return LIQUID_OK; } int dsssframegen_reconfigure_header(dsssframegen _q) { qpacketmodem_configure(_q->header_encoder, _q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1, LIQUID_MODEM_BPSK); _q->header_mod_len = qpacketmodem_get_frame_len(_q->header_encoder); _q->header_mod = (float complex *)realloc( _q->header_mod, _q->header_mod_len * sizeof(float complex)); return LIQUID_OK; } float complex dsssframegen_generate_symbol(dsssframegen _q) { if (!_q->frame_assembled) { return 0.f; } switch (_q->state) { case STATE_PREAMBLE: return dsssframegen_generate_preamble(_q); case STATE_HEADER: return dsssframegen_generate_header(_q); case STATE_PAYLOAD: return dsssframegen_generate_payload(_q); case STATE_TAIL: return dsssframegen_generate_tail(_q); default: liquid_error(LIQUID_EINT,"dsssframegen_generate_symbol(), unknown/unsupported internal state"); } return 0.f; } float complex dsssframegen_generate_preamble(dsssframegen _q) { float complex symbol = _q->preamble_pn[_q->symbol_counter]; ++_q->symbol_counter; if (_q->symbol_counter == 64) { _q->symbol_counter = 0; _q->state = STATE_HEADER; } return symbol; } float complex dsssframegen_generate_header(dsssframegen _q) { if (_q->symbol_counter == 0) { _q->sym = _q->header_mod[_q->bit_counter]; } float complex symbol; synth_crcf_mix_up(_q->header_synth, _q->sym, &symbol); synth_crcf_step(_q->header_synth); ++_q->symbol_counter; if (_q->symbol_counter == synth_crcf_get_length(_q->header_synth)) { _q->symbol_counter = 0; ++_q->bit_counter; if (_q->bit_counter == _q->header_mod_len) { _q->bit_counter = 0; _q->state = STATE_PAYLOAD; } } return symbol; } float complex dsssframegen_generate_payload(dsssframegen _q) { if (_q->symbol_counter == 0) { _q->sym = _q->payload_mod[_q->bit_counter]; } float complex symbol; synth_crcf_mix_up(_q->payload_synth, _q->sym, &symbol); synth_crcf_step(_q->payload_synth); ++_q->symbol_counter; if (_q->symbol_counter == synth_crcf_get_length(_q->payload_synth)) { _q->symbol_counter = 0; ++_q->bit_counter; if (_q->bit_counter == _q->payload_mod_len) { _q->bit_counter = 0; _q->state = STATE_TAIL; } } return symbol; } float complex dsssframegen_generate_tail(dsssframegen _q) { ++_q->symbol_counter; if (_q->symbol_counter == 2 * _q->m) { _q->symbol_counter = 0; _q->frame_complete = 1; _q->frame_assembled = 0; } return 0.f; } liquid-dsp-1.7.0/src/framing/src/dsssframesync.c000066400000000000000000000462241474751757600216620ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // dsssframesync.c // #include #include #include #include #include #include #include "liquid.internal.h" int dsssframesync_execute_seekpn (dsssframesync _q, float complex _x); int dsssframesync_step (dsssframesync _q, float complex _x, float complex * _y); int dsssframesync_execute_rxpreamble(dsssframesync _q, float complex _x); int dsssframesync_decode_header (dsssframesync _q); int dsssframesync_decode_payload (dsssframesync _q); int dsssframesync_execute_rxheader (dsssframesync _q, float complex _x); int dsssframesync_execute_rxpayload (dsssframesync _q, float complex _x); int dsssframesync_configure_payload (dsssframesync _q); static dsssframegenprops_s dsssframesyncprops_header_default = { DSSSFRAME_H_CRC, DSSSFRAME_H_FEC0, DSSSFRAME_H_FEC1, }; enum state { DSSSFRAMESYNC_STATE_DETECTFRAME = 0, DSSSFRAMESYNC_STATE_RXPREAMBLE, DSSSFRAMESYNC_STATE_RXHEADER, DSSSFRAMESYNC_STATE_RXPAYLOAD, }; struct dsssframesync_s { framesync_callback callback; void * userdata; framesyncstats_s framesyncstats; framedatastats_s framedatastats; unsigned int k; unsigned int m; float beta; qdetector_cccf detector; float tau_hat; float dphi_hat; float phi_hat; float gamma_hat; nco_crcf mixer; nco_crcf pll; firpfb_crcf mf; unsigned int npfb; int mf_counter; unsigned int pfb_index; float complex * preamble_pn; float complex * preamble_rx; synth_crcf header_synth; synth_crcf payload_synth; int header_soft; flexframegenprops_s header_props; float complex * header_spread; unsigned int header_spread_len; qpacketmodem header_decoder; unsigned int header_user_len; unsigned int header_dec_len; unsigned char * header_dec; int header_valid; int payload_soft; float complex * payload_spread; unsigned int payload_spread_len; qpacketmodem payload_decoder; unsigned int payload_dec_len; unsigned char * payload_dec; int payload_valid; unsigned int preamble_counter; unsigned int symbol_counter; enum state state; }; dsssframesync dsssframesync_create(framesync_callback _callback, void * _userdata) { dsssframesync q = (dsssframesync)calloc(1, sizeof(struct dsssframesync_s)); q->callback = _callback; q->userdata = _userdata; q->k = 2; q->m = 7; q->beta = 0.3f; unsigned int i; q->preamble_pn = (float complex *)calloc(64, sizeof(float complex)); q->preamble_rx = (float complex *)calloc(64, sizeof(float complex)); msequence ms = msequence_create(7, 0x0089, 1); for (i = 0; i < 64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } msequence_destroy(ms); float complex * pn = (float complex *)calloc(64, sizeof(float complex)); ms = msequence_create(7, 0x00cb, 0x53); for (i = 0; i < 64; i++) { pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } q->header_synth = synth_crcf_create(pn, 64); q->payload_synth = synth_crcf_create(pn, 64); synth_crcf_pll_set_bandwidth(q->header_synth, 1e-4f); synth_crcf_pll_set_bandwidth(q->payload_synth, 1e-4f); free(pn); msequence_destroy(ms); q->detector = qdetector_cccf_create_linear( q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, q->k, q->m, q->beta); qdetector_cccf_set_threshold(q->detector, 0.5f); q->npfb = 32; q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb, q->k, q->m, q->beta); q->mixer = nco_crcf_create(LIQUID_NCO); q->pll = nco_crcf_create(LIQUID_NCO); nco_crcf_pll_set_bandwidth(q->pll, 1e-4f); // very low bandwidth q->header_decoder = qpacketmodem_create(); q->header_user_len = DSSSFRAME_H_USER_DEFAULT; dsssframesync_set_header_props(q, NULL); q->payload_decoder = qpacketmodem_create(); q->payload_spread_len = 64; q->payload_spread = (float complex *)malloc(q->payload_spread_len * sizeof(float complex)); dsssframesync_reset_framedatastats(q); dsssframesync_reset(q); return q; } int dsssframesync_destroy(dsssframesync _q) { if (_q == NULL) return liquid_error(LIQUID_EIOBJ,"dsssframesync_destroy(), NULL pointer passed"); free(_q->preamble_pn); free(_q->preamble_rx); free(_q->header_spread); free(_q->header_dec); free(_q->payload_spread); free(_q->payload_dec); qpacketmodem_destroy(_q->header_decoder); qpacketmodem_destroy(_q->payload_decoder); qdetector_cccf_destroy(_q->detector); firpfb_crcf_destroy(_q->mf); nco_crcf_destroy(_q->mixer); nco_crcf_destroy(_q->pll); synth_crcf_destroy(_q->header_synth); synth_crcf_destroy(_q->payload_synth); free(_q); return LIQUID_OK; } int dsssframesync_print(dsssframesync _q) { printf("\n"); return LIQUID_OK; } int dsssframesync_reset(dsssframesync _q) { qdetector_cccf_reset(_q->detector); nco_crcf_reset(_q->mixer); nco_crcf_reset(_q->pll); firpfb_crcf_reset(_q->mf); _q->state = DSSSFRAMESYNC_STATE_DETECTFRAME; _q->preamble_counter = 0; _q->symbol_counter = 0; _q->framesyncstats.evm = 0.f; return LIQUID_OK; } int dsssframesync_is_frame_open(dsssframesync _q) { return (_q->state == DSSSFRAMESYNC_STATE_DETECTFRAME) ? 0 : 1; } int dsssframesync_set_header_len(dsssframesync _q, unsigned int _len) { _q->header_user_len = _len; _q->header_dec_len = DSSSFRAME_H_DEC + _q->header_user_len; _q->header_dec = (unsigned char *)realloc(_q->header_dec, _q->header_dec_len * sizeof(unsigned char)); qpacketmodem_configure(_q->header_decoder, _q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1, LIQUID_MODEM_BPSK); _q->header_spread_len = synth_crcf_get_length(_q->header_synth); _q->header_spread = (float complex *)realloc( _q->header_spread, _q->header_spread_len * sizeof(float complex)); return LIQUID_OK; } int dsssframesync_decode_header_soft(dsssframesync _q, int _soft) { _q->header_soft = _soft; return LIQUID_OK; } int dsssframesync_decode_payload_soft(dsssframesync _q, int _soft) { _q->payload_soft = _soft; return LIQUID_OK; } int dsssframesync_set_header_props(dsssframesync _q, dsssframegenprops_s * _props) { if (_props == NULL) _props = &dsssframesyncprops_header_default; if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EIMODE,"dsssframesync_set_header_props(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EIMODE,"dsssframesync_set_header_props(), invalid/unsupported FEC scheme"); // copy properties to internal structure memmove(&_q->header_props, _props, sizeof(dsssframegenprops_s)); // reconfigure payload buffers (reallocate as necessary) return dsssframesync_set_header_len(_q, _q->header_user_len); } int dsssframesync_execute(dsssframesync _q, float complex * _x, unsigned int _n) { unsigned int i; for (i = 0; i < _n; i++) { switch (_q->state) { case DSSSFRAMESYNC_STATE_DETECTFRAME: // detect frame (look for p/n sequence) dsssframesync_execute_seekpn(_q, _x[i]); break; case DSSSFRAMESYNC_STATE_RXPREAMBLE: // receive p/n sequence symbols dsssframesync_execute_rxpreamble(_q, _x[i]); break; case DSSSFRAMESYNC_STATE_RXHEADER: // receive header symbols dsssframesync_execute_rxheader(_q, _x[i]); break; case DSSSFRAMESYNC_STATE_RXPAYLOAD: // receive payload symbols dsssframesync_execute_rxpayload(_q, _x[i]); break; default: return liquid_error(LIQUID_EINT,"dsssframesync_execute(), invalid internal state"); } } return LIQUID_OK; } // execute synchronizer, seeking p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int dsssframesync_execute_seekpn(dsssframesync _q, float complex _x) { // push through pre-demod synchronizer float complex * v = qdetector_cccf_execute(_q->detector, _x); // check if frame has been detected if (v == NULL) return LIQUID_OK; // get estimates _q->tau_hat = qdetector_cccf_get_tau(_q->detector); _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); _q->dphi_hat = qdetector_cccf_get_dphi(_q->detector); _q->phi_hat = qdetector_cccf_get_phi(_q->detector); // set appropriate filterbank index if (_q->tau_hat > 0) { _q->pfb_index = (unsigned int)(_q->tau_hat * _q->npfb) % _q->npfb; _q->mf_counter = 0; } else { _q->pfb_index = (unsigned int)((1.0f + _q->tau_hat) * _q->npfb) % _q->npfb; _q->mf_counter = 1; } // output filter scale (gain estimate, scaled by 1/2 for k=2 samples/symbol) firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); // set frequency/phase of mixer nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); nco_crcf_set_phase(_q->mixer, _q->phi_hat); // update state _q->state = DSSSFRAMESYNC_STATE_RXPREAMBLE; // run buffered samples through synchronizer unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); return dsssframesync_execute(_q, v, buf_len); } int dsssframesync_step(dsssframesync _q, float complex _x, float complex * _y) { // mix sample down float complex v; nco_crcf_mix_down(_q->mixer, _x, &v); nco_crcf_step(_q->mixer); // push sample into filterbank firpfb_crcf_push(_q->mf, v); firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); // increment counter to determine if sample is available _q->mf_counter++; int sample_available = (_q->mf_counter >= 1) ? 1 : 0; // set output sample if available if (sample_available) { // set output *_y = v; // decrement counter by k=2 samples/symbol _q->mf_counter -= _q->k; } // return flag return sample_available; } int dsssframesync_execute_rxpreamble(dsssframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = dsssframesync_step(_q, _x, &mf_out); // compute output if timeout if (!sample_available) return LIQUID_OK; // save output in p/n symbols buffer unsigned int delay = _q->k * _q->m; // delay from matched filter if (_q->preamble_counter >= delay) { unsigned int index = _q->preamble_counter - delay; _q->preamble_rx[index] = mf_out; } // update p/n counter _q->preamble_counter++; // update state if (_q->preamble_counter == 64 + delay) _q->state = DSSSFRAMESYNC_STATE_RXHEADER; return LIQUID_OK; } int dsssframesync_execute_rxheader(dsssframesync _q, float complex _x) { float complex mf_out = 0.f; int sample_available = dsssframesync_step(_q, _x, &mf_out); if (!sample_available) return LIQUID_OK; _q->header_spread[_q->symbol_counter % synth_crcf_get_length(_q->header_synth)] = mf_out; ++_q->symbol_counter; if (_q->symbol_counter % synth_crcf_get_length(_q->header_synth)) return LIQUID_OK; int header_complete = dsssframesync_decode_header(_q); if (!header_complete) return LIQUID_OK; if (_q->header_valid) { _q->symbol_counter = 0; _q->state = DSSSFRAMESYNC_STATE_RXPAYLOAD; return LIQUID_OK; } // if not taken, header is NOT valid ++_q->framedatastats.num_frames_detected; if (_q->callback != NULL) { _q->framesyncstats.evm = 0.f; _q->framesyncstats.rssi = 20 * log10f(_q->gamma_hat); _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; _q->callback( _q->header_dec, _q->header_valid, NULL, 0, 0, _q->framesyncstats, _q->userdata); } return dsssframesync_reset(_q); } int dsssframesync_decode_header(dsssframesync _q) { float complex prev_corr, corr, next_corr; nco_crcf_mix_block_down( _q->pll, _q->header_spread, _q->header_spread, synth_crcf_get_length(_q->header_synth)); synth_crcf_despread_triple(_q->header_synth, _q->header_spread, &prev_corr, &corr, &next_corr); int complete = qpacketmodem_decode_soft_sym(_q->header_decoder, corr); float phase_error = qpacketmodem_get_demodulator_phase_error(_q->header_decoder); nco_crcf_pll_step(_q->pll, synth_crcf_get_length(_q->header_synth) * phase_error); if (!complete) { return 0; } dsssframesync_configure_payload(_q); return 1; } int dsssframesync_configure_payload(dsssframesync _q) { _q->header_valid = qpacketmodem_decode_soft_payload(_q->header_decoder, _q->header_dec); if (!_q->header_valid) return LIQUID_OK; unsigned int n = _q->header_user_len; unsigned int protocol = _q->header_dec[n + 0]; if (protocol != DSSSFRAME_PROTOCOL) { _q->header_valid = 0; return liquid_error(LIQUID_EIMODE,"dsssframesync_decode_header(), invalid framing protocol %u (expected %u)\n",protocol,DSSSFRAME_PROTOCOL); } unsigned int payload_dec_len = (_q->header_dec[n + 1] << 8) | (_q->header_dec[n + 2]); _q->payload_dec_len = payload_dec_len; unsigned int check = (_q->header_dec[n + 3] >> 5) & 0x07; unsigned int fec0 = (_q->header_dec[n + 3]) & 0x1f; unsigned int fec1 = (_q->header_dec[n + 4]) & 0x1f; if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EIMODE,"dsssframesync_decode_header(), decoded CRC exceeds available\n"); } else if (fec0 == LIQUID_FEC_UNKNOWN || fec0 >= LIQUID_FEC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EIMODE,"dsssframesync_decode_header(), decoded FEC (inner) exceeds available\n"); return LIQUID_OK; } else if (fec1 == LIQUID_FEC_UNKNOWN || fec1 >= LIQUID_FEC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EIMODE,"dsssframesync_decode_header(), decoded FEC (outer) exceeds available\n"); } _q->payload_dec = (unsigned char *)realloc(_q->payload_dec, (_q->payload_dec_len) * sizeof(unsigned char)); qpacketmodem_configure( _q->payload_decoder, _q->payload_dec_len, check, fec0, fec1, LIQUID_MODEM_BPSK); synth_crcf_set_frequency(_q->payload_synth, synth_crcf_get_frequency(_q->header_synth)); return LIQUID_OK; } int dsssframesync_execute_rxpayload(dsssframesync _q, float complex _x) { float complex mf_out = 0.f; int sample_available = dsssframesync_step(_q, _x, &mf_out); if (!sample_available) return LIQUID_OK; _q->payload_spread[_q->symbol_counter % synth_crcf_get_length(_q->payload_synth)] = mf_out; ++_q->symbol_counter; if (_q->symbol_counter % synth_crcf_get_length(_q->payload_synth) != 0) return LIQUID_OK; int payload_complete = dsssframesync_decode_payload(_q); if (!payload_complete) return LIQUID_OK; _q->framesyncstats.check = qpacketmodem_get_crc(_q->payload_decoder); _q->framesyncstats.fec0 = qpacketmodem_get_fec0(_q->payload_decoder); _q->framesyncstats.fec1 = qpacketmodem_get_fec1(_q->payload_decoder); if (_q->callback != NULL) { _q->callback(_q->header_dec, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framesyncstats, _q->userdata); } return dsssframesync_reset(_q); } int dsssframesync_decode_payload(dsssframesync _q) { float complex prev_corr, corr, next_corr; nco_crcf_mix_block_down( _q->pll, _q->payload_spread, _q->payload_spread, synth_crcf_get_length(_q->payload_synth)); synth_crcf_despread_triple( _q->payload_synth, _q->payload_spread, &prev_corr, &corr, &next_corr); int complete = qpacketmodem_decode_soft_sym(_q->payload_decoder, corr); float phase_error = qpacketmodem_get_demodulator_phase_error(_q->payload_decoder); nco_crcf_pll_step(_q->pll, synth_crcf_get_length(_q->payload_synth) * phase_error); if (!complete) { return 0; } _q->payload_valid = qpacketmodem_decode_soft_payload(_q->payload_decoder, _q->payload_dec); return 1; } int dsssframesync_reset_framedatastats(dsssframesync _q) { return framedatastats_reset(&_q->framedatastats); } framedatastats_s dsssframesync_get_framedatastats(dsssframesync _q) { return _q->framedatastats; } int dsssframesync_debug_enable(dsssframesync _q) { return liquid_error(LIQUID_EIMODE,"dsssframesync_debug_enable(), mode not supported"); } int dsssframesync_debug_disable(dsssframesync _q) { return liquid_error(LIQUID_EIMODE,"dsssframesync_debug_disable(), mode not supported"); } int dsssframesync_debug_print(dsssframesync _q, const char * _filename) { return liquid_error(LIQUID_EIMODE,"dsssframesync_debug_print(), mode not supported"); } liquid-dsp-1.7.0/src/framing/src/flexframegen.c000066400000000000000000000463641474751757600214460ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // flexible frame generator #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_FLEXFRAMEGEN 1 // reconfigure internal properties int flexframegen_reconfigure (flexframegen _q); float complex flexframegen_generate_symbol (flexframegen _q); float complex flexframegen_generate_preamble(flexframegen _q); float complex flexframegen_generate_header (flexframegen _q); float complex flexframegen_generate_payload (flexframegen _q); float complex flexframegen_generate_tail (flexframegen _q); // default flexframegen properties static flexframegenprops_s flexframegenprops_default = { LIQUID_CRC_16, // check LIQUID_FEC_NONE, // fec0 LIQUID_FEC_NONE, // fec1 LIQUID_MODEM_BPSK, // mod_scheme }; static flexframegenprops_s flexframegenprops_header_default = { FLEXFRAME_H_CRC, FLEXFRAME_H_FEC0, FLEXFRAME_H_FEC1, FLEXFRAME_H_MOD, }; int flexframegenprops_init_default(flexframegenprops_s * _props) { memmove(_props, &flexframegenprops_default, sizeof(flexframegenprops_s)); return LIQUID_OK; } struct flexframegen_s { // interpolator unsigned int k; // interp samples/symbol (fixed at 2) unsigned int m; // interp filter delay (symbols) float beta; // excess bandwidth factor firinterp_crcf interp; // interpolator object float complex buf_interp[2]; // output interpolator buffer [size: k x 1] flexframegenprops_s props; // payload properties flexframegenprops_s header_props; // header properties // preamble float complex * preamble_pn; // p/n sequence // header unsigned char * header; // header data unsigned int header_user_len; // header user section length unsigned int header_dec_len; // header length (decoded) qpacketmodem header_encoder; // header encoder/modulator unsigned int header_mod_len; // header length (encoded/modulated) float complex * header_mod; // header symbols (encoded/modulated) qpilotgen header_pilotgen; // header pilot symbol generator unsigned int header_sym_len; // header length (pilots added) float complex * header_sym; // header symbols (pilots added) // payload unsigned int payload_dec_len; // length of decoded qpacketmodem payload_encoder; // packet encoder/modulator unsigned int payload_sym_len; // length of encoded/modulated payload float complex * payload_sym; // encoded payload symbols // counters/states unsigned int symbol_counter; // output symbol number unsigned int sample_counter; // output sample number int frame_assembled; // frame assembled flag int frame_complete; // frame completed flag enum { STATE_PREAMBLE=0, // write preamble p/n sequence STATE_HEADER, // write header symbols STATE_PAYLOAD, // write payload symbols STATE_TAIL, // tail symbols } state; // write state }; flexframegen flexframegen_create(flexframegenprops_s * _fgprops) { flexframegen q = (flexframegen) malloc(sizeof(struct flexframegen_s)); unsigned int i; // create pulse-shaping filter q->k = 2; q->m = 7; q->beta = 0.25f; q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,q->k,q->m,q->beta,0); // generate pn sequence q->preamble_pn = (float complex *) malloc(64*sizeof(float complex)); msequence ms = msequence_create(7, 0x0089, 1); for (i=0; i<64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } msequence_destroy(ms); // reset object flexframegen_reset(q); // create header encoder/modulator q->header = NULL; q->header_mod = NULL; q->header_sym = NULL; q->header_encoder = NULL; q->header_pilotgen = NULL; q->header_user_len = FLEXFRAME_H_USER_DEFAULT; // payload encoder/modulator (initialize with default parameters to be reconfigured later) q->payload_encoder = qpacketmodem_create(); q->payload_dec_len = 64; q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_encoder); q->payload_sym = (float complex *) malloc( q->payload_sym_len*sizeof(float complex)); // set payload properties flexframegen_setprops(q, _fgprops); flexframegen_set_header_props(q, NULL); // return pointer to main object return q; } int flexframegen_destroy(flexframegen _q) { // destroy internal objects firinterp_crcf_destroy(_q->interp); qpacketmodem_destroy (_q->header_encoder); qpilotgen_destroy (_q->header_pilotgen); qpacketmodem_destroy (_q->payload_encoder); // free buffers/arrays free(_q->preamble_pn); // preamble symbols free(_q->header); // header bytes free(_q->header_mod); // encoded/modulated header symbols free(_q->header_sym); free(_q->payload_sym); // encoded/modulated payload symbols // destroy frame generator free(_q); return LIQUID_OK; } // print flexframegen object internals int flexframegen_print(flexframegen _q) { printf("\n"); #if 0 unsigned int num_frame_symbols = 64 + // preamble p/n sequence length _q->header_sym_len + // header symbols _q->payload_sym_len + // number of modulation symbols 2*_q->m; // number of tail symbols unsigned int num_frame_bits = 8*_q->payload_dec_len; float eta = (float)num_frame_bits / (float)num_frame_symbols; printf("flexframegen:\n"); printf(" head : %u symbols\n", _q->m); printf(" preamble : %u\n", 64); printf(" header : %u symbols (%u bytes)\n", _q->header_sym_len, _q->header_dec_len); printf(" payload : %u symbols (%u bytes)\n", _q->payload_sym_len, _q->payload_dec_len); printf(" payload crc : %s\n", crc_scheme_str[_q->props.check][1]); printf(" fec (inner) : %s\n", fec_scheme_str[_q->props.fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->props.fec1][1]); printf(" mod scheme : %s\n", modulation_types[_q->props.mod_scheme].name); printf(" tail : %u symbols\n", _q->m); printf(" total : %u symbols\n", num_frame_symbols); printf(" efficiency : %.2f bits/second/Hz\n", eta); #endif return LIQUID_OK; } // reset flexframegen object internals int flexframegen_reset(flexframegen _q) { // reset internal counters and state _q->symbol_counter = 0; _q->sample_counter = 0; _q->frame_assembled = 0; _q->frame_complete = 0; _q->state = STATE_PREAMBLE; return LIQUID_OK; } // is frame assembled? int flexframegen_is_assembled(flexframegen _q) { return _q->frame_assembled; } // get flexframegen properties // _q : frame generator object // _props : frame generator properties structure pointer int flexframegen_getprops(flexframegen _q, flexframegenprops_s * _props) { // copy properties structure to output pointer memmove(_props, &_q->props, sizeof(flexframegenprops_s)); return LIQUID_OK; } // set flexframegen properties // _q : frame generator object // _props : frame generator properties structure pointer int flexframegen_setprops(flexframegen _q, flexframegenprops_s * _props) { // if frame is already assembled, give warning if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"flexframegen_setprops(), frame is already assembled; must reset() first"); // if properties object is NULL, initialize with defaults if (_props == NULL) return flexframegen_setprops(_q, &flexframegenprops_default); // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"flexframegen_setprops(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"flexframegen_setprops(), invalid/unsupported FEC scheme"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EICONFIG,"flexframegen_setprops(), invalid/unsupported modulation scheme"); // TODO : determine if re-configuration is necessary // copy properties to internal structure memmove(&_q->props, _props, sizeof(flexframegenprops_s)); // reconfigure payload buffers (reallocate as necessary) return flexframegen_reconfigure(_q); } int flexframegen_set_header_len(flexframegen _q, unsigned int _len) { // if frame is already assembled, give warning if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"flexframegen_setprops(), frame is already assembled; must reset() first"); _q->header_user_len = _len; _q->header_dec_len = FLEXFRAME_H_DEC + _q->header_user_len; _q->header = (unsigned char *) realloc(_q->header, _q->header_dec_len*sizeof(unsigned char)); if (_q->header_encoder) { qpacketmodem_destroy(_q->header_encoder); } _q->header_encoder = qpacketmodem_create(); qpacketmodem_configure(_q->header_encoder, _q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1, _q->header_props.mod_scheme); _q->header_mod_len = qpacketmodem_get_frame_len(_q->header_encoder); _q->header_mod = (float complex *) realloc(_q->header_mod, _q->header_mod_len*sizeof(float complex)); // create header pilot sequence generator if (_q->header_pilotgen) { qpilotgen_destroy(_q->header_pilotgen); } _q->header_pilotgen = qpilotgen_create(_q->header_mod_len, 16); _q->header_sym_len = qpilotgen_get_frame_len(_q->header_pilotgen); _q->header_sym = (float complex *) realloc(_q->header_sym, _q->header_sym_len*sizeof(float complex)); //printf("header: %u bytes > %u mod > %u sym\n", 64, _q->header_mod_len, _q->header_sym_len); return LIQUID_OK; } int flexframegen_set_header_props(flexframegen _q, flexframegenprops_s * _props) { // if frame is already assembled, give warning if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"flexframegen_set_header_props(), frame is already assembled; must reset() first"); if (_props == NULL) _props = &flexframegenprops_header_default; // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EIMODE,"flexframegen_set_header_props(), invalid/unsupported CRC scheme\n"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EIMODE,"flexframegen_set_header_props(), invalid/unsupported FEC scheme\n"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EIMODE,"flexframegen_set_header_props(), invalid/unsupported modulation scheme\n"); // copy properties to internal structure memmove(&_q->header_props, _props, sizeof(flexframegenprops_s)); // reconfigure payload buffers (reallocate as necessary) return flexframegen_set_header_len(_q, _q->header_user_len); } // get frame length (number of samples) unsigned int flexframegen_getframelen(flexframegen _q) { if (!_q->frame_assembled) { liquid_error(LIQUID_EICONFIG,"flexframegen_getframelen(), frame not assembled!"); return 0; } unsigned int num_frame_symbols = 64 + // preamble p/n sequence length _q->header_sym_len + // header symbols _q->payload_sym_len + // number of modulation symbols 2*_q->m; // number of tail symbols return num_frame_symbols*_q->k; // k samples/symbol } // exectue frame generator (create the frame) // _q : frame generator object // _header : user-defined header // _payload : variable payload buffer (configured by setprops method) // _payload_dec_len: length of payload int flexframegen_assemble(flexframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_dec_len) { // reset object flexframegen_reset(_q); // set decoded payload length _q->payload_dec_len = _payload_dec_len; // copy user-defined header to internal if (_header == NULL) memset(_q->header, 0x00, _q->header_user_len*sizeof(unsigned char)); else memmove(_q->header, _header, _q->header_user_len*sizeof(unsigned char)); // first several bytes of header are user-defined unsigned int n = _q->header_user_len; // add FLEXFRAME_PROTOCOL _q->header[n+0] = FLEXFRAME_PROTOCOL; // add payload length _q->header[n+1] = (_q->payload_dec_len >> 8) & 0xff; _q->header[n+2] = (_q->payload_dec_len ) & 0xff; // add modulation scheme/depth (pack into single byte) _q->header[n+3] = (unsigned int)(_q->props.mod_scheme); // add CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] _q->header[n+4] = (_q->props.check & 0x07) << 5; _q->header[n+4] |= (_q->props.fec0) & 0x1f; _q->header[n+5] = (_q->props.fec1) & 0x1f; // encode/modulate header qpacketmodem_encode(_q->header_encoder, _q->header, _q->header_mod); // add pilots qpilotgen_execute(_q->header_pilotgen, _q->header_mod, _q->header_sym); // reconfigure payload flexframegen_reconfigure(_q); // encode/modulate payload qpacketmodem_encode(_q->payload_encoder, _payload, _q->payload_sym); // set assembled flag _q->frame_assembled = 1; return LIQUID_OK; } // write samples of assembled frame, two samples at a time, returning // '1' when frame is complete, '0' otherwise. Zeros will be written // to the buffer if the frame is not assembled // _q : frame generator object // _buffer : output buffer [size: _buffer_len x 1] // _buffer_len : output buffer length int flexframegen_write_samples(flexframegen _q, float complex * _buffer, unsigned int _buffer_len) { unsigned int i; for (i=0; i<_buffer_len; i++) { // determine if new sample needs to be written if (_q->sample_counter == 0) { // generate new symbol float complex sym = flexframegen_generate_symbol(_q); // interpolate result firinterp_crcf_execute(_q->interp, sym, _q->buf_interp); } // write output sample from interpolator buffer _buffer[i] = _q->buf_interp[_q->sample_counter]; // adjust sample counter _q->sample_counter = (_q->sample_counter + 1) % _q->k; } return _q->frame_complete; } // // internal // // reconfigure internal buffers, objects, etc. int flexframegen_reconfigure(flexframegen _q) { // configure payload encoder/modulator qpacketmodem_configure(_q->payload_encoder, _q->payload_dec_len, _q->props.check, _q->props.fec0, _q->props.fec1, _q->props.mod_scheme); // re-allocate memory for encoded message _q->payload_sym_len = qpacketmodem_get_frame_len(_q->payload_encoder); _q->payload_sym = (float complex*) realloc(_q->payload_sym, _q->payload_sym_len*sizeof(float complex)); // ensure payload was reallocated appropriately if (_q->payload_sym == NULL) return liquid_error(LIQUID_EIMEM,"flexframegen_reconfigure(), could not re-allocate payload array"); return LIQUID_OK; } // fill interpolator buffer float complex flexframegen_generate_symbol(flexframegen _q) { // write zeros to buffer if frame is not assembled if (!_q->frame_assembled) return 0.0f; switch (_q->state) { case STATE_PREAMBLE: return flexframegen_generate_preamble(_q); case STATE_HEADER: return flexframegen_generate_header (_q); case STATE_PAYLOAD: return flexframegen_generate_payload (_q); case STATE_TAIL: return flexframegen_generate_tail (_q); default: liquid_error(LIQUID_EICONFIG,"flexframegen_generate_symbol(), unknown/unsupported internal state"); } return 0.0f; } // generate preamble float complex flexframegen_generate_preamble(flexframegen _q) { float complex symbol = _q->preamble_pn[_q->symbol_counter++]; // check state if (_q->symbol_counter == 64) { _q->symbol_counter = 0; _q->state = STATE_HEADER; } return symbol; } // generate header float complex flexframegen_generate_header(flexframegen _q) { float complex symbol = _q->header_sym[_q->symbol_counter++]; // check state if (_q->symbol_counter == _q->header_sym_len) { _q->symbol_counter = 0; _q->state = STATE_PAYLOAD; } return symbol; } // generate payload float complex flexframegen_generate_payload(flexframegen _q) { float complex symbol = _q->payload_sym[_q->symbol_counter++]; // check state if (_q->symbol_counter == _q->payload_sym_len) { _q->symbol_counter = 0; _q->state = STATE_TAIL; } return symbol; } // generate tail float complex flexframegen_generate_tail(flexframegen _q) { // increment symbol counter _q->symbol_counter++; // check state if (_q->symbol_counter == 2*_q->m) { _q->symbol_counter = 0; _q->frame_complete = 1; _q->frame_assembled = 0; } return 0.0f; } liquid-dsp-1.7.0/src/framing/src/flexframesync.c000066400000000000000000001062621474751757600216430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // flexframesync.c // // basic frame synchronizer // #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_FLEXFRAMESYNC 1 #define DEBUG_FLEXFRAMESYNC_PRINT 0 #define DEBUG_FILENAME "flexframesync_internal_debug.m" #define DEBUG_BUFFER_LEN (2000) #define FLEXFRAMESYNC_ENABLE_EQ 0 // push samples through detection stage int flexframesync_execute_seekpn(flexframesync _q, float complex _x); // step receiver mixer, matched filter, decimator // _q : frame synchronizer // _x : input sample // _y : output symbol int flexframesync_step(flexframesync _q, float complex _x, float complex * _y); // push samples through synchronizer, saving received p/n symbols int flexframesync_execute_rxpreamble(flexframesync _q, float complex _x); // decode header and reconfigure payload int flexframesync_decode_header(flexframesync _q); // receive header symbols int flexframesync_execute_rxheader(flexframesync _q, float complex _x); // receive payload symbols int flexframesync_execute_rxpayload(flexframesync _q, float complex _x); static flexframegenprops_s flexframesyncprops_header_default = { FLEXFRAME_H_CRC, FLEXFRAME_H_FEC0, FLEXFRAME_H_FEC1, FLEXFRAME_H_MOD, }; // flexframesync object structure struct flexframesync_s { // callback framesync_callback callback; // user-defined callback function void * userdata; // user-defined data structure framesyncstats_s framesyncstats; // frame statistic object (synchronizer) framedatastats_s framedatastats; // frame statistic object (packet statistics) // synchronizer objects unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor qdetector_cccf detector; // pre-demod detector float tau_hat; // fractional timing offset estimate float dphi_hat; // carrier frequency offset estimate float phi_hat; // carrier phase offset estimate float gamma_hat; // channel gain estimate nco_crcf mixer; // carrier frequency recovery (coarse) nco_crcf pll; // carrier frequency recovery (fine) // timing recovery objects, states firpfb_crcf mf; // matched filter decimator unsigned int npfb; // number of filters in symsync int mf_counter; // matched filter output timer unsigned int pfb_index; // filterbank index #if FLEXFRAMESYNC_ENABLE_EQ eqlms_cccf equalizer; // equalizer (trained on p/n sequence) #endif // preamble float complex * preamble_pn; // known 64-symbol p/n sequence float complex * preamble_rx; // received p/n symbols // header int header_soft; // header performs soft demod float complex * header_sym; // header symbols with pilots (received) unsigned int header_sym_len; // header symbols with pilots (length) qpilotsync header_pilotsync; // header demodulator/decoder float complex * header_mod; // header symbols (received) unsigned int header_mod_len; // header symbols (length) qpacketmodem header_decoder; // header demodulator/decoder unsigned int header_user_len; // length of user-defined array unsigned int header_dec_len; // length of header (decoded) unsigned char * header_dec; // header bytes (decoded) int header_valid; // header CRC flag flexframegenprops_s header_props; // header properties // payload int payload_soft; // payload performs soft demod modemcf payload_demod; // payload demod (for phase recovery only) float complex * payload_sym; // payload symbols (received) unsigned int payload_sym_len; // payload symbols (length) qpacketmodem payload_decoder; // payload demodulator/decoder unsigned char * payload_dec; // payload data (bytes) unsigned int payload_dec_len; // payload data (length) int payload_valid; // payload CRC flag // status variables unsigned int preamble_counter; // counter: num of p/n syms received unsigned int symbol_counter; // counter: num of symbols received enum { FLEXFRAMESYNC_STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) FLEXFRAMESYNC_STATE_RXPREAMBLE, // receive p/n sequence FLEXFRAMESYNC_STATE_RXHEADER, // receive header data FLEXFRAMESYNC_STATE_RXPAYLOAD, // receive payload data } state; // receiver state #if DEBUG_FLEXFRAMESYNC int debug_enabled; // debugging enabled? int debug_objects_created; // debugging objects created? int debug_qdetector_flush; // debug: flag to set if we are flushing detector windowcf debug_x; // debug: raw input samples #endif }; // create flexframesync object // _callback : callback function invoked when frame is received // _userdata : user-defined data object passed to callback flexframesync flexframesync_create(framesync_callback _callback, void * _userdata) { flexframesync q = (flexframesync) malloc(sizeof(struct flexframesync_s)); q->callback = _callback; q->userdata = _userdata; q->m = 7; // filter delay (symbols) q->beta = 0.3f; // excess bandwidth factor unsigned int i; // generate p/n sequence q->preamble_pn = (float complex*) malloc(64*sizeof(float complex)); q->preamble_rx = (float complex*) malloc(64*sizeof(float complex)); msequence ms = msequence_create(7, 0x0089, 1); for (i=0; i<64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2) * _Complex_I; } msequence_destroy(ms); // create frame detector unsigned int k = 2; // samples/symbol q->detector = qdetector_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, k, q->m, q->beta); qdetector_cccf_set_threshold(q->detector, 0.5f); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_crcf_create_rnyquist(LIQUID_FIRFILT_ARKAISER, q->npfb,k,q->m,q->beta); #if FLEXFRAMESYNC_ENABLE_EQ // create equalizer unsigned int p = 3; q->equalizer = eqlms_cccf_create_lowpass(2*k*p+1, 0.4f); eqlms_cccf_set_bw(q->equalizer, 0.05f); #endif // create down-coverters for carrier phase tracking q->mixer = nco_crcf_create(LIQUID_NCO); q->pll = nco_crcf_create(LIQUID_NCO); nco_crcf_pll_set_bandwidth(q->pll, 1e-4f); // very low bandwidth // header demodulator/decoder q->header_sym = NULL; q->header_mod = NULL; q->header_dec = NULL; q->header_pilotsync = NULL; q->header_decoder = NULL; q->header_user_len = FLEXFRAME_H_USER_DEFAULT; q->header_soft = 0; flexframesync_set_header_props(q, NULL); // payload demodulator for phase recovery q->payload_demod = modemcf_create(LIQUID_MODEM_QPSK); // create payload demodulator/decoder object q->payload_dec_len = 64; int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_BPSK; q->payload_decoder = qpacketmodem_create(); qpacketmodem_configure(q->payload_decoder, q->payload_dec_len, check, fec0, fec1, mod_scheme); //qpacketmodem_print(q->payload_decoder); //assert( qpacketmodem_get_frame_len(q->payload_decoder)==600 ); q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_decoder); // allocate memory for payload symbols and recovered data bytes q->payload_sym = (float complex*) malloc(q->payload_sym_len*sizeof(float complex)); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); q->payload_soft = 0; // reset global data counters flexframesync_reset_framedatastats(q); #if DEBUG_FLEXFRAMESYNC // set debugging flags, objects to NULL q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_qdetector_flush = 0; q->debug_x = NULL; #endif // reset state and return flexframesync_reset(q); return q; } // destroy frame synchronizer object, freeing all internal memory int flexframesync_destroy(flexframesync _q) { #if DEBUG_FLEXFRAMESYNC // clean up debug objects (if created) if (_q->debug_objects_created) windowcf_destroy(_q->debug_x); #endif // free allocated arrays free(_q->preamble_pn); free(_q->preamble_rx); free(_q->header_sym); free(_q->header_mod); free(_q->header_dec); free(_q->payload_sym); free(_q->payload_dec); // destroy synchronization objects qpilotsync_destroy (_q->header_pilotsync); // header demodulator/decoder qpacketmodem_destroy (_q->header_decoder); // header demodulator/decoder modemcf_destroy (_q->payload_demod); // payload demodulator (for PLL) qpacketmodem_destroy (_q->payload_decoder); // payload demodulator/decoder qdetector_cccf_destroy(_q->detector); // frame detector firpfb_crcf_destroy (_q->mf); // matched filter nco_crcf_destroy (_q->mixer); // oscillator (coarse) nco_crcf_destroy (_q->pll); // oscillator (fine) #if FLEXFRAMESYNC_ENABLE_EQ eqlms_cccf_destroy (_q->equalizer); // LMS equalizer #endif // free main object memory free(_q); return LIQUID_OK; } // print frame synchronizer object internals int flexframesync_print(flexframesync _q) { printf("\n"); return LIQUID_OK; } // reset frame synchronizer object int flexframesync_reset(flexframesync _q) { // reset binary pre-demod synchronizer qdetector_cccf_reset(_q->detector); // reset carrier recovery objects nco_crcf_reset(_q->mixer); nco_crcf_reset(_q->pll); // reset symbol timing recovery state firpfb_crcf_reset(_q->mf); // reset state _q->state = FLEXFRAMESYNC_STATE_DETECTFRAME; _q->preamble_counter= 0; _q->symbol_counter = 0; // reset frame statistics _q->framesyncstats.evm = 0.0f; return LIQUID_OK; } int flexframesync_is_frame_open(flexframesync _q) { return (_q->state == FLEXFRAMESYNC_STATE_DETECTFRAME) ? 0 : 1; } int flexframesync_set_header_len(flexframesync _q, unsigned int _len) { _q->header_user_len = _len; _q->header_dec_len = FLEXFRAME_H_DEC + _q->header_user_len; _q->header_dec = (unsigned char *) realloc(_q->header_dec, _q->header_dec_len*sizeof(unsigned char)); if (_q->header_decoder) { qpacketmodem_destroy(_q->header_decoder); } _q->header_decoder = qpacketmodem_create(); qpacketmodem_configure(_q->header_decoder, _q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1, _q->header_props.mod_scheme); _q->header_mod_len = qpacketmodem_get_frame_len(_q->header_decoder); _q->header_mod = (float complex*) realloc(_q->header_mod, _q->header_mod_len*sizeof(float complex)); // header pilot synchronizer if (_q->header_pilotsync) { qpilotsync_destroy(_q->header_pilotsync); } _q->header_pilotsync = qpilotsync_create(_q->header_mod_len, 16); _q->header_sym_len = qpilotsync_get_frame_len(_q->header_pilotsync); _q->header_sym = (float complex*) realloc(_q->header_sym, _q->header_sym_len*sizeof(float complex)); return LIQUID_OK; } int flexframesync_decode_header_soft(flexframesync _q, int _soft) { _q->header_soft = _soft; return LIQUID_OK; } int flexframesync_decode_payload_soft(flexframesync _q, int _soft) { _q->payload_soft = _soft; return LIQUID_OK; } int flexframesync_set_header_props(flexframesync _q, flexframegenprops_s * _props) { if (_props == NULL) _props = &flexframesyncprops_header_default; // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"flexframesync_set_header_props(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"flexframesync_set_header_props(), invalid/unsupported FEC scheme"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EICONFIG,"flexframesync_set_header_props(), invalid/unsupported modulation scheme"); // copy properties to internal structure memmove(&_q->header_props, _props, sizeof(flexframegenprops_s)); // reconfigure payload buffers (reallocate as necessary) return flexframesync_set_header_len(_q, _q->header_user_len); } // execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples int flexframesync_execute(flexframesync _q, float complex * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { #if DEBUG_FLEXFRAMESYNC // write samples to debug buffer // NOTE: the debug_qdetector_flush prevents samples from being written twice if (_q->debug_enabled && !_q->debug_qdetector_flush) windowcf_push(_q->debug_x, _x[i]); #endif switch (_q->state) { case FLEXFRAMESYNC_STATE_DETECTFRAME: // detect frame (look for p/n sequence) flexframesync_execute_seekpn(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXPREAMBLE: // receive p/n sequence symbols flexframesync_execute_rxpreamble(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXHEADER: // receive header symbols flexframesync_execute_rxheader(_q, _x[i]); break; case FLEXFRAMESYNC_STATE_RXPAYLOAD: // receive payload symbols flexframesync_execute_rxpayload(_q, _x[i]); break; default: return liquid_error(LIQUID_EINT,"flexframesync_exeucte(), unknown/unsupported internal state"); } } return LIQUID_OK; } // // internal methods // // execute synchronizer, seeking p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int flexframesync_execute_seekpn(flexframesync _q, float complex _x) { // push through pre-demod synchronizer float complex * v = qdetector_cccf_execute(_q->detector, _x); // check if frame has been detected if (v == NULL) return LIQUID_OK; // get estimates _q->tau_hat = qdetector_cccf_get_tau (_q->detector); _q->gamma_hat = qdetector_cccf_get_gamma(_q->detector); _q->dphi_hat = qdetector_cccf_get_dphi (_q->detector); _q->phi_hat = qdetector_cccf_get_phi (_q->detector); #if DEBUG_FLEXFRAMESYNC_PRINT printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); #endif // set appropriate filterbank index if (_q->tau_hat > 0) { _q->pfb_index = (unsigned int)( _q->tau_hat * _q->npfb) % _q->npfb; _q->mf_counter = 0; } else { _q->pfb_index = (unsigned int)((1.0f+_q->tau_hat) * _q->npfb) % _q->npfb; _q->mf_counter = 1; } // output filter scale (gain estimate, scaled by 1/2 for k=2 samples/symbol) firpfb_crcf_set_scale(_q->mf, 0.5f / _q->gamma_hat); // set frequency/phase of mixer nco_crcf_set_frequency(_q->mixer, _q->dphi_hat); nco_crcf_set_phase (_q->mixer, _q->phi_hat ); // update state _q->state = FLEXFRAMESYNC_STATE_RXPREAMBLE; #if DEBUG_FLEXFRAMESYNC // the debug_qdetector_flush prevents samples from being written twice _q->debug_qdetector_flush = 1; #endif // run buffered samples through synchronizer unsigned int buf_len = qdetector_cccf_get_buf_len(_q->detector); flexframesync_execute(_q, v, buf_len); #if DEBUG_FLEXFRAMESYNC _q->debug_qdetector_flush = 0; #endif return LIQUID_OK; } // step receiver mixer, matched filter, decimator // _q : frame synchronizer // _x : input sample // _y : output symbol int flexframesync_step(flexframesync _q, float complex _x, float complex * _y) { // mix sample down float complex v; nco_crcf_mix_down(_q->mixer, _x, &v); nco_crcf_step (_q->mixer); // push sample into filterbank firpfb_crcf_push (_q->mf, v); firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); #if FLEXFRAMESYNC_ENABLE_EQ // push sample through equalizer eqlms_cccf_push(_q->equalizer, v); #endif // increment counter to determine if sample is available _q->mf_counter++; int sample_available = (_q->mf_counter >= 1) ? 1 : 0; // set output sample if available if (sample_available) { #if FLEXFRAMESYNC_ENABLE_EQ // compute equalizer output eqlms_cccf_execute(_q->equalizer, &v); #endif // set output *_y = v; // decrement counter by k=2 samples/symbol _q->mf_counter -= 2; } // return flag return sample_available; } // execute synchronizer, receiving p/n sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int flexframesync_execute_rxpreamble(flexframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_step(_q, _x, &mf_out); // compute output if timeout if (sample_available) { // save output in p/n symbols buffer #if FLEXFRAMESYNC_ENABLE_EQ unsigned int delay = 2*_q->m + 3; // delay from matched filter and equalizer #else unsigned int delay = 2*_q->m; // delay from matched filter #endif if (_q->preamble_counter >= delay) { unsigned int index = _q->preamble_counter-delay; _q->preamble_rx[index] = mf_out; #if FLEXFRAMESYNC_ENABLE_EQ // train equalizer eqlms_cccf_step(_q->equalizer, _q->preamble_pn[index], mf_out); #endif } // update p/n counter _q->preamble_counter++; // update state if (_q->preamble_counter == 64 + delay) _q->state = FLEXFRAMESYNC_STATE_RXHEADER; } return LIQUID_OK; } // execute synchronizer, receiving header // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int flexframesync_execute_rxheader(flexframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_step(_q, _x, &mf_out); // compute output if timeout if (sample_available) { // save payload symbols (modem input/output) _q->header_sym[_q->symbol_counter] = mf_out; // increment counter _q->symbol_counter++; if (_q->symbol_counter == _q->header_sym_len) { // decode header flexframesync_decode_header(_q); if (_q->header_valid) { // continue on to decoding payload _q->symbol_counter = 0; _q->state = FLEXFRAMESYNC_STATE_RXPAYLOAD; return LIQUID_OK; } // update statistics _q->framedatastats.num_frames_detected++; // header invalid: invoke callback if (_q->callback != NULL) { // set framestats internals _q->framesyncstats.evm = 0.0f; //20*log10f(sqrtf(_q->framesyncstats.evm / 600)); _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framesyncstats.mod_bps = 0; _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; // invoke callback method _q->callback(_q->header_dec, _q->header_valid, NULL, // payload 0, // payload length 0, // payload valid, _q->framesyncstats, _q->userdata); } // reset frame synchronizer return flexframesync_reset(_q); } } return LIQUID_OK; } // decode header int flexframesync_decode_header(flexframesync _q) { // recover data symbols from pilots qpilotsync_execute(_q->header_pilotsync, _q->header_sym, _q->header_mod); // decode payload if (_q->header_soft) { _q->header_valid = qpacketmodem_decode_soft(_q->header_decoder, _q->header_mod, _q->header_dec); } else { _q->header_valid = qpacketmodem_decode(_q->header_decoder, _q->header_mod, _q->header_dec); } if (!_q->header_valid) return LIQUID_OK; // set fine carrier frequency and phase float dphi_hat = qpilotsync_get_dphi(_q->header_pilotsync); float phi_hat = qpilotsync_get_phi (_q->header_pilotsync); //printf("residual offset: dphi=%12.8f, phi=%12.8f\n", dphi_hat, phi_hat); nco_crcf_set_frequency(_q->pll, dphi_hat); nco_crcf_set_phase (_q->pll, phi_hat + dphi_hat * _q->header_sym_len); // first several bytes of header are user-defined unsigned int n = _q->header_user_len; // first byte is for expansion/version validation unsigned int protocol = _q->header_dec[n+0]; if (protocol != FLEXFRAME_PROTOCOL) { _q->header_valid = 0; return liquid_error(LIQUID_EICONFIG,"flexframesync_decode_header(), invalid framing protocol %u (expected %u)", protocol, FLEXFRAME_PROTOCOL); } // strip off payload length unsigned int payload_dec_len = (_q->header_dec[n+1] << 8) | (_q->header_dec[n+2]); _q->payload_dec_len = payload_dec_len; // strip off modulation scheme/depth unsigned int mod_scheme = _q->header_dec[n+3]; // strip off CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] unsigned int check = (_q->header_dec[n+4] >> 5 ) & 0x07; unsigned int fec0 = (_q->header_dec[n+4] ) & 0x1f; unsigned int fec1 = (_q->header_dec[n+5] ) & 0x1f; // validate properties if (mod_scheme == 0 || mod_scheme >= LIQUID_MODEM_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EICONFIG,"flexframesync_decode_header(), invalid modulation scheme"); } else if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EICONFIG,"flexframesync_decode_header(), decoded CRC exceeds available"); } else if (fec0 == LIQUID_FEC_UNKNOWN || fec0 >= LIQUID_FEC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EICONFIG,"flexframesync_decode_header(), decoded FEC (inner) exceeds available"); } else if (fec1 == LIQUID_FEC_UNKNOWN || fec1 >= LIQUID_FEC_NUM_SCHEMES) { _q->header_valid = 0; return liquid_error(LIQUID_EICONFIG,"flexframesync_decode_header(), decoded FEC (outer) exceeds available"); } // re-create payload demodulator for phase-locked loop _q->payload_demod = modemcf_recreate(_q->payload_demod, mod_scheme); // reconfigure payload demodulator/decoder qpacketmodem_configure(_q->payload_decoder, payload_dec_len, check, fec0, fec1, mod_scheme); // set length appropriately _q->payload_sym_len = qpacketmodem_get_frame_len(_q->payload_decoder); // re-allocate buffers accordingly _q->payload_sym = (float complex*) realloc(_q->payload_sym, (_q->payload_sym_len)*sizeof(float complex)); _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, (_q->payload_dec_len)*sizeof(unsigned char)); if (_q->payload_sym == NULL || _q->payload_dec == NULL) { _q->header_valid = 0; return liquid_error(LIQUID_EIMEM,"flexframesync_decode_header(), could not re-allocate payload arrays"); } #if DEBUG_FLEXFRAMESYNC_PRINT // print results printf("flexframesync_decode_header():\n"); printf(" header crc : %s\n", _q->header_valid ? "pass" : "FAIL"); printf(" check : %s\n", crc_scheme_str[check][1]); printf(" fec (inner) : %s\n", fec_scheme_str[fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[fec1][1]); printf(" mod scheme : %s\n", modulation_types[mod_scheme].name); printf(" payload sym len : %u\n", _q->payload_sym_len); printf(" payload dec len : %u\n", _q->payload_dec_len); printf(" user data :"); unsigned int i; for (i=0; i<_q->header_user_len; i++) printf(" %.2x", _q->header_dec[i]); printf("\n"); #endif return LIQUID_OK; } // execute synchronizer, receiving payload // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int flexframesync_execute_rxpayload(flexframesync _q, float complex _x) { // step synchronizer float complex mf_out = 0.0f; int sample_available = flexframesync_step(_q, _x, &mf_out); // compute output if timeout if (sample_available) { // TODO: clean this up // mix down with fine-tuned oscillator nco_crcf_mix_down(_q->pll, mf_out, &mf_out); // track phase, accumulate error-vector magnitude unsigned int sym; modemcf_demodulate(_q->payload_demod, mf_out, &sym); float phase_error = modemcf_get_demodulator_phase_error(_q->payload_demod); float evm = modemcf_get_demodulator_evm (_q->payload_demod); nco_crcf_pll_step(_q->pll, phase_error); nco_crcf_step(_q->pll); _q->framesyncstats.evm += evm*evm; // save payload symbols (modem input/output) _q->payload_sym[_q->symbol_counter] = mf_out; // increment counter _q->symbol_counter++; if (_q->symbol_counter == _q->payload_sym_len) { // decode payload if (_q->payload_soft) { _q->payload_valid = qpacketmodem_decode_soft(_q->payload_decoder, _q->payload_sym, _q->payload_dec); } else { _q->payload_valid = qpacketmodem_decode(_q->payload_decoder, _q->payload_sym, _q->payload_dec); } // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid++; if (_q->payload_valid) { _q->framedatastats.num_payloads_valid += 1; _q->framedatastats.num_bytes_received += _q->payload_dec_len; } // invoke callback if (_q->callback != NULL) { // set framestats internals int ms = qpacketmodem_get_modscheme(_q->payload_decoder); _q->framesyncstats.evm = 10*log10f(_q->framesyncstats.evm / (float)_q->payload_sym_len); _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.cfo = nco_crcf_get_frequency(_q->mixer); _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = _q->payload_sym_len; _q->framesyncstats.mod_scheme = ms; _q->framesyncstats.mod_bps = modulation_types[ms].bps; _q->framesyncstats.check = qpacketmodem_get_crc(_q->payload_decoder); _q->framesyncstats.fec0 = qpacketmodem_get_fec0(_q->payload_decoder); _q->framesyncstats.fec1 = qpacketmodem_get_fec1(_q->payload_decoder); // invoke callback method _q->callback(_q->header_dec, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framesyncstats, _q->userdata); } // reset frame synchronizer return flexframesync_reset(_q); } } return LIQUID_OK; } // reset frame data statistics int flexframesync_reset_framedatastats(flexframesync _q) { return framedatastats_reset(&_q->framedatastats); } // retrieve frame data statistics framedatastats_s flexframesync_get_framedatastats(flexframesync _q) { return _q->framedatastats; } // enable debugging int flexframesync_debug_enable(flexframesync _q) { // create debugging objects if necessary #if DEBUG_FLEXFRAMESYNC if (_q->debug_objects_created) return LIQUID_OK; // create debugging objects _q->debug_x = windowcf_create(DEBUG_BUFFER_LEN); // set debugging flags _q->debug_enabled = 1; _q->debug_objects_created = 1; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"flexframesync_debug_enable(): compile-time debugging disabled"); #endif } // disable debugging int flexframesync_debug_disable(flexframesync _q) { // disable debugging #if DEBUG_FLEXFRAMESYNC _q->debug_enabled = 0; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"flexframesync_debug_enable(): compile-time debugging disabled"); #endif } // print debugging information int flexframesync_debug_print(flexframesync _q, const char * _filename) { #if DEBUG_FLEXFRAMESYNC if (!_q->debug_objects_created) return liquid_error(LIQUID_EICONFIG,"flexframesync_debug_print(), debugging objects don't exist; enable debugging first"); unsigned int i; float complex * rc; FILE* fid = fopen(_filename,"w"); if (fid==NULL) return liquid_error(LIQUID_EIO,"flexframesync_debug_print(), could not open '%s' for writing", _filename); fprintf(fid,"%% %s: auto-generated file", _filename); fprintf(fid,"\n\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); // main figure fprintf(fid,"figure('Color','white','position',[100 100 800 600]);\n"); // write x fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; ipreamble_pn; for (i=0; i<64; i++) fprintf(fid,"preamble_pn(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write p/n symbols fprintf(fid,"preamble_rx = zeros(1,64);\n"); rc = _q->preamble_rx; for (i=0; i<64; i++) fprintf(fid,"preamble_rx(%4u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write recovered header symbols (after qpilotsync) fprintf(fid,"header_mod = zeros(1,%u);\n", _q->header_mod_len); rc = _q->header_mod; for (i=0; i<_q->header_mod_len; i++) fprintf(fid,"header_mod(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); // write raw payload symbols fprintf(fid,"payload_sym = zeros(1,%u);\n", _q->payload_sym_len); rc = _q->payload_sym; for (i=0; i<_q->payload_sym_len; i++) fprintf(fid,"payload_sym(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(rc[i]), cimagf(rc[i])); fprintf(fid,"subplot(3,2,[3 5]);\n"); fprintf(fid,"plot(real(header_mod),imag(header_mod),'o');\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"title('Received Header Symbols');\n"); fprintf(fid,"subplot(3,2,[4 6]);\n"); fprintf(fid,"plot(real(payload_sym),imag(payload_sym),'+');\n"); fprintf(fid,"xlabel('in-phase');\n"); fprintf(fid,"ylabel('quadrature phase');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-1 1 -1 1]*1.5);\n"); fprintf(fid,"axis square;\n"); fprintf(fid,"title('Received Payload Symbols');\n"); fprintf(fid,"\n\n"); fclose(fid); printf("flexframesync/debug: results written to %s\n", _filename); #else return liquid_error(LIQUID_EICONFIG,"flexframesync_debug_print(): compile-time debugging disabled"); #endif return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/framedatastats.c000066400000000000000000000046501474751757600217760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // framedatastats.c // // Default and generic frame statistics // #include #include #include #include #include #include "liquid.internal.h" // reset framedatastats object int framedatastats_reset(framedatastats_s * _stats) { if (_stats == NULL) return LIQUID_OK; _stats->num_frames_detected = 0; _stats->num_headers_valid = 0; _stats->num_payloads_valid = 0; _stats->num_bytes_received = 0; return LIQUID_OK; } // print framedatastats object int framedatastats_print(framedatastats_s * _stats) { if (_stats == NULL) return LIQUID_OK; float percent_headers = 0.0f; float percent_payloads = 0.0f; if (_stats->num_frames_detected > 0) { percent_headers = 100.0f*(float)_stats->num_headers_valid / (float)_stats->num_frames_detected; percent_payloads = 100.0f*(float)_stats->num_payloads_valid / (float)_stats->num_frames_detected; } printf(" frames detected : %u\n", _stats->num_frames_detected); printf(" headers valid : %-6u (%8.4f %%)\n", _stats->num_headers_valid, percent_headers); printf(" payloads valid : %-6u (%8.4f %%)\n", _stats->num_payloads_valid, percent_payloads); printf(" bytes received : %lu\n", _stats->num_bytes_received); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/framegen64.c000066400000000000000000000151351474751757600207310ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // framegen64.c // // frame64 generator: 8-byte header, 64-byte payload, 1340-sample frame // #include #include #include #include #include #include #include "liquid.internal.h" struct framegen64_s { qpacketmodem enc; // packet encoder/modulator qpilotgen pilotgen; // pilot symbol generator float complex pn_sequence[64]; // 64-symbol p/n sequence unsigned char payload_dec[150]; // 600 = 150 bytes * 8 bits/bytes / 2 bits/symbol float complex payload_sym[600]; // modulated payload symbols float complex payload_tx[630]; // modulated payload symbols with pilots unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor firinterp_crcf interp; // pulse-shaping filter/interpolator }; // create framegen64 object framegen64 framegen64_create() { framegen64 q = (framegen64) malloc(sizeof(struct framegen64_s)); q->m = 7; q->beta = 0.3f; unsigned int i; // generate pn sequence msequence ms = msequence_create(7, 0x0089, 1); for (i=0; i<64; i++) { q->pn_sequence[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->pn_sequence[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } msequence_destroy(ms); // create payload encoder/modulator object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_QPSK; q->enc = qpacketmodem_create(); qpacketmodem_configure(q->enc, 72, check, fec0, fec1, mod_scheme); //qpacketmodem_print(q->enc); assert( qpacketmodem_get_frame_len(q->enc)==600 ); // create pilot generator q->pilotgen = qpilotgen_create(600, 21); assert( qpilotgen_get_frame_len(q->pilotgen)==630 ); // create pulse-shaping filter (k=2) q->interp = firinterp_crcf_create_prototype(LIQUID_FIRFILT_ARKAISER,2,q->m,q->beta,0); // return main object return q; } // copy object framegen64 framegen64_copy(framegen64 q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("framegen64_copy(), object cannot be NULL"); // as this object is stateless, we can really create a new one return framegen64_create(); } // destroy framegen64 object int framegen64_destroy(framegen64 _q) { // destroy internal objects qpacketmodem_destroy(_q->enc); qpilotgen_destroy(_q->pilotgen); firinterp_crcf_destroy(_q->interp); // free main object memory free(_q); return LIQUID_OK; } // print framegen64 object internals int framegen64_print(framegen64 _q) { #if 0 float eta = (float) (8*(64 + 8)) / (float) (LIQUID_FRAME64_LEN/2); printf("framegen64 [m=%u, beta=%4.2f]:\n", _q->m, _q->beta); printf(" preamble/etc.\n"); printf(" * ramp/up symbols : %3u\n", _q->m); printf(" * p/n symbols : %3u\n", 64); printf(" * ramp\\down symbols : %3u\n", _q->m); printf(" * zero padding : %3u\n", 12); printf(" payload\n"); #if 0 printf(" * payload crc : %s\n", crc_scheme_str[_q->check][1]); printf(" * fec (inner) : %s\n", fec_scheme_str[_q->fec0][1]); printf(" * fec (outer) : %s\n", fec_scheme_str[_q->fec1][1]); #endif printf(" * payload len, uncoded : %3u bytes\n", 64); printf(" * payload len, coded : %3u bytes\n", 150); printf(" * modulation scheme : %s\n", modulation_types[LIQUID_MODEM_QPSK].name); printf(" * payload symbols : %3u\n", 600); printf(" * pilot symbols : %3u\n", 30); printf(" summary\n"); printf(" * total symbols : %3u\n", LIQUID_FRAME64_LEN/2); printf(" * spectral efficiency : %6.4f b/s/Hz\n", eta); #else printf("\n", _q->m, _q->beta); #endif return LIQUID_OK; } // execute frame generator (creates a frame) // _q : frame generator object // _header : 8-byte header data, NULL for random // _payload : 64-byte payload data, NULL for random // _frame : output frame samples [size: LIQUID_FRAME64_LEN x 1] int framegen64_execute(framegen64 _q, unsigned char * _header, unsigned char * _payload, float complex * _frame) { unsigned int i; // concatenate header and payload for (i=0; i<8; i++) _q->payload_dec[i] = _header==NULL ? rand() & 0xff : _header[i]; for (i=0; i<64; i++) _q->payload_dec[i+8] = _payload==NULL ? rand() & 0xff : _payload[i]; // run packet encoder and modulator qpacketmodem_encode(_q->enc, _q->payload_dec, _q->payload_sym); // add pilot symbols qpilotgen_execute(_q->pilotgen, _q->payload_sym, _q->payload_tx); unsigned int n=0; // reset interpolator firinterp_crcf_reset(_q->interp); // p/n sequence for (i=0; i<64; i++) { firinterp_crcf_execute(_q->interp, _q->pn_sequence[i], &_frame[n]); n+=2; } // frame payload for (i=0; i<630; i++) { firinterp_crcf_execute(_q->interp, _q->payload_tx[i], &_frame[n]); n+=2; } // interpolator settling for (i=0; i<2*_q->m + 2 + 10; i++) { firinterp_crcf_execute(_q->interp, 0.0f, &_frame[n]); n+=2; } assert(n==LIQUID_FRAME64_LEN); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/framesync64.c000066400000000000000000000352721474751757600211400ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // basic frame synchronizer with 8 bytes header and 64 bytes payload #include #include #include #include #include #include #include "liquid.internal.h" // synchronization callback, return 0:continue, 1:reset int framesync64_callback_internal(float complex * _buf, unsigned int _buf_len, void * _context); // export debugging based on return value // 0 : do not write file // >0 : write specific number (hex) // -1 : number of packets detected // -2 : id using first 4 bytes of header // -3 : write with random extension int framesync64_debug_export(framesync64 _q, int _code, float complex * _payload_rx); // framesync64 object structure struct framesync64_s { // callback framesync_callback callback; // user-defined callback function void * userdata; // user-defined data structure framesyncstats_s framesyncstats; // frame statistic object (synchronizer) framedatastats_s framedatastats; // frame statistic object (packet statistics) // synchronizer objects unsigned int m; // filter delay (symbols) float beta; // filter excess bandwidth factor qdsync_cccf sync; // sequence detector // preamble float complex preamble_pn[64]; // known 64-symbol p/n sequence float complex preamble_rx[64]; // received p/n symbols // payload decoder float complex payload_sym[600]; // received payload symbols unsigned char payload_dec[ 72]; // decoded payload bytes qpacketmodem dec; // packet demodulator/decoder qpilotsync pilotsync; // pilot extraction, carrier recovery int payload_valid; // did payload pass crc? windowcf buf_debug; // debug: raw input samples char * prefix; // debug: filename prefix char * filename; // debug: filename buffer unsigned int num_files_exported; // debug: number of files exported }; // create framesync64 object // _callback : callback function invoked when frame is received // _userdata : user-defined data object passed to callback framesync64 framesync64_create(framesync_callback _callback, void * _userdata) { framesync64 q = (framesync64) malloc(sizeof(struct framesync64_s)); q->callback = _callback; q->userdata = _userdata; q->m = 7; // filter delay (symbols) q->beta = 0.3f; // excess bandwidth factor unsigned int i; // generate p/n sequence msequence ms = msequence_create(7, 0x0089, 1); for (i=0; i<64; i++) { q->preamble_pn[i] = (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2); q->preamble_pn[i] += (msequence_advance(ms) ? M_SQRT1_2 : -M_SQRT1_2)*_Complex_I; } msequence_destroy(ms); // create frame detector with callback to run frame sync in one step q->sync = qdsync_cccf_create_linear(q->preamble_pn, 64, LIQUID_FIRFILT_ARKAISER, 2, q->m, q->beta, framesync64_callback_internal, q); qdsync_cccf_set_buf_len(q->sync, 64 + 630); // create payload demodulator/decoder object int check = LIQUID_CRC_24; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_GOLAY2412; int mod_scheme = LIQUID_MODEM_QPSK; q->dec = qpacketmodem_create(); qpacketmodem_configure(q->dec, 72, check, fec0, fec1, mod_scheme); assert( qpacketmodem_get_frame_len(q->dec)==600 ); // create pilot synchronizer q->pilotsync = qpilotsync_create(600, 21); assert( qpilotsync_get_frame_len(q->pilotsync)==630); // reset global data counters framesync64_reset_framedatastats(q); // set debugging fields q->buf_debug= windowcf_create(LIQUID_FRAME64_LEN); q->prefix = NULL; q->filename = NULL; q->num_files_exported = 0; framesync64_set_prefix(q, "framesync64"); // reset state and return framesync64_reset(q); return q; } // copy object framesync64 framesync64_copy(framesync64 q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("framesync64_copy(), object cannot be NULL"); // allocate memory for new object framesync64 q_copy = (framesync64) malloc(sizeof(struct framesync64_s)); // copy entire memory space over and overwrite values as needed memmove(q_copy, q_orig, sizeof(struct framesync64_s)); // set callback and userdata fields //q_copy->callback = q_orig->callback; //q_copy->userdata = q_orig->userdata; // copy objects q_copy->sync = qdsync_cccf_copy (q_orig->sync); q_copy->dec = qpacketmodem_copy(q_orig->dec); q_copy->pilotsync= qpilotsync_copy (q_orig->pilotsync); q_copy->buf_debug= windowcf_copy (q_orig->buf_debug); // set prefix value q_copy->prefix = NULL; q_copy->filename = NULL; framesync64_set_prefix(q_copy, q_orig->prefix); // update the context for the sync object to that detected frames will // apply to this new frame synchronizer object qdsync_cccf_set_context(q_copy->sync, q_copy); return q_copy; } // destroy frame synchronizer object, freeing all internal memory int framesync64_destroy(framesync64 _q) { // destroy synchronization objects qdsync_cccf_destroy (_q->sync); // frame detector/synchronizer qpacketmodem_destroy(_q->dec); // payload demodulator qpilotsync_destroy (_q->pilotsync); // pilot synchronizer windowcf_destroy (_q->buf_debug); // free allocated buffers free(_q->prefix); free(_q->filename); // free main object memory free(_q); return LIQUID_OK; } // print frame synchronizer object internals int framesync64_print(framesync64 _q) { printf("\n"); return LIQUID_OK; } // reset frame synchronizer object int framesync64_reset(framesync64 _q) { // reset synchronizer qdsync_cccf_reset(_q->sync); return LIQUID_OK; } // set the callback function int framesync64_set_callback(framesync64 _q, framesync_callback _callback) { _q->callback = _callback; return LIQUID_OK; } // set the user-defined data field (context) int framesync64_set_userdata(framesync64 _q, void * _userdata) { _q->userdata = _userdata; return LIQUID_OK; } // execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples int framesync64_execute(framesync64 _q, float complex * _x, unsigned int _n) { return qdsync_cccf_execute(_q->sync, _x, _n); } // // internal methods // // synchronization callback, return 0:continue, 1:reset int framesync64_callback_internal(float complex * _buf, unsigned int _buf_len, void * _context) { // type cast context input as frame synchronizer object framesync64 _q = (framesync64)_context; // recover data symbols from pilots (input buffer with 64-symbol preamble offset) qpilotsync_execute(_q->pilotsync, _buf + 64, _q->payload_sym); // decode payload _q->payload_valid = qpacketmodem_decode(_q->dec, _q->payload_sym, _q->payload_dec); // update statistics _q->framedatastats.num_frames_detected++; _q->framedatastats.num_headers_valid += _q->payload_valid; _q->framedatastats.num_payloads_valid += _q->payload_valid; _q->framedatastats.num_bytes_received += _q->payload_valid ? 64 : 0; // set framesyncstats internals _q->framesyncstats.evm = qpacketmodem_get_demodulator_evm(_q->dec); _q->framesyncstats.rssi = 20*log10f( qdsync_cccf_get_gamma(_q->sync) ); _q->framesyncstats.cfo = qdsync_cccf_get_dphi(_q->sync) + qpilotsync_get_dphi(_q->pilotsync) / 2.0f; _q->framesyncstats.framesyms = _q->payload_sym; _q->framesyncstats.num_framesyms = 600; _q->framesyncstats.mod_scheme = LIQUID_MODEM_QPSK; _q->framesyncstats.mod_bps = 2; _q->framesyncstats.check = LIQUID_CRC_24; _q->framesyncstats.fec0 = LIQUID_FEC_NONE; _q->framesyncstats.fec1 = LIQUID_FEC_GOLAY2412; // invoke callback if (_q->callback != NULL) { int rc = _q->callback(&_q->payload_dec[0], // header is first 8 bytes _q->payload_valid, &_q->payload_dec[8], // payload is last 64 bytes 64, _q->payload_valid, _q->framesyncstats, _q->userdata); // export debugging based on return value framesync64_debug_export(_q, rc, _buf+64); } // reset frame synchronizer return framesync64_reset(_q); } // DEPRECATED: enable debugging int framesync64_debug_enable(framesync64 _q) { return LIQUID_OK; } // DEPRECATED: disable debugging int framesync64_debug_disable(framesync64 _q) { return LIQUID_OK; } // DEPRECATED: print debugging information int framesync64_debug_print(framesync64 _q, const char * _filename) { return LIQUID_OK; } // get detection threshold float framesync64_get_threshold(framesync64 _q) { return qdsync_cccf_get_threshold(_q->sync); } // set detection threshold int framesync64_set_threshold(framesync64 _q, float _threshold) { return qdsync_cccf_set_threshold(_q->sync, _threshold); } // set prefix for exporting debugging files, default: "framesync64" // _q : frame sync object // _prefix : string with valid file path int framesync64_set_prefix(framesync64 _q, const char * _prefix) { // skip if input is NULL pointer if (_prefix == NULL) return LIQUID_OK; // sanity check unsigned int n = strlen(_prefix); if (n > 1<<14) return liquid_error(LIQUID_EICONFIG,"framesync64_set_prefix(), input string size exceeds reasonable limits"); // reallocate memory, copy input, and return _q->prefix = (char*) realloc(_q->prefix, n+ 1); _q->filename = (char*) realloc(_q->filename, n+15); memmove(_q->prefix, _prefix, n); _q->prefix[n] = '\0'; return LIQUID_OK; } // get prefix for exporting debugging files const char * framesync64_get_prefix(framesync64 _q) { return (const char*) _q->prefix; } // get number of files exported unsigned int framesync64_get_num_files_exported(framesync64 _q) { return _q->num_files_exported; } // get name of last debugging file written const char * framesync64_get_filename(framesync64 _q) { return _q->num_files_exported == 0 ? NULL : (const char*) _q->filename; } // reset frame data statistics int framesync64_reset_framedatastats(framesync64 _q) { return framedatastats_reset(&_q->framedatastats); } // retrieve frame data statistics framedatastats_s framesync64_get_framedatastats(framesync64 _q) { return _q->framedatastats; } // export debugging samples to file int framesync64_debug_export(framesync64 _q, int _code, float complex * _payload_rx) { // determine what to do based on callback return code if (_code == 0) { // do not export file return LIQUID_OK; } else if (_code > 0) { // user-defined value sprintf(_q->filename,"%s_u%.8x.dat", _q->prefix, _code); } else if (_code == -1) { // based on number of packets detected sprintf(_q->filename,"%s_n%.8x.dat", _q->prefix, _q->framedatastats.num_frames_detected); } else if (_code == -2) { // decoded header (first 4 bytes) sprintf(_q->filename,"%s_h", _q->prefix); char * p = _q->filename + strlen(_q->prefix) + 2; for (unsigned int i=0; i<4; i++) { sprintf(p,"%.2x", _q->payload_dec[i]); p += 2; } sprintf(p,".dat"); } else if (_code == -3) { // random extension sprintf(_q->filename,"%s_r%.8x.dat", _q->prefix, rand() & 0xffffffff); } else { return liquid_error(LIQUID_EICONFIG,"framesync64_debug_export(), invalid return code %d", _code); } FILE * fid = fopen(_q->filename,"wb"); if (fid == NULL) return liquid_error(LIQUID_EIO,"framesync64_debug_export(), could not open %s for writing", _q->filename); // TODO: write file header? // write debug buffer float complex * rc; windowcf_read(_q->buf_debug, &rc); fwrite(rc, sizeof(float complex), LIQUID_FRAME64_LEN, fid); // export framesync stats //framesyncstats_export(_q->framesyncstats, fid); // export measured offsets float tau_hat = 0.0f; float phi_hat = 0.0f; fwrite(&tau_hat, sizeof(float), 1, fid); fwrite(&(_q->framesyncstats.cfo), sizeof(float), 1, fid); fwrite(&phi_hat, sizeof(float), 1, fid); fwrite(&(_q->framesyncstats.rssi), sizeof(float), 1, fid); fwrite(&(_q->framesyncstats.evm), sizeof(float), 1, fid); // export payload values fwrite(_payload_rx, sizeof(float complex), 630, fid); fwrite(_q->payload_sym, sizeof(float complex), 600, fid); fwrite(_q->payload_dec, sizeof(unsigned char), 72, fid); fclose(fid); _q->num_files_exported++; printf("framesync64_debug_export(), results written to %s (%u total)\n", _q->filename, _q->num_files_exported); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/framesyncstats.c000066400000000000000000000066551474751757600220500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // framesyncstats.c // // Default and generic frame statistics // #include #include #include #include #include #include "liquid.internal.h" framesyncstats_s framesyncstats_default = { // signal quality 0.0f, // error vector magnitude 0.0f, // rssi 0.0f, // carrier frequency offset // demodulated frame symbols NULL, // framesyms 0, // num_framesyms // modulation/coding scheme, etc. LIQUID_MODEM_UNKNOWN, // mod_scheme 0, // mod_bps LIQUID_CRC_UNKNOWN, // check LIQUID_FEC_UNKNOWN, // fec0 LIQUID_FEC_UNKNOWN // fec1 }; // initialize framesyncstats object on default int framesyncstats_init_default(framesyncstats_s * _stats) { memmove(_stats, &framesyncstats_default, sizeof(framesyncstats_s)); return LIQUID_OK; } // print framesyncstats object int framesyncstats_print(framesyncstats_s * _stats) { // validate statistics object if (_stats->mod_scheme >= LIQUID_MODEM_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"framesyncstats_print(), invalid modulation scheme"); if (_stats->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"framesyncstats_print(), invalid CRC scheme"); if (_stats->fec0 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"framesyncstats_print(), invalid FEC scheme (inner)"); if (_stats->fec1 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"framesyncstats_print(), invalid FEC scheme (outer)"); printf(" EVM : %12.8f dB\n", _stats->evm); printf(" rssi : %12.8f dB\n", _stats->rssi); printf(" carrier offset : %12.8f Fs\n", _stats->cfo); printf(" num symbols : %u\n", _stats->num_framesyms); printf(" mod scheme : %s (%u bits/symbol)\n", modulation_types[_stats->mod_scheme].name, _stats->mod_bps); printf(" validity check : %s\n", crc_scheme_str[_stats->check][0]); printf(" fec (inner) : %s\n", fec_scheme_str[_stats->fec0][0]); printf(" fec (outer) : %s\n", fec_scheme_str[_stats->fec1][0]); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/framing_cccf.c000066400000000000000000000055341474751757600213760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // complex floating-point synchronization and supporting objects #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "cccf" #define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) #define T float #define TO float complex #define TC float complex #define TI float complex #define ABS(X) cabsf(X) #define REAL(X) crealf(X) #define IMAG(X) cimagf(X) #define TO_COMPLEX 1 #define TC_COMPLEX 1 #define TI_COMPLEX 1 // supporting references #define AGC(name) LIQUID_CONCAT(agc_crcf,name) #define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define EQLMS(name) LIQUID_CONCAT(eqlms_cccf,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define QDETECTOR(name) LIQUID_CONCAT(qdetector_cccf,name) #define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) #define WINDOW(name) LIQUID_CONCAT(windowf,name) // object references #define BPRESYNC(name) LIQUID_CONCAT(bpresync_cccf,name) #define BSYNC(name) LIQUID_CONCAT(bsync_cccf,name) #define PRESYNC(name) LIQUID_CONCAT(presync_cccf,name) #define QDETECTOR(name) LIQUID_CONCAT(qdetector_cccf,name) #define QDSYNC(name) LIQUID_CONCAT(qdsync_cccf,name) #define SYMTRACK(name) LIQUID_CONCAT(symtrack_cccf,name) // prototypes #include "bpresync.proto.c" #include "bsync.proto.c" #include "presync.proto.c" #include "qdetector.proto.c" #include "qdsync.proto.c" #include "symtrack.proto.c" liquid-dsp-1.7.0/src/framing/src/framing_crcf.c000066400000000000000000000045271474751757600214160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // complex floating-point synchronization and supporting objects #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "crcf" #define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) #define T float #define TO float complex #define TC float #define TI float complex #define ABS(X) cabsf(X) #define REAL(X) crealf(X) #define IMAG(X) cimagf(X) #define TO_COMPLEX 1 #define TC_COMPLEX 0 #define TI_COMPLEX 1 // supporting references #define AGC(name) LIQUID_CONCAT(agc_crcf,name) #define BSYNC(name) LIQUID_CONCAT(bsync_crcf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define EQLMS(name) LIQUID_CONCAT(eqlms_crcf,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define SYMSYNC(name) LIQUID_CONCAT(symsync_crcf,name) #define WINDOW(name) LIQUID_CONCAT(windowf,name) // object references #define BSYNC(name) LIQUID_CONCAT(bsync_crcf,name) // prototypes #include "bsync.proto.c" liquid-dsp-1.7.0/src/framing/src/framing_rrrf.c000066400000000000000000000045041474751757600214470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // real floating-point synchronization and supporting objects #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "rrrf" #define PRINTVAL(x) printf("%12.4e + j%12.4e", crealf(x), cimagf(x)) #define T float #define TO float #define TC float #define TI float #define ABS(X) cabsf(X) #define REAL(X) crealf(X) #define IMAG(X) cimagf(X) #define TO_COMPLEX 0 #define TC_COMPLEX 0 #define TI_COMPLEX 0 // supporting references #define AGC(name) LIQUID_CONCAT(agc_rrrf,name) #define BSYNC(name) LIQUID_CONCAT(bsync_rrrf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_rrrf,name) #define EQLMS(name) LIQUID_CONCAT(eqlms_rrrf,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define NCO(name) LIQUID_CONCAT(nco_rrrf,name) #define SYMSYNC(name) LIQUID_CONCAT(symsync_rrrf,name) #define WINDOW(name) LIQUID_CONCAT(windowf,name) // object references #define BSYNC(name) LIQUID_CONCAT(bsync_rrrf,name) // prototypes #include "bsync.proto.c" liquid-dsp-1.7.0/src/framing/src/framingcf.c000066400000000000000000000045061474751757600207270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // complex floating-point framing and signal generators #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION "cf" #define TO float complex // output type #define T float // primitive type #define TO_COMPLEX 1 #define T_COMPLEX 0 // supporting references #define FIRINTERP(name) LIQUID_CONCAT(firinterp_crcf,name) #define IIRFILT(name) LIQUID_CONCAT(iirfilt_crcf, name) #define MODEM(name) LIQUID_CONCAT(modemcf, name) #define MSRESAMP(name) LIQUID_CONCAT(msresamp_crcf,name) #define NCO(name) LIQUID_CONCAT(nco_crcf, name) #define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf, name) // object references #define MSOURCE(name) LIQUID_CONCAT(msourcecf, name) #define QPACKETMODEM(name) LIQUID_CONCAT(qpacketmodem, name) #define QSOURCE(name) LIQUID_CONCAT(qsourcecf, name) #define SYMSTREAM(name) LIQUID_CONCAT(symstreamcf, name) #define SYMSTREAMR(name) LIQUID_CONCAT(symstreamrcf, name) // prototypes #include "msource.proto.c" #include "qpacketmodem.proto.c" #include "qsource.proto.c" #include "symstream.proto.c" #include "symstreamr.proto.c" liquid-dsp-1.7.0/src/framing/src/fskframegen.c000066400000000000000000000422261474751757600212640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // frequency-shift keying (FSK) frame generator #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_FSKFRAMEGEN 0 // fskframegen int fskframegen_encode_header (fskframegen _q, unsigned char * _header); int fskframegen_generate_symbol (fskframegen _q); int fskframegen_generate_zeros (fskframegen _q); int fskframegen_generate_preamble(fskframegen _q); int fskframegen_generate_header (fskframegen _q); int fskframegen_generate_payload (fskframegen _q); // fskframe object structure struct fskframegen_s { unsigned int m; // modulator bits/symbol unsigned int k; // modulator samples/symbol float bandwidth; // modulator bandwidth unsigned int M; // modulator constellation size, M=2^m fskmod mod_header; // modulator object for the header (BFSK) fskmod mod; // modulator object (M-FSK) float complex * buf; // modulator transmit buffer [size: k x 1] // preamble unsigned int preamble_sym_len; // preamble symbols length unsigned char * preamble_sym; // preamble symbol sequence // header #if 0 unsigned int header_dec_len; // header decoded message length crc_scheme header_crc; // header validity check fec_scheme header_fec0; // header inner code fec_scheme header_fec1; // header outer code packetizer header_encoder; // header encoder unsigned int header_enc_len; // header encoded message length unsigned char * header_dec; // header uncoded [size: header_dec_len x 1] unsigned char * header_enc; // header encoded [size: header_enc_len x 1] unsigned int header_sym_len; // header symbols length #else unsigned int header_dec_len; // unsigned int header_sym_len; // unsigned char * header_dec; // header uncoded [size: header_dec_len x 1] unsigned char * header_sym; // header: unmodulated symbols qpacketmodem header_encoder; // #endif // payload #if 0 unsigned int payload_dec_len; // payload decoded message length crc_scheme payload_crc; // payload validity check fec_scheme payload_fec0; // payload inner code fec_scheme payload_fec1; // payload outer code packetizer payload_encoder; // payload encoder unsigned int payload_enc_len; // payload encoded message length unsigned char * payload_enc; // paylaod encoded [size: payload_enc_len x 1] unsigned int payload_sym_len; // payload symbols length #else unsigned int payload_dec_len; // crc_scheme payload_crc; // payload validity check fec_scheme payload_fec0; // payload inner code fec_scheme payload_fec1; // payload outer code unsigned int payload_sym_len; // unsigned char * payload_sym; // qpacketmodem payload_encoder; // #endif // framing state enum { STATE_OFF, // unassembled STATE_PREAMBLE, // preamble STATE_HEADER, // header STATE_PAYLOAD, // payload (frame) } state; int frame_assembled; // frame assembled flag int frame_complete; // frame completed flag unsigned int symbol_counter; // output symbol counter unsigned int sample_counter; // output sample counter }; // create fskframegen object fskframegen fskframegen_create() { fskframegen q = (fskframegen) malloc(sizeof(struct fskframegen_s)); // set static values q->m = 4; // modulation bits/symbol q->M = 1 << q->m; // modulation constellation size q->k = 2 << q->m; // samples per symbol q->bandwidth = 0.25f; // occupied one-sided bandwidth (normalized to sample rate) // create modulators q->mod_header = fskmod_create( 1, q->k, q->bandwidth); q->mod = fskmod_create(q->m, q->k, q->bandwidth); q->buf = (float complex*) malloc( q->k * sizeof(float complex) ); // preamble symbols (over-sampled by 2) msequence preamble_ms = msequence_create(6, 0x6d, 1); q->preamble_sym_len = 64; q->preamble_sym = (unsigned char*)malloc(2*q->preamble_sym_len*sizeof(unsigned char)); unsigned int i; for (i=0; ipreamble_sym_len; i++) { q->preamble_sym[2*i+0] = msequence_advance(preamble_ms) ? 1 : 0; q->preamble_sym[2*i+1] = q->preamble_sym[2*i+0]; } msequence_destroy(preamble_ms); // header objects/arrays #if 0 q->header_dec_len = 10; q->header_crc = LIQUID_CRC_32; q->header_fec0 = LIQUID_FEC_NONE; q->header_fec1 = LIQUID_FEC_GOLAY2412; q->header_encoder = packetizer_create(q->header_dec_len, q->header_crc, q->header_fec0, q->header_fec1); q->header_enc_len = packetizer_get_dec_msg_len(q->header_encoder); q->header_dec = (unsigned char*)malloc(q->header_dec_len*sizeof(unsigned char)); q->header_enc = (unsigned char*)malloc(q->header_enc_len*sizeof(unsigned char)); q->header_sym_len = q->header_enc_len * 8 / q->m; #else q->header_dec_len = 10; q->header_dec = (unsigned char*)malloc(q->header_dec_len*sizeof(unsigned char)); q->header_encoder = qpacketmodem_create(); qpacketmodem_configure(q->header_encoder, q->header_dec_len, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_GOLAY2412, LIQUID_MODEM_BPSK); q->header_sym_len = qpacketmodem_get_frame_len(q->header_encoder); q->header_sym = (unsigned char*)malloc(q->header_sym_len*sizeof(unsigned char)); #endif // payload objects/arrays #if 0 q->payload_dec_len = 10; q->payload_crc = LIQUID_CRC_32; q->payload_fec0 = LIQUID_FEC_NONE; q->payload_fec1 = LIQUID_FEC_GOLAY2412; q->payload_encoder = packetizer_create(q->payload_dec_len, q->payload_crc, q->payload_fec0, q->payload_fec1); q->payload_enc_len = packetizer_get_dec_msg_len(q->payload_encoder); q->payload_enc = (unsigned char*)malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_sym_len = 0; // TODO: set this appropriately #else q->payload_dec_len = 200; q->payload_crc = LIQUID_CRC_32; q->payload_fec0 = LIQUID_FEC_NONE; q->payload_fec1 = LIQUID_FEC_HAMMING128; q->payload_encoder = qpacketmodem_create(); qpacketmodem_configure(q->payload_encoder, q->payload_dec_len, q->payload_crc, q->payload_fec0, q->payload_fec1, LIQUID_MODEM_QAM16); // TODO: set bits/sym appropriately q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_encoder); q->payload_sym = (unsigned char*)malloc(q->payload_sym_len*sizeof(unsigned char)); #endif // reset framing object fskframegen_reset(q); // return object return q; } // destroy fskframegen object int fskframegen_destroy(fskframegen _q) { // destroy modulators fskmod_destroy(_q->mod_header); fskmod_destroy(_q->mod); free(_q->buf); // free preamble symbols array free(_q->preamble_sym); // destroy/free header objects/arrays #if 0 free(_q->header_dec); free(_q->header_enc); packetizer_destroy(_q->header_encoder); #else free(_q->header_dec); free(_q->header_sym); qpacketmodem_destroy(_q->header_encoder); #endif // destroy/free payload objects/arrays #if 0 free(_q->payload_enc); packetizer_destroy(_q->payload_encoder); #else free(_q->payload_sym); qpacketmodem_destroy(_q->payload_encoder); #endif // free main object memory free(_q); return LIQUID_OK; } // reset frame generator object int fskframegen_reset(fskframegen _q) { // reset modulator fskmod_reset(_q->mod_header); fskmod_reset(_q->mod); // reset states _q->state = STATE_OFF; _q->frame_assembled = 0; _q->frame_complete = 0; _q->symbol_counter = 0; _q->sample_counter = _q->k; // indicate we are ready for a new symbol return LIQUID_OK; } // print fskframegen object internals int fskframegen_print(fskframegen _q) { #if 0 printf("fskframegen:\n"); printf(" physical properties\n"); printf(" bits/symbol : %u\n", _q->m); printf(" samples/symbol : %u\n", _q->k); printf(" bandwidth : %-8.3f\n", _q->bandwidth); printf(" framing properties\n"); printf(" preamble : %-4u symbols\n", _q->preamble_sym_len); printf(" header : %-4u symbols, %-4u bytes\n", _q->header_sym_len, _q->header_dec_len); printf(" payload : %-4u symbols, %-4u bytes\n", _q->payload_sym_len, _q->payload_dec_len); printf(" packet properties\n"); printf(" crc : %s\n", crc_scheme_str[_q->payload_crc ][1]); printf(" fec (inner) : %s\n", fec_scheme_str[_q->payload_fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->payload_fec1][1]); printf(" total samples : %-4u samples\n", fskframegen_getframelen(_q)); #else printf("\n"); #endif return LIQUID_OK; } // assemble frame // _q : frame generator object // _header : raw header // _payload : raw payload [size: _payload_len x 1] // _payload_len : raw payload length (bytes) // _check : data validity check // _fec0 : inner forward error correction // _fec1 : outer forward error correction int fskframegen_assemble(fskframegen _q, unsigned char * _header, unsigned char * _payload, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, fec_scheme _fec1) { #if 1 liquid_error(LIQUID_ENOIMP,"fskframegen_assemble(), base functionality not implemented; ignoring input parameters for now"); #else // set properties _q->payload_dec_len = _payload_len; _q->payload_crc = _check; _q->payload_fec0 = _fec0; _q->payload_fec1 = _fec1; // re-create payload packetizer //int rc = qpacketmodem_configure(_q->payload_encoder, _q->payload_dec_len, _q->payload_crc, _q->payload_fec0, _q->payload_fec1, LIQUID_MODEM_QPSK); #endif // get packet length _q->payload_sym_len = qpacketmodem_get_frame_len(_q->payload_encoder); // re-allocate memory _q->payload_sym = (unsigned char*) realloc(_q->payload_sym, _q->payload_sym_len*sizeof(unsigned char)); // set assembled flag _q->frame_assembled = 1; // encode header fskframegen_encode_header(_q, _header); // encode payload symbols qpacketmodem_encode_syms(_q->payload_encoder, _payload, _q->payload_sym); #if 0 printf("tx payload symbols (%u)\n", _q->payload_sym_len); unsigned int i; for (i=0; i<_q->payload_sym_len; i++) printf("%1x%s", _q->payload_sym[i], ((i+1)%64)==0 ? "\n" : ""); printf("\n"); #endif // set state appropriately _q->state = STATE_PREAMBLE; return LIQUID_OK; } // get frame length (number of samples) unsigned int fskframegen_getframelen(fskframegen _q) { if (!_q->frame_assembled) { liquid_error(LIQUID_EICONFIG,"fskframegen_getframelen(), frame not assembled!"); return 0; } unsigned int num_frame_symbols = _q->preamble_sym_len + // number of preamble p/n symbols _q->header_sym_len + // number of preamble p/n symbols _q->payload_sym_len; // number of payload symbols return num_frame_symbols*_q->k; // k samples/symbol } // write sample to output buffer int fskframegen_write_samples(fskframegen _q, float complex * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // buffer emptied; generate new symbol if (_q->sample_counter == _q->k) { fskframegen_generate_symbol(_q); _q->sample_counter = 0; } _buf[i] = _q->buf[_q->sample_counter++]; } return _q->frame_assembled ? 0 : 1; } // // internal methods // int fskframegen_encode_header(fskframegen _q, unsigned char * _header) { // first 8 bytes user data memmove(_q->header_dec, _header, 8); unsigned int n = 8; #if 0 // first byte is for expansion/version validation _q->header_dec[n+0] = 0; // version // add payload length _q->header_dec[n+1] = (_q->payload_dec_len >> 8) & 0xff; _q->header_dec[n+2] = (_q->payload_dec_len ) & 0xff; // add CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] _q->header_dec[n+3] = (_q->payload_crc & 0x07) << 5; _q->header_dec[n+3] |= (_q->payload_fec0 ) & 0x1f; _q->header_dec[n+4] = (_q->payload_fec1 ) & 0x1f; #else while (n < _q->header_dec_len) _q->header_dec[n++] = 0xff; #endif // run packet encoder, encoding into symbols qpacketmodem_encode_syms(_q->header_encoder, _q->header_dec, _q->header_sym); #if 0 printf("tx header symbols (%u):\n", _q->header_sym_len); unsigned int i; for (i=0; i<_q->header_sym_len; i++) printf("%1x", _q->header_sym[i]); printf("\n"); printf("tx header decoded (%u):\n", _q->header_dec_len); for (i=0; i<_q->header_dec_len; i++) printf(" %2x", _q->header_dec[i]); printf("\n"); #endif // TODO: scramble header return LIQUID_OK; } // write single symbol to internal buffer int fskframegen_generate_symbol(fskframegen _q) { switch (_q->state) { case STATE_OFF: return fskframegen_generate_zeros(_q); case STATE_PREAMBLE: return fskframegen_generate_preamble(_q); case STATE_HEADER: return fskframegen_generate_header(_q); case STATE_PAYLOAD: return fskframegen_generate_payload(_q); default:; } return liquid_error(LIQUID_EINT,"fskframegen_writesymbol(), unknown/unsupported internal state"); } int fskframegen_generate_zeros(fskframegen _q) { unsigned int i; for (i=0; i<_q->k; i++) _q->buf[i] = 0.0f; return LIQUID_OK; } int fskframegen_generate_preamble(fskframegen _q) { unsigned char s = _q->preamble_sym[_q->symbol_counter]; fskmod_modulate(_q->mod_header, s, _q->buf); // TODO: apply ramping for first symbol? _q->symbol_counter++; // NOTE: preamble is over-sampled by 2 if (_q->symbol_counter == 2*_q->preamble_sym_len) { _q->symbol_counter = 0; _q->state = STATE_HEADER; } return LIQUID_OK; } int fskframegen_generate_header(fskframegen _q) { unsigned int s = _q->header_sym[_q->symbol_counter]; fskmod_modulate(_q->mod_header, s, _q->buf); _q->symbol_counter++; if (_q->symbol_counter == _q->header_sym_len) { _q->symbol_counter = 0; _q->state = STATE_PAYLOAD; } return LIQUID_OK; } int fskframegen_generate_payload(fskframegen _q) { unsigned int s = _q->payload_sym[_q->symbol_counter]; fskmod_modulate(_q->mod, s, _q->buf); _q->symbol_counter++; if (_q->symbol_counter == _q->payload_sym_len) { _q->symbol_counter = 0; _q->frame_assembled = 0; _q->state = STATE_OFF; } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/fskframesync.c000066400000000000000000000640721474751757600214720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // fskframesync.c // #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_FSKFRAMESYNC 1 #define DEBUG_FSKFRAMESYNC_PRINT 0 #define DEBUG_FSKFRAMESYNC_FILENAME "fskframesync_debug.m" #define DEBUG_FSKFRAMESYNC_BUFFER_LEN (2000) // execute stages int fskframesync_execute_detectframe(fskframesync _q, float complex _x); int fskframesync_execute_rxheader( fskframesync _q, float complex _x); int fskframesync_execute_rxpayload( fskframesync _q, float complex _x); // decode header int fskframesync_decode_header(fskframesync _q); // fskframesync object structure struct fskframesync_s { unsigned int m; // demodulator bits/symbol unsigned int k; // demodulator samples/symbol float bandwidth; // demodulator bandwidth unsigned int M; // demodulator constellation size, M=2^m fskdem dem_header; // demodulator object for the header (BFSK) fskdem dem; // demodulator object (M-FSK) float complex * buf; // demodulator transmit buffer [size: k x 1] framesync_callback callback; // user-defined callback function void * userdata; // user-defined data structure framesyncstats_s framestats; // frame statistic object // synchronizer objects, states firpfb_crcf pfb; // timing recovery unsigned int npfb; // timing recovery (number of filters in bank) unsigned int pfb_index; // timing recovery (filter bank index) nco_crcf nco; // coarse carrier frequency recovery firfilt_rrrf detector; // frame correlator detector windowcf buf_rx; // pre-demod buffered samples, size: k windowf buf_LLR2; // detector signal level float rxy[3]; // detector output for timing recovery // header #if 0 unsigned int header_dec_len; // header decoded message length crc_scheme header_crc; // header validity check fec_scheme header_fec0; // header inner code fec_scheme header_fec1; // header outer code packetizer header_decoder; // header encoder unsigned int header_enc_len; // header encoded message length unsigned char * header_dec; // header uncoded [size: header_dec_len x 1] unsigned char * header_enc; // header encoded [size: header_enc_len x 1] unsigned int header_sym_len; // header symbols length #else unsigned int header_dec_len; // header length (decoded bytes) unsigned int header_sym_len; // header length (number of modulated symbols) unsigned char * header_dec; // header uncoded [size: header_dec_len x 1] unsigned char * header_sym; // header: unmodulated symbols qpacketmodem header_decoder; // #endif // payload #if 0 unsigned int payload_dec_len; // payload decoded message length crc_scheme payload_crc; // payload validity check fec_scheme payload_fec0; // payload inner code fec_scheme payload_fec1; // payload outer code packetizer payload_decoder; // payload encoder unsigned int payload_enc_len; // payload encoded message length unsigned char * payload_enc; // paylaod encoded [size: payload_enc_len x 1] unsigned int payload_sym_len; // payload symbols length #else unsigned int payload_dec_len; // payload decoded message length crc_scheme payload_crc; // payload validity check fec_scheme payload_fec0; // payload inner code fec_scheme payload_fec1; // payload outer code unsigned int payload_sym_len; // payload symbols length unsigned char * payload_sym; // unsigned char * payload_dec; // payload decoded [size: payload_dec_len x 1] qpacketmodem payload_decoder; // #endif // framing state enum { STATE_DETECTFRAME=0,// preamble STATE_RXHEADER, // header STATE_RXPAYLOAD, // payload (frame) } state; int frame_assembled; // frame assembled flag int frame_detected; // frame detected flag unsigned int sample_counter; // output sample counter unsigned int symbol_counter; // output symbol counter unsigned int timer; // sample timer // debugging structures #if DEBUG_FSKFRAMESYNC int debug_enabled; // debugging enabled? int debug_objects_created; // debugging objects created? windowcf debug_x; // received samples buffer #endif }; // create GMSK frame synchronizer // _callback : callback function // _userdata : user data pointer passed to callback function fskframesync fskframesync_create(framesync_callback _callback, void * _userdata) { fskframesync q = (fskframesync) malloc(sizeof(struct fskframesync_s)); // set static values q->callback = _callback; q->userdata = _userdata; q->m = 4; q->M = 1 << q->m; q->k = 2 << q->m; q->bandwidth = 0.25f; // create demodulators q->dem_header = fskdem_create( 1, q->k, q->bandwidth); q->dem = fskdem_create(q->m, q->k, q->bandwidth); q->buf = (float complex*) malloc( q->k * sizeof(float complex) ); // create polyphase filterbank for timing recovery q->npfb = 64; q->pfb = firpfb_crcf_create_kaiser(q->npfb, 5, 0.45f, 40.0f); // create oscillator for frequency recovery q->nco = nco_crcf_create(LIQUID_VCO); // create buffer for demodulator input q->buf_rx = windowcf_create(q->k); // create preamble frame detector from preamble symbols (over-sampled by 2) msequence preamble_ms = msequence_create(6, 0x6d, 1); unsigned int preamble_sym_len = 63; // 64; float * preamble = (float*) malloc( 2*preamble_sym_len*sizeof(float) ); unsigned int i; for (i=0; idetector = firfilt_rrrf_create(preamble, 2*preamble_sym_len); free(preamble); msequence_destroy(preamble_ms); // create buffer for detection q->buf_LLR2 = windowf_create(2*preamble_sym_len); // header objects/arrays #if 0 q->header_dec_len = 10; q->header_crc = LIQUID_CRC_32; q->header_fec0 = LIQUID_FEC_NONE; q->header_fec1 = LIQUID_FEC_GOLAY2412; q->header_decoder = packetizer_create(q->header_dec_len, q->header_crc, q->header_fec0, q->header_fec1); q->header_enc_len = packetizer_get_dec_msg_len(q->header_decoder); q->header_dec = (unsigned char*)malloc(q->header_dec_len*sizeof(unsigned char)); q->header_enc = (unsigned char*)malloc(q->header_enc_len*sizeof(unsigned char)); q->header_sym_len = q->header_enc_len * 8 / q->m; #else q->header_dec_len = 10; q->header_dec = (unsigned char*)malloc(q->header_dec_len*sizeof(unsigned char)); q->header_decoder = qpacketmodem_create(); qpacketmodem_configure(q->header_decoder, q->header_dec_len, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_GOLAY2412, LIQUID_MODEM_BPSK); q->header_sym_len = qpacketmodem_get_frame_len(q->header_decoder); q->header_sym = (unsigned char*)malloc(q->header_sym_len*sizeof(unsigned char)); #endif // payload objects/arrays #if 0 q->payload_dec_len = 10; q->payload_crc = LIQUID_CRC_32; q->payload_fec0 = LIQUID_FEC_NONE; q->payload_fec1 = LIQUID_FEC_GOLAY2412; q->payload_decoder = packetizer_create(q->payload_dec_len, q->payload_crc, q->payload_fec0, q->payload_fec1); q->payload_enc_len = packetizer_get_dec_msg_len(q->payload_decoder); q->payload_enc = (unsigned char*)malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_sym_len = 0; // TODO: set this appropriately #else q->payload_dec_len = 200; q->payload_crc = LIQUID_CRC_32; q->payload_fec0 = LIQUID_FEC_NONE; q->payload_fec1 = LIQUID_FEC_HAMMING128; q->payload_decoder = qpacketmodem_create(); qpacketmodem_configure(q->payload_decoder, q->payload_dec_len, q->payload_crc, q->payload_fec0, q->payload_fec1, LIQUID_MODEM_QAM16); // TODO: set bits/sym appropriately q->payload_sym_len = qpacketmodem_get_frame_len(q->payload_decoder); q->payload_sym = (unsigned char*)malloc(q->payload_sym_len*sizeof(unsigned char)); q->payload_dec = (unsigned char*)malloc(q->payload_dec_len*sizeof(unsigned char)); #endif #if DEBUG_FSKFRAMESYNC // debugging structures q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; #endif // reset synchronizer fskframesync_reset(q); // return synchronizer object return q; } // destroy frame synchronizer object, freeing all internal memory int fskframesync_destroy(fskframesync _q) { #if DEBUG_FSKFRAMESYNC // destroy debugging objects if (_q->debug_objects_created) { windowcf_destroy(_q->debug_x); } #endif // destroy modulators fskdem_destroy(_q->dem_header); fskdem_destroy(_q->dem); free(_q->buf); // reset symbol timing recovery state firpfb_crcf_destroy(_q->pfb); // reset carrier recovery objects nco_crcf_destroy(_q->nco); // clear pre-demod buffer windowcf_destroy(_q->buf_rx); // reset internal objects firfilt_rrrf_destroy(_q->detector); windowf_destroy(_q->buf_LLR2); // destroy/free header objects/arrays #if 0 free(_q->header_dec); free(_q->header_enc); packetizer_destroy(_q->header_decoder); #else free(_q->header_dec); free(_q->header_sym); qpacketmodem_destroy(_q->header_decoder); #endif // destroy/free payload objects/arrays #if 0 free(_q->payload_enc); packetizer_destroy(_q->payload_decoder); #else free(_q->payload_sym); free(_q->payload_dec); qpacketmodem_destroy(_q->payload_decoder); #endif // free main object memory free(_q); return LIQUID_OK; } // print frame synchronizer object internals int fskframesync_print(fskframesync _q) { #if 0 printf("fskframesync:\n"); printf(" physical properties\n"); printf(" bits/symbol : %u\n", _q->m); printf(" samples/symbol : %u\n", _q->k); printf(" bandwidth : %-8.3f\n", _q->bandwidth); printf(" framing properties\n"); printf(" preamble : %-4u symbols\n", 0); //_q->preamble_sym_len); printf(" header : %-4u symbols, %-4u bytes\n", _q->header_sym_len, _q->header_dec_len); printf(" payload : %-4u symbols, %-4u bytes\n", _q->payload_sym_len, _q->payload_dec_len); printf(" packet properties\n"); printf(" crc : %s\n", crc_scheme_str[_q->payload_crc ][1]); printf(" fec (inner) : %s\n", fec_scheme_str[_q->payload_fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->payload_fec1][1]); printf(" total samples : %-4u samples\n", 0); #else printf("\n"); #endif return LIQUID_OK; } // reset frame synchronizer object int fskframesync_reset(fskframesync _q) { // reset symbol timing recovery state firpfb_crcf_reset(_q->pfb); // reset carrier recovery objects nco_crcf_reset(_q->nco); // clear pre-demod buffer windowcf_reset(_q->buf_rx); // reset internal objects firfilt_rrrf_reset(_q->detector); // reset state and counters _q->state = STATE_DETECTFRAME; _q->frame_detected = 0; _q->sample_counter = 0; _q->symbol_counter = 0; _q->timer = _q->k - 1; _q->pfb_index = 0; return LIQUID_OK; } // execute frame synchronizer // _q : frame synchronizer object // _x : input sample int fskframesync_execute(fskframesync _q, float complex _x) { // push through synchronizer #if DEBUG_FSKFRAMESYNC if (_q->debug_enabled) windowcf_push(_q->debug_x, _x); #endif switch (_q->state) { case STATE_DETECTFRAME: return fskframesync_execute_detectframe(_q, _x); case STATE_RXHEADER: return fskframesync_execute_rxheader (_q, _x); case STATE_RXPAYLOAD: return fskframesync_execute_rxpayload (_q, _x); default:; } return liquid_error(LIQUID_EINT,"fskframesync_execute(), invalid internal mode"); } // execute frame synchronizer on a block of samples // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples int fskframesync_execute_block(fskframesync _q, float complex * _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) { if (fskframesync_execute(_q, _x[i])) return liquid_error(LIQUID_EINT,"fskframesync_execute_block(), invalid internal mode"); } return LIQUID_OK; } // // internal methods // int fskframesync_execute_detectframe(fskframesync _q, float complex _x) { #if 0 // push sample through timing recovery and compute output float complex y; firpfb_crcf_push(_q->pfb, _x); firpfb_crcf_execute(_q->pfb, 0, &y); // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buf_rx, y); #else windowcf_push(_q->buf_rx, _x); #endif // decrement timer and determine if symbol output is ready _q->timer--; if (_q->timer) return LIQUID_OK; // reset timer _q->timer = _q->k; // run demodulator and retrieve FFT result, computing LLR sample output float complex * r; windowcf_read(_q->buf_rx, &r); fskdem_demodulate(_q->dem_header, r); int fft_bin_range = 2; float v0 = fskdem_get_symbol_energy(_q->dem_header, 0, fft_bin_range); // energy for '0' symbol float v1 = fskdem_get_symbol_energy(_q->dem_header, 1, fft_bin_range); // energy for '1' symbol // compute LLR value float LLR = logf( (v1+1e-9f)/(v0+1e-9f) ); // push result into detector float v; firfilt_rrrf_push( _q->detector, LLR); firfilt_rrrf_execute(_q->detector, &v); // scale by signal level windowf_push(_q->buf_LLR2, LLR*LLR); float * rf; windowf_read(_q->buf_LLR2, &rf); float g = 0.0f; unsigned int i; unsigned int n = 126; // sum squares for (i=0; irxy[0] = _q->rxy[1]; _q->rxy[1] = _q->rxy[2]; _q->rxy[2] = rxy; // check state; we are waiting for correlator to peak here if (!_q->frame_detected) { // frame not yet detected; check cross-correlator output // NOTE: because this is a ratio of energies in frequency, we don't need // to take the absolute value here; only positive values should work if (rxy > 0.5f) { //printf("### fskframe detected! ###\n"); _q->frame_detected = 1; } } else { // frame has already been detected; wait for signal to peak if (_q->rxy[1] > _q->rxy[2]) { //printf("signal peaked! %12.8f %12.8f %12.8f\n", // _q->rxy[0], _q->rxy[1], _q->rxy[2]); #if 0 // compute estimate, apply bias compensation float gamma = (_q->rxy[2] - _q->rxy[0]) / _q->rxy[1]; float p2 = 9.54907046918287e-01f; float p1 = 8.87465224972323e-02; float xf = fabsf(gamma); float tau_hat = copysignf(p2*xf*xf + p1*xf, gamma); int num_samples = round(tau_hat * _q->k); printf("timing offset estimate : %12.8f -> %12.8f (%d samples)\n", gamma, tau_hat, num_samples); #endif // TODO: set timer and filterbank index accordingly _q->timer = 2*_q->k; // update state... _q->state = STATE_RXHEADER; } else { //printf("signal not yet peaked...\n"); } } return LIQUID_OK; } int fskframesync_execute_rxheader(fskframesync _q, float complex _x) { #if 0 // push sample through timing recovery and compute output float complex y; firpfb_crcf_push(_q->pfb, _x); firpfb_crcf_execute(_q->pfb, 0, &y); // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buf_rx, y); #else windowcf_push(_q->buf_rx, _x); #endif // decrement timer and determine if symbol output is ready _q->timer--; if (_q->timer) return LIQUID_OK; // reset timer _q->timer = _q->k; // run demodulator float complex * r; windowcf_read(_q->buf_rx, &r); unsigned char sym = fskdem_demodulate(_q->dem_header, r); // add symbol to header buffer _q->header_sym[_q->symbol_counter++] = sym; // decode header if appropriate if (_q->symbol_counter == _q->header_sym_len) { // decode header int header_valid = qpacketmodem_decode_syms(_q->header_decoder, _q->header_sym, _q->header_dec); #if 0 printf("rx header symbols (%u):\n", _q->header_sym_len); unsigned int i; for (i=0; i<_q->header_sym_len; i++) printf("%1x", _q->header_sym[i]); printf("\n"); printf("rx header decoded (%u):\n", _q->header_dec_len); for (i=0; i<_q->header_dec_len; i++) printf(" %.2x", _q->header_dec[i]); printf("\n"); printf("header: %s\n", header_valid ? "valid" : "INVALID"); #endif if (header_valid) { // continue on to decoding payload _q->symbol_counter = 0; _q->state = STATE_RXPAYLOAD; return LIQUID_OK; } // update statistics //_q->framedatastats.num_frames_detected++; // header invalid: invoke callback if (_q->callback != NULL) { // set framestats internals _q->framestats.evm = 0.0f; //20*log10f(sqrtf(_q->framestats.evm / 600)); _q->framestats.rssi = 0.0f; //20*log10f(_q->gamma_hat); _q->framestats.cfo = 0.0f; //nco_crcf_get_frequency(_q->mixer); _q->framestats.framesyms = NULL; _q->framestats.num_framesyms = 0; _q->framestats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framestats.mod_bps = 0; _q->framestats.check = LIQUID_CRC_UNKNOWN; _q->framestats.fec0 = LIQUID_FEC_UNKNOWN; _q->framestats.fec1 = LIQUID_FEC_UNKNOWN; // invoke callback method _q->callback(_q->header_dec, 0, // header valid NULL, // payload 0, // payload length 0, // payload valid, _q->framestats, _q->userdata); } // reset frame synchronizer fskframesync_reset(_q); } return LIQUID_OK; } int fskframesync_execute_rxpayload(fskframesync _q, float complex _x) { #if 0 // push sample through timing recovery and compute output float complex y; firpfb_crcf_push(_q->pfb, _x); firpfb_crcf_execute(_q->pfb, 0, &y); // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buf_rx, y); #else windowcf_push(_q->buf_rx, _x); #endif // decrement timer and determine if symbol output is ready _q->timer--; if (_q->timer) return LIQUID_OK; // reset timer _q->timer = _q->k; // run demodulator float complex * r; windowcf_read(_q->buf_rx, &r); unsigned char sym = fskdem_demodulate(_q->dem, r); // add symbol to payload buffer _q->payload_sym[_q->symbol_counter++] = sym; // decode payload if appropriate if (_q->symbol_counter == _q->payload_sym_len) { #if 0 printf("rx payload symbols (%u)\n", _q->payload_sym_len); unsigned int i; for (i=0; i<_q->payload_sym_len; i++) printf("%1x%s", _q->payload_sym[i], ((i+1)%64)==0 ? "\n" : ""); printf("\n"); #endif // decode payload int payload_valid = qpacketmodem_decode_syms(_q->payload_decoder, _q->payload_sym, _q->payload_dec); //printf("payload: %s\n", payload_valid ? "valid" : "INVALID"); // invoke callback if (_q->callback != NULL) { // set framestats internals _q->framestats.evm = 0.0f; //20*log10f(sqrtf(_q->framestats.evm / 600)); _q->framestats.rssi = 0.0f; //20*log10f(_q->gamma_hat); _q->framestats.cfo = 0.0f; //nco_crcf_get_frequency(_q->mixer); _q->framestats.framesyms = NULL; _q->framestats.num_framesyms = 0; _q->framestats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framestats.mod_bps = 0; _q->framestats.check = _q->payload_crc; _q->framestats.fec0 = _q->payload_fec0; _q->framestats.fec1 = _q->payload_fec1; // invoke callback method _q->callback(_q->header_dec, // decoded header 1, // header valid _q->payload_dec, // payload _q->payload_dec_len, // payload length payload_valid, // payload valid, _q->framestats, _q->userdata); } // reset frame synchronizer return fskframesync_reset(_q); } return LIQUID_OK; } // decode header and re-configure payload decoder int fskframesync_decode_header(fskframesync _q) { return LIQUID_OK; } int fskframesync_debug_enable(fskframesync _q) { // create debugging objects if necessary #if DEBUG_FSKFRAMESYNC if (!_q->debug_objects_created) { _q->debug_x = windowcf_create(DEBUG_FSKFRAMESYNC_BUFFER_LEN); } // set debugging flags _q->debug_enabled = 1; _q->debug_objects_created = 1; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"fskframesync_debug_enable(), compile-time debugging disabled\n"); #endif } int fskframesync_debug_disable(fskframesync _q) { #if DEBUG_FSKFRAMESYNC _q->debug_enabled = 0; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"fskframesync_debug_disable(), compile-time debugging disabled\n"); #endif } int fskframesync_debug_export(fskframesync _q, const char * _filename) { #if DEBUG_FSKFRAMESYNC if (!_q->debug_objects_created) return liquid_error(LIQUID_EICONFIG,"fskframe_debug_print(), debugging objects don't exist; enable debugging first"); FILE* fid = fopen(_filename,"w"); if (fid == NULL) return liquid_error(LIQUID_EIO,"fskframesync_debug_print(), could not open '%s' for writing", _filename); fprintf(fid,"%% %s: auto-generated file", _filename); fprintf(fid,"\n\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"close all;\n\n"); fprintf(fid,"num_samples = %u;\n", DEBUG_FSKFRAMESYNC_BUFFER_LEN); fprintf(fid,"t = 0:(num_samples-1);\n"); unsigned int i; float complex * rc; // write x fprintf(fid,"x = zeros(1,num_samples);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; i #include #include #include #include #include #include "liquid.internal.h" // gmskframegen int gmskframegen_encode_header( gmskframegen _q, const unsigned char * _header); int gmskframegen_write_zeros (gmskframegen _q); int gmskframegen_write_preamble(gmskframegen _q); int gmskframegen_write_header( gmskframegen _q); int gmskframegen_write_payload( gmskframegen _q); int gmskframegen_write_tail( gmskframegen _q); int gmskframegen_gen_symbol( gmskframegen _q); // gmskframe object structure struct gmskframegen_s { gmskmod mod; // GMSK modulator unsigned int k; // filter samples/symbol unsigned int m; // filter semi-length (symbols) float BT; // filter bandwidth-time product // framing lengths (symbols) unsigned int preamble_len; // unsigned int header_len; // length of header (encoded) unsigned int payload_len; // unsigned int tail_len; // // preamble //unsigned int genpoly_header;// generator polynomial msequence ms_preamble; // preamble p/n sequence // header unsigned int header_user_len; unsigned int header_enc_len; unsigned char * header_dec; // uncoded header [header_user_len + GMSKFRAME_H_DEC] unsigned char * header_enc; // encoded header [header_enc_len] packetizer p_header; // header packetizer // payload packetizer p_payload; // payload packetizer crc_scheme check; // CRC fec_scheme fec0; // inner forward error correction fec_scheme fec1; // outer forward error correction unsigned int dec_msg_len; // unsigned int enc_msg_len; // unsigned char * payload_enc;// encoded payload // framing state enum { STATE_UNASSEMBLED, // frame not assembled STATE_PREAMBLE, // preamble STATE_HEADER, // header STATE_PAYLOAD, // payload (frame) STATE_TAIL, // tail symbols } state; int frame_assembled; // frame assembled flag int frame_complete; // frame completed flag unsigned int symbol_counter;// // output sample buffer (one symbol's worth of data) complex float * buf_sym; // size: k x 1 unsigned int buf_idx; // output sample buffer index }; // create gmskframegen object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskframegen gmskframegen_create_set(unsigned int _k, unsigned int _m, float _BT) { gmskframegen q = (gmskframegen) malloc(sizeof(struct gmskframegen_s)); // set internal properties q->k = _k; // samples/symbol q->m = _m; // filter delay (symbols) q->BT = _BT; // filter bandwidth-time product // internal/derived values q->preamble_len = 63; // number of preamble symbols q->payload_len = 0; // number of payload symbols q->tail_len = 2*q->m; // number of tail symbols (flush interp) // create modulator q->mod = gmskmod_create(q->k, q->m, q->BT); // preamble objects/arrays q->ms_preamble = msequence_create(6, 0x6d, 1); // reset framing object gmskframegen_reset(q); q->header_dec = NULL; q->header_enc = NULL; q->p_header = NULL; gmskframegen_set_header_len(q, GMSKFRAME_H_USER_DEFAULT); // payload objects/arrays q->dec_msg_len = 0; q->check = LIQUID_CRC_32; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; q->p_payload = packetizer_create(q->dec_msg_len, q->check, q->fec0, q->fec1); q->enc_msg_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_len = 8*q->enc_msg_len; // allocate memory for encoded packet q->payload_enc = (unsigned char*) malloc(q->enc_msg_len*sizeof(unsigned char)); // allocate memory for symbols q->buf_sym = (float complex*)malloc(q->k*sizeof(float complex)); // reset object and return gmskframegen_reset(q); return q; } // create default GMSK frame generator (k=2, m=3, BT=0.5) gmskframegen gmskframegen_create() { return gmskframegen_create_set(2, 3, 0.5f); } // destroy gmskframegen object int gmskframegen_destroy(gmskframegen _q) { // destroy gmsk modulator gmskmod_destroy(_q->mod); // destroy/free preamble objects/arrays msequence_destroy(_q->ms_preamble); // destroy/free header objects/arrays free(_q->header_dec); free(_q->header_enc); packetizer_destroy(_q->p_header); // destroy/free payload objects/arrays free(_q->payload_enc); packetizer_destroy(_q->p_payload); // free symbol buffer free(_q->buf_sym); // free main object memory free(_q); return LIQUID_OK; } // reset frame generator object int gmskframegen_reset(gmskframegen _q) { // reset GMSK modulator gmskmod_reset(_q->mod); // reset states _q->state = STATE_UNASSEMBLED; msequence_reset(_q->ms_preamble); _q->frame_assembled = 0; _q->frame_complete = 0; _q->symbol_counter = 0; _q->buf_idx = _q->k; // indicate buffer is empty return LIQUID_OK; } // is frame assembled? int gmskframegen_is_assembled(gmskframegen _q) { return _q->frame_assembled; } // print gmskframegen object internals int gmskframegen_print(gmskframegen _q) { #if 0 printf("gmskframegen:\n"); printf(" physical properties\n"); printf(" samples/symbol : %u\n", _q->k); printf(" filter delay : %u symbols\n", _q->m); printf(" bandwidth-time : %-8.3f\n", _q->BT); printf(" framing properties\n"); printf(" preamble : %-4u symbols\n", _q->preamble_len); printf(" header : %-4u symbols\n", _q->header_len); printf(" payload : %-4u symbols\n", _q->payload_len); printf(" tail : %-4u symbols\n", _q->tail_len); printf(" packet properties\n"); printf(" crc : %s\n", crc_scheme_str[_q->check][1]); printf(" fec (inner) : %s\n", fec_scheme_str[_q->fec0][1]); printf(" fec (outer) : %s\n", fec_scheme_str[_q->fec1][1]); printf(" total samples : %-4u samples\n", gmskframegen_getframelen(_q)); #else printf("\n"); #endif return LIQUID_OK; } int gmskframegen_set_header_len(gmskframegen _q, unsigned int _len) { if (_q->frame_assembled) return liquid_error(LIQUID_EICONFIG,"gmskframegen_set_header_len(), frame is already assembled; must reset() first"); _q->header_user_len = _len; unsigned int header_dec_len = GMSKFRAME_H_DEC + _q->header_user_len; _q->header_dec = (unsigned char*)realloc(_q->header_dec, header_dec_len*sizeof(unsigned char)); if (_q->p_header) { packetizer_destroy(_q->p_header); } _q->p_header = packetizer_create(header_dec_len, GMSKFRAME_H_CRC, GMSKFRAME_H_FEC, LIQUID_FEC_NONE); _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header); _q->header_enc = (unsigned char*)realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char)); _q->header_len = _q->header_enc_len * 8; return LIQUID_OK; } // assemble frame // _q : frame generator object // _header : raw header // _payload : raw payload [size: _payload_len x 1] // _payload_len : raw payload length (bytes) // _check : data validity check // _fec0 : inner forward error correction // _fec1 : outer forward error correction int gmskframegen_assemble(gmskframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, fec_scheme _fec1) { // reset frame generator state gmskframegen_reset(_q); // re-create frame generator if properties don't match if (_q->dec_msg_len != _payload_len || _q->check != _check || _q->fec0 != _fec0 || _q->fec1 != _fec1) { // set properties _q->dec_msg_len = _payload_len; _q->check = _check; _q->fec0 = _fec0; _q->fec1 = _fec1; // re-create payload packetizer _q->p_payload = packetizer_recreate(_q->p_payload, _q->dec_msg_len, _q->check, _q->fec0, _q->fec1); // get packet length _q->enc_msg_len = packetizer_get_enc_msg_len(_q->p_payload); _q->payload_len = 8*_q->enc_msg_len; // re-allocate memory _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->enc_msg_len*sizeof(unsigned char)); } // set assembled flag _q->frame_assembled = 1; // encode header gmskframegen_encode_header(_q, _header); // encode payload packetizer_encode(_q->p_payload, _payload, _q->payload_enc); _q->state = STATE_PREAMBLE; return LIQUID_OK; } // assemble default frame with a particular size payload int gmskframegen_assemble_default(gmskframegen _q, unsigned int _payload_len) { return gmskframegen_assemble(_q, NULL, NULL, _payload_len, LIQUID_CRC_32, LIQUID_FEC_NONE, LIQUID_FEC_GOLAY2412); } // get frame length (number of samples) unsigned int gmskframegen_getframelen(gmskframegen _q) { if (!_q->frame_assembled) { liquid_error(LIQUID_EICONFIG,"gmskframegen_getframelen(), frame not assembled"); return 0; } unsigned int num_frame_symbols = _q->preamble_len + // number of preamble p/n symbols _q->header_len + // number of header symbols _q->payload_len + // number of payload symbols 2*_q->m; // number of tail symbols return num_frame_symbols*_q->k; // k samples/symbol } // generate a symbol's worth of samples to internal buffer int gmskframegen_gen_symbol(gmskframegen _q) { _q->buf_idx = 0; switch (_q->state) { case STATE_UNASSEMBLED: gmskframegen_write_zeros (_q); break; case STATE_PREAMBLE: gmskframegen_write_preamble(_q); break; case STATE_HEADER: gmskframegen_write_header (_q); break; case STATE_PAYLOAD: gmskframegen_write_payload (_q); break; case STATE_TAIL: gmskframegen_write_tail (_q); break; default: return liquid_error(LIQUID_EINT,"gmskframegen_writesymbol(), invalid internal state"); } /* // reset framing object if (_q->frame_complete) gmskframegen_reset(_q); */ return LIQUID_OK; } // write samples of assembled frame // _q : frame generator object // _buf : output buffer [size: _buf_len x 1] // _buf_len : output buffer length int gmskframegen_write(gmskframegen _q, float complex * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // fill buffer if needed if (_q->buf_idx == _q->k) gmskframegen_gen_symbol(_q); // save output sample _buf[i] = _q->buf_sym[_q->buf_idx++]; } return _q->frame_complete; } // DEPRECATED: write samples of assembled frame // _q : frame generator object // _buf : output buffer [size: _buf_len x 1] int gmskframegen_write_samples(gmskframegen _q, float complex * _buf) { return gmskframegen_write(_q, _buf, _q->k); } // // internal methods // int gmskframegen_encode_header(gmskframegen _q, const unsigned char * _header) { // first 'n' bytes user data if (_header == NULL) memset(_q->header_dec, 0, _q->header_user_len); else memmove(_q->header_dec, _header, _q->header_user_len); unsigned int n = _q->header_user_len; // first byte is for expansion/version validation _q->header_dec[n+0] = GMSKFRAME_VERSION; // add payload length _q->header_dec[n+1] = (_q->dec_msg_len >> 8) & 0xff; _q->header_dec[n+2] = (_q->dec_msg_len ) & 0xff; // add CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] _q->header_dec[n+3] = (_q->check & 0x07) << 5; _q->header_dec[n+3] |= (_q->fec0) & 0x1f; _q->header_dec[n+4] = (_q->fec1) & 0x1f; // run packet encoder packetizer_encode(_q->p_header, _q->header_dec, _q->header_enc); // scramble header scramble_data(_q->header_enc, _q->header_enc_len); #if 0 printf(" header_enc :"); unsigned int i; for (i=0; iheader_enc[i]); printf("\n"); #endif return LIQUID_OK; } int gmskframegen_write_zeros(gmskframegen _q) { memset(_q->buf_sym, 0x0, _q->k*sizeof(float complex)); return LIQUID_OK; } int gmskframegen_write_preamble(gmskframegen _q) { unsigned char bit = msequence_advance(_q->ms_preamble); gmskmod_modulate(_q->mod, bit, _q->buf_sym); // apply ramping window to first 'm' symbols if (_q->symbol_counter < _q->m) { unsigned int i; for (i=0; i<_q->k; i++) _q->buf_sym[i] *= liquid_hamming(_q->symbol_counter*_q->k + i, 2*_q->m*_q->k); } _q->symbol_counter++; if (_q->symbol_counter == _q->preamble_len) { msequence_reset(_q->ms_preamble); _q->symbol_counter = 0; _q->state = STATE_HEADER; } return LIQUID_OK; } int gmskframegen_write_header(gmskframegen _q) { div_t d = div(_q->symbol_counter, 8); unsigned int byte_index = d.quot; unsigned int bit_index = d.rem; unsigned char byte = _q->header_enc[byte_index]; unsigned char bit = (byte >> (8-bit_index-1)) & 0x01; gmskmod_modulate(_q->mod, bit, _q->buf_sym); _q->symbol_counter++; if (_q->symbol_counter == _q->header_len) { _q->symbol_counter = 0; _q->state = STATE_PAYLOAD; } return LIQUID_OK; } int gmskframegen_write_payload(gmskframegen _q) { div_t d = div(_q->symbol_counter, 8); unsigned int byte_index = d.quot; unsigned int bit_index = d.rem; unsigned char byte = _q->payload_enc[byte_index]; unsigned char bit = (byte >> (8-bit_index-1)) & 0x01; gmskmod_modulate(_q->mod, bit, _q->buf_sym); _q->symbol_counter++; if (_q->symbol_counter == _q->payload_len) { _q->symbol_counter = 0; _q->state = STATE_TAIL; } return LIQUID_OK; } int gmskframegen_write_tail(gmskframegen _q) { unsigned char bit = rand() % 2; gmskmod_modulate(_q->mod, bit, _q->buf_sym); // apply ramping window to last 'm' symbols if (_q->symbol_counter >= _q->m) { unsigned int i; for (i=0; i<_q->k; i++) _q->buf_sym[i] *= liquid_hamming(_q->m*_q->k + (_q->symbol_counter-_q->m)*_q->k + i, 2*_q->m*_q->k); } _q->symbol_counter++; if (_q->symbol_counter == _q->tail_len) { _q->symbol_counter = 0; _q->frame_complete = 1; _q->state = STATE_UNASSEMBLED; } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/gmskframesync.c000066400000000000000000000715331474751757600216500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // gmskframesync.c #include #include #include #include #include #include #include "liquid.internal.h" // enable pre-demodulation filter (remove out-of-band noise) #define GMSKFRAMESYNC_PREFILTER 1 // execute a single, post-filtered sample int gmskframesync_execute_sample(gmskframesync _q, float complex _x); // push buffered p/n sequence through synchronizer int gmskframesync_pushpn(gmskframesync _q); // ... int gmskframesync_syncpn(gmskframesync _q); // update instantaneous frequency estimate int gmskframesync_update_fi(gmskframesync _q, float complex _x); // update symbol synchronizer internal state (filtered error, index, etc.) // _q : frame synchronizer // _x : input sample // _y : output symbol int gmskframesync_update_symsync(gmskframesync _q, float _x, float * _y); // execute stages int gmskframesync_execute_detectframe(gmskframesync _q, float complex _x); int gmskframesync_execute_rxpreamble( gmskframesync _q, float complex _x); int gmskframesync_execute_rxheader( gmskframesync _q, float complex _x); int gmskframesync_execute_rxpayload( gmskframesync _q, float complex _x); // decode header int gmskframesync_decode_header(gmskframesync _q); // gmskframesync object structure struct gmskframesync_s { #if GMSKFRAMESYNC_PREFILTER iirfilt_crcf prefilter; // pre-demodulation filter #endif unsigned int k; // filter samples/symbol unsigned int m; // filter semi-length (symbols) float BT; // filter bandwidth-time product framesync_callback callback; // user-defined callback function void * userdata; // user-defined data structure framesyncstats_s framesyncstats;// frame statistic object framedatastats_s framedatastats;// frame statistic object (packet statistics) // float complex x_prime; // received sample state float fi_hat; // instantaneous frequency estimate // timing recovery objects, states firpfb_rrrf mf; // matched filter decimator firpfb_rrrf dmf; // derivative matched filter decimator unsigned int npfb; // number of filters in symsync float pfb_q; // filtered timing error float pfb_soft; // soft filterbank index int pfb_index; // hard filterbank index int pfb_timer; // filterbank output flag float symsync_out; // symbol synchronizer output // synchronizer objects detector_cccf frame_detector; // pre-demod detector float tau_hat; // fractional timing offset estimate float dphi_hat; // carrier frequency offset estimate float gamma_hat; // channel gain estimate windowcf buffer; // pre-demod buffered samples, size: k*(pn_len+m) nco_crcf nco_coarse; // coarse carrier frequency recovery // preamble unsigned int preamble_len; // number of symbols in preamble float * preamble_pn; // preamble p/n sequence (known) float * preamble_rx; // preamble p/n sequence (received) // header unsigned int header_user_len; unsigned int header_enc_len; unsigned int header_mod_len; unsigned char * header_mod; unsigned char * header_enc; unsigned char * header_dec; packetizer p_header; int header_valid; // payload char payload_byte; // received byte crc_scheme check; // payload validity check fec_scheme fec0; // payload FEC (inner) fec_scheme fec1; // payload FEC (outer) unsigned int payload_enc_len; // length of encoded payload unsigned int payload_dec_len; // payload length (num un-encoded bytes) unsigned char * payload_enc; // payload data (encoded bytes) unsigned char * payload_dec; // payload data (encoded bytes) packetizer p_payload; // payload packetizer int payload_valid; // did payload pass crc? // status variables enum { STATE_DETECTFRAME=0, // detect frame (seek p/n sequence) STATE_RXPREAMBLE, // receive p/n sequence STATE_RXHEADER, // receive header data STATE_RXPAYLOAD, // receive payload data } state; unsigned int preamble_counter; // counter: num of p/n syms received unsigned int header_counter; // counter: num of header syms received unsigned int payload_counter; // counter: num of payload syms received }; // create GMSK frame synchronizer // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create_set(unsigned int _k, unsigned int _m, float _BT, framesync_callback _callback, void * _userdata) { gmskframesync q = (gmskframesync) malloc(sizeof(struct gmskframesync_s)); q->callback = _callback; q->userdata = _userdata; q->k = _k; // samples/symbol q->m = _m; // filter delay (symbols) q->BT = _BT; // filter bandwidth-time product #if GMSKFRAMESYNC_PREFILTER // create default low-pass Butterworth filter q->prefilter = iirfilt_crcf_create_lowpass(3, 0.5f*(1 + q->BT) / (float)(q->k)); #endif unsigned int i; // frame detector q->preamble_len = 63; q->preamble_pn = (float*)malloc(q->preamble_len*sizeof(float)); q->preamble_rx = (float*)malloc(q->preamble_len*sizeof(float)); float complex preamble_samples[q->preamble_len*q->k]; msequence ms = msequence_create(6, 0x6d, 1); gmskmod mod = gmskmod_create(q->k, q->m, q->BT); for (i=0; ipreamble_len + q->m; i++) { unsigned char bit = msequence_advance(ms); // save p/n sequence if (i < q->preamble_len) q->preamble_pn[i] = bit ? 1.0f : -1.0f; // modulate/interpolate if (i < q->m) gmskmod_modulate(mod, bit, &preamble_samples[0]); else gmskmod_modulate(mod, bit, &preamble_samples[(i-q->m)*q->k]); } gmskmod_destroy(mod); msequence_destroy(ms); #if 0 // print sequence for (i=0; ipreamble_len*q->k; i++) printf("preamble(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(preamble_samples[i]), cimagf(preamble_samples[i])); #endif // create frame detector float threshold = 0.5f; // detection threshold float dphi_max = 0.05f; // maximum carrier offset allowable q->frame_detector = detector_cccf_create(preamble_samples, q->preamble_len*q->k, threshold, dphi_max); q->buffer = windowcf_create(q->k*(q->preamble_len+q->m)); // create symbol timing recovery filters q->npfb = 32; // number of filters in the bank q->mf = firpfb_rrrf_create_rnyquist( LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); q->dmf = firpfb_rrrf_create_drnyquist(LIQUID_FIRFILT_GMSKRX,q->npfb,q->k,q->m,q->BT); // create down-coverters for carrier phase tracking q->nco_coarse = nco_crcf_create(LIQUID_NCO); // create/allocate header objects/arrays q->header_mod = NULL; q->header_enc = NULL; q->header_dec = NULL; q->p_header = NULL; gmskframesync_set_header_len(q, GMSKFRAME_H_USER_DEFAULT); // create/allocate payload objects/arrays q->payload_dec_len = 1; q->check = LIQUID_CRC_32; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; q->p_payload = packetizer_create(q->payload_dec_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_dec = (unsigned char*) malloc(q->payload_dec_len*sizeof(unsigned char)); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); // reset synchronizer gmskframesync_reset(q); // reset global data counters gmskframesync_reset_framedatastats(q); // return synchronizer object return q; } // create GMSK frame synchronizer with default parameters (k=2, m=3, bt=0.5) // _callback : callback function // _userdata : user data pointer passed to callback function gmskframesync gmskframesync_create(framesync_callback _callback, void * _userdata) { return gmskframesync_create_set(2, 3, 0.5f, _callback, _userdata); } // destroy frame synchronizer object, freeing all internal memory int gmskframesync_destroy(gmskframesync _q) { // destroy synchronizer objects #if GMSKFRAMESYNC_PREFILTER iirfilt_crcf_destroy(_q->prefilter);// pre-demodulator filter #endif firpfb_rrrf_destroy(_q->mf); // matched filter firpfb_rrrf_destroy(_q->dmf); // derivative matched filter nco_crcf_destroy(_q->nco_coarse); // coarse NCO // preamble detector_cccf_destroy(_q->frame_detector); windowcf_destroy(_q->buffer); free(_q->preamble_pn); free(_q->preamble_rx); // header packetizer_destroy(_q->p_header); free(_q->header_mod); free(_q->header_enc); free(_q->header_dec); // payload packetizer_destroy(_q->p_payload); free(_q->payload_enc); free(_q->payload_dec); // free main object memory free(_q); return LIQUID_OK; } // print frame synchronizer object internals int gmskframesync_print(gmskframesync _q) { printf("\n"); return LIQUID_OK; } int gmskframesync_set_header_len(gmskframesync _q, unsigned int _len) { _q->header_user_len = _len; unsigned int header_dec_len = GMSKFRAME_H_DEC + _q->header_user_len; _q->header_dec = (unsigned char*)realloc(_q->header_dec, header_dec_len*sizeof(unsigned char)); if (_q->p_header) { packetizer_destroy(_q->p_header); } _q->p_header = packetizer_create(header_dec_len, GMSKFRAME_H_CRC, GMSKFRAME_H_FEC, LIQUID_FEC_NONE); _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header); _q->header_enc = (unsigned char*)realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char)); _q->header_mod_len = _q->header_enc_len * 8; _q->header_mod = (unsigned char*)realloc(_q->header_mod, _q->header_mod_len*sizeof(unsigned char)); return LIQUID_OK; } // reset frame synchronizer object int gmskframesync_reset(gmskframesync _q) { // reset state and counters _q->state = STATE_DETECTFRAME; _q->preamble_counter = 0; _q->header_counter = 0; _q->payload_counter = 0; // clear pre-demod buffer windowcf_reset(_q->buffer); // reset internal objects detector_cccf_reset(_q->frame_detector); // reset carrier recovery objects nco_crcf_reset(_q->nco_coarse); // reset sample state _q->x_prime = 0.0f; _q->fi_hat = 0.0f; // reset symbol timing recovery state firpfb_rrrf_reset(_q->mf); firpfb_rrrf_reset(_q->dmf); _q->pfb_q = 0.0f; // filtered error signal return LIQUID_OK; } int gmskframesync_is_frame_open(gmskframesync _q) { return (_q->state == STATE_DETECTFRAME) ? 0 : 1; } int gmskframesync_execute_sample(gmskframesync _q, float complex _x) { switch (_q->state) { case STATE_DETECTFRAME: return gmskframesync_execute_detectframe(_q, _x); case STATE_RXPREAMBLE: return gmskframesync_execute_rxpreamble (_q, _x); case STATE_RXHEADER: return gmskframesync_execute_rxheader (_q, _x); case STATE_RXPAYLOAD: return gmskframesync_execute_rxpayload (_q, _x); default:; } return liquid_error(LIQUID_EINT,"gmskframesync_execute_sample(), invalid internal state"); } // execute frame synchronizer // _q : frame synchronizer object // _x : input sample array [size: _n x 1] // _n : number of input samples int gmskframesync_execute(gmskframesync _q, float complex * _x, unsigned int _n) { // push through synchronizer unsigned int i; for (i=0; i<_n; i++) { float complex xf; // input sample #if GMSKFRAMESYNC_PREFILTER iirfilt_crcf_execute(_q->prefilter, _x[i], &xf); #else xf = _x[i]; #endif gmskframesync_execute_sample(_q, xf); } return LIQUID_OK; } // reset frame data statistics int gmskframesync_reset_framedatastats(gmskframesync _q) { return framedatastats_reset(&_q->framedatastats); } // retrieve frame data statistics framedatastats_s gmskframesync_get_framedatastats(gmskframesync _q) { return _q->framedatastats; } // DEPRECATED int gmskframesync_debug_enable(gmskframesync _q) { return LIQUID_OK; } // DEPRECATED int gmskframesync_debug_disable(gmskframesync _q) { return LIQUID_OK; } // DEPRECATED int gmskframesync_debug_print(gmskframesync _q, const char * _filename) { return LIQUID_OK; } // // internal methods // // update symbol synchronizer internal state (filtered error, index, etc.) // _q : frame synchronizer // _x : input sample // _y : output symbol int gmskframesync_update_symsync(gmskframesync _q, float _x, float * _y) { // push sample into filterbanks firpfb_rrrf_push(_q->mf, _x); firpfb_rrrf_push(_q->dmf, _x); // float mf_out = 0.0f; // matched-filter output float dmf_out = 0.0f; // derivatived matched-filter output int sample_available = 0; // compute output if timeout if (_q->pfb_timer <= 0) { sample_available = 1; // reset timer _q->pfb_timer = _q->k; // k samples/symbol firpfb_rrrf_execute(_q->mf, _q->pfb_index, &mf_out); firpfb_rrrf_execute(_q->dmf, _q->pfb_index, &dmf_out); // update filtered timing error // lo bandwidth parameters: {0.92, 1.20}, about 100 symbols settling time // med bandwidth parameters: {0.98, 0.20}, about 200 symbols settling time // hi bandwidth parameters: {0.99, 0.05}, about 500 symbols settling time _q->pfb_q = 0.99f*_q->pfb_q + 0.05f*crealf( conjf(mf_out)*dmf_out ); // accumulate error into soft filterbank value _q->pfb_soft += _q->pfb_q; // compute actual filterbank index _q->pfb_index = roundf(_q->pfb_soft); // constrain index to be in [0, npfb-1] while (_q->pfb_index < 0) { _q->pfb_index += _q->npfb; _q->pfb_soft += _q->npfb; // adjust pfb output timer _q->pfb_timer--; } while (_q->pfb_index > _q->npfb-1) { _q->pfb_index -= _q->npfb; _q->pfb_soft -= _q->npfb; // adjust pfb output timer _q->pfb_timer++; } //printf(" b/soft : %12.8f\n", _q->pfb_soft); } // decrement symbol timer _q->pfb_timer--; // set output and return *_y = mf_out / (float)(_q->k); return sample_available; } // push buffered p/n sequence through synchronizer int gmskframesync_pushpn(gmskframesync _q) { unsigned int i; // reset filterbanks firpfb_rrrf_reset(_q->mf); firpfb_rrrf_reset(_q->dmf); // read buffer float complex * rc; windowcf_read(_q->buffer, &rc); // compute delay and filterbank index // tau_hat < 0 : delay = 2*k*m-1, index = round( tau_hat *npfb), flag = 0 // tau_hat > 0 : delay = 2*k*m-2, index = round((1-tau_hat)*npfb), flag = 0 assert(_q->tau_hat < 0.5f && _q->tau_hat > -0.5f); unsigned int delay = 2*_q->k*_q->m - 1; // samples to buffer before computing output _q->pfb_soft = -_q->tau_hat*_q->npfb; _q->pfb_index = (int) roundf(_q->pfb_soft); while (_q->pfb_index < 0) { delay -= 1; _q->pfb_index += _q->npfb; _q->pfb_soft += _q->npfb; } _q->pfb_timer = 0; // set coarse carrier frequency offset nco_crcf_set_frequency(_q->nco_coarse, _q->dphi_hat); unsigned int buffer_len = (_q->preamble_len + _q->m) * _q->k; for (i=0; inco_coarse, rc[i], &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // push initial samples into filterbanks firpfb_rrrf_push(_q->mf, _q->fi_hat); firpfb_rrrf_push(_q->dmf, _q->fi_hat); } // set state (still need a few more samples before entire p/n // sequence has been received) _q->state = STATE_RXPREAMBLE; for (i=delay; ipreamble_len; i++) printf(" %3u : %12.8f : %12.8f\n", i, _q->preamble_pn[i], _q->preamble_rx[i]); #endif return LIQUID_OK; } // update instantaneous frequency estimate int gmskframesync_update_fi(gmskframesync _q, float complex _x) { // compute differential phase _q->fi_hat = cargf(conjf(_q->x_prime)*_x) * _q->k; // update internal state _q->x_prime = _x; return LIQUID_OK; } int gmskframesync_execute_detectframe(gmskframesync _q, float complex _x) { // push sample into pre-demod p/n sequence buffer windowcf_push(_q->buffer, _x); // push through pre-demod synchronizer int detected = detector_cccf_correlate(_q->frame_detector, _x, &_q->tau_hat, &_q->dphi_hat, &_q->gamma_hat); // check if frame has been detected if (detected) { //printf("***** frame detected! tau-hat:%8.4f, dphi-hat:%8.4f, gamma:%8.2f dB\n", // _q->tau_hat, _q->dphi_hat, 20*log10f(_q->gamma_hat)); // push buffered samples through synchronizer // NOTE: state will be updated to STATE_RXPREAMBLE internally gmskframesync_pushpn(_q); } return LIQUID_OK; } int gmskframesync_execute_rxpreamble(gmskframesync _q, float complex _x) { // validate input if (_q->preamble_counter == _q->preamble_len) return liquid_error(LIQUID_EINT,"gmskframesync_execute_rxpn(), p/n buffer already full!\n"); // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // save output in p/n symbols buffer _q->preamble_rx[ _q->preamble_counter ] = mf_out / (float)(_q->k); // update counter _q->preamble_counter++; if (_q->preamble_counter == _q->preamble_len) { gmskframesync_syncpn(_q); _q->state = STATE_RXHEADER; } } return LIQUID_OK; } int gmskframesync_execute_rxheader(gmskframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // demodulate unsigned char s = mf_out > 0.0f ? 1 : 0; // TODO: update evm // save bit in buffer _q->header_mod[_q->header_counter] = s; // increment header counter _q->header_counter++; if (_q->header_counter == _q->header_mod_len) { // decode header gmskframesync_decode_header(_q); // invoke callback if header is invalid _q->framedatastats.num_frames_detected++; if (!_q->header_valid && _q->callback != NULL) { // set framesyncstats internals _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.evm = 0.0f; _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framesyncstats.mod_bps = 1; _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; // invoke callback method _q->callback(_q->header_dec, _q->header_valid, NULL, 0, 0, _q->framesyncstats, _q->userdata); gmskframesync_reset(_q); } // reset if invalid if (!_q->header_valid) return gmskframesync_reset(_q); // update state _q->state = STATE_RXPAYLOAD; } } return LIQUID_OK; } int gmskframesync_execute_rxpayload(gmskframesync _q, float complex _x) { // mix signal down float complex y; nco_crcf_mix_down(_q->nco_coarse, _x, &y); nco_crcf_step(_q->nco_coarse); // update instantanenous frequency estimate gmskframesync_update_fi(_q, y); // update symbol synchronizer float mf_out = 0.0f; int sample_available = gmskframesync_update_symsync(_q, _q->fi_hat, &mf_out); // compute output if timeout if (sample_available) { // demodulate unsigned char s = mf_out > 0.0f ? 1 : 0; // TODO: update evm // save payload _q->payload_byte <<= 1; _q->payload_byte |= s ? 0x01 : 0x00; _q->payload_enc[_q->payload_counter/8] = _q->payload_byte; // increment counter _q->payload_counter++; if (_q->payload_counter == 8*_q->payload_enc_len) { // decode payload _q->payload_valid = packetizer_decode(_q->p_payload, _q->payload_enc, _q->payload_dec); // update statistics _q->framedatastats.num_headers_valid++; _q->framedatastats.num_payloads_valid += _q->payload_valid; _q->framedatastats.num_bytes_received += _q->payload_dec_len; // invoke callback if (_q->callback != NULL) { // set framesyncstats internals _q->framesyncstats.rssi = 20*log10f(_q->gamma_hat); _q->framesyncstats.evm = 0.0f; _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framesyncstats.mod_bps = 1; _q->framesyncstats.check = _q->check; _q->framesyncstats.fec0 = _q->fec0; _q->framesyncstats.fec1 = _q->fec1; // invoke callback method _q->callback(_q->header_dec, _q->header_valid, _q->payload_dec, _q->payload_dec_len, _q->payload_valid, _q->framesyncstats, _q->userdata); } // reset frame synchronizer gmskframesync_reset(_q); } } return LIQUID_OK; } // decode header and re-configure payload decoder int gmskframesync_decode_header(gmskframesync _q) { // pack each 1-bit header symbols into 8-bit bytes unsigned int num_written; liquid_pack_bytes(_q->header_mod, _q->header_mod_len, _q->header_enc, _q->header_enc_len, &num_written); assert(num_written==_q->header_enc_len); // unscramble data unscramble_data(_q->header_enc, _q->header_enc_len); // run packet decoder _q->header_valid = packetizer_decode(_q->p_header, _q->header_enc, _q->header_dec); if (!_q->header_valid) return LIQUID_OK; unsigned int n = _q->header_user_len; // first byte is for expansion/version validation if (_q->header_dec[n+0] != GMSKFRAME_VERSION) { liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid framing version (received %u, expected %u)", _q->header_dec[n+0], GMSKFRAME_VERSION); _q->header_valid = 0; return LIQUID_OK; } // strip off payload length unsigned int payload_dec_len = (_q->header_dec[n+1] << 8) | (_q->header_dec[n+2]); // strip off CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+3] // fec0 : least-significant 5 bits of [n+3] // fec1 : least-significant 5 bits of [n+4] unsigned int check = (_q->header_dec[n+3] >> 5 ) & 0x07; unsigned int fec0 = (_q->header_dec[n+3] ) & 0x1f; unsigned int fec1 = (_q->header_dec[n+4] ) & 0x1f; // validate properties if (check == LIQUID_CRC_UNKNOWN || check >= LIQUID_CRC_NUM_SCHEMES) { liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported crc: %u", check); check = LIQUID_CRC_UNKNOWN; _q->header_valid = 0; } if (fec0 >= LIQUID_FEC_NUM_SCHEMES) { liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported fec (inner): %u", fec0); fec0 = LIQUID_FEC_UNKNOWN; _q->header_valid = 0; } if (fec1 >= LIQUID_FEC_NUM_SCHEMES) { liquid_error(LIQUID_EICONFIG,"gmskframesync_decode_header(), invalid/unsupported fec (outer): %u", fec1); fec1 = LIQUID_FEC_UNKNOWN; _q->header_valid = 0; } // configure payload receiver if (_q->header_valid) { // set new packetizer properties _q->payload_dec_len = payload_dec_len; _q->check = check; _q->fec0 = fec0; _q->fec1 = fec1; // recreate packetizer object _q->p_payload = packetizer_recreate(_q->p_payload, _q->payload_dec_len, _q->check, _q->fec0, _q->fec1); // re-compute payload encoded message length _q->payload_enc_len = packetizer_get_enc_msg_len(_q->p_payload); // re-allocate buffers accordingly _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->payload_enc_len*sizeof(unsigned char)); _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, _q->payload_dec_len*sizeof(unsigned char)); } // return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/msource.proto.c000066400000000000000000000367131474751757600216170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Generic source generator // #include #include #include #include // internal structure struct MSOURCE(_s) { // internal sources QSOURCE() * sources; // array of sources unsigned int num_sources; // number of sources int id_counter; // qsource id counter // channelizer description unsigned int M; // channelizer size unsigned int m; // channelizer filter semi-length float as; // channelizer filter stop-band suppression (dB) firpfbch2_crcf ch; // analysis channelizer object // buffers float complex * buf_freq; // [size: M x 1] float complex * buf_time; // [size: M/2 x 1] unsigned int read_index; // output buffer read index unsigned int num_blocks; // output buffer read index // global counters unsigned long long num_samples; // total number of samples generated }; // // internal methods // // find index of qsource object by id within list, return -1 if not found int MSOURCE(_find)(MSOURCE() _q, int _id); // find qsource object by id within list, return NULL if not found QSOURCE() MSOURCE(_get_source)(MSOURCE() _q, int _id); // add source to list int MSOURCE(_add_source)(MSOURCE() _q, QSOURCE() _s); // generate samples internally int MSOURCE(_generate)(MSOURCE() _q); // create msource object MSOURCE() MSOURCE(_create)(unsigned int _M, unsigned int _m, float _as) { // validate input if (_M < 2) return liquid_error_config("msource%s_create(), number of subcarriers must be at least 2",EXTENSION); if (_M % 2) return liquid_error_config("msource%s_create(), number of subcarriers must be even",EXTENSION); if (_m==0) return liquid_error_config("msource%s_create(), filter semi-length must be greater than zero",EXTENSION); // allocate memory for main object MSOURCE() q = (MSOURCE()) malloc( sizeof(struct MSOURCE(_s)) ); // q->sources = NULL; q->num_sources = 0; q->id_counter = 0; q->M = _M; q->m = _m; q->as = _as; q->num_samples = 0; q->ch = firpfbch2_crcf_create_kaiser(LIQUID_SYNTHESIZER, q->M, q->m, q->as); q->buf_freq = (float complex*) malloc(q->M * sizeof(float complex)); q->buf_time = (float complex*) malloc(q->M/2 * sizeof(float complex)); q->read_index = q->M/2; // indicate buffer is empty q->num_blocks = 0; // reset and return main object MSOURCE(_reset)(q); return q; } // create msource object with default parameters MSOURCE() MSOURCE(_create_default)(void) { return MSOURCE(_create)(1200, 4, 60); } // copy object MSOURCE() MSOURCE(_copy)(MSOURCE() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("msource%s_copy(), object cannot be NULL", EXTENSION); // create filter object and copy base parameters MSOURCE() q_copy = (MSOURCE()) malloc(sizeof(struct MSOURCE(_s))); memmove(q_copy, q_orig, sizeof(struct MSOURCE(_s))); // copy signal sources q_copy->sources = (QSOURCE()*) malloc(q_orig->num_sources*sizeof(QSOURCE())); unsigned int i; for (i=0; inum_sources; i++) q_copy->sources[i] = QSOURCE(_copy)(q_orig->sources[i]); // copy synthesis channelizer q_copy->ch = firpfbch2_crcf_copy(q_orig->ch); // copy buffers q_copy->buf_freq = (float complex *) liquid_malloc_copy(q_orig->buf_freq, q_orig->M, sizeof(float complex)); q_copy->buf_time = (float complex *) liquid_malloc_copy(q_orig->buf_time, q_orig->M/2, sizeof(float complex)); return q_copy; } // destroy msource object, freeing all internal memory int MSOURCE(_destroy)(MSOURCE() _q) { // destroy internal objects unsigned int i; for (i=0; i<_q->num_sources; i++) QSOURCE(_destroy)(_q->sources[i]); // free list of sources free(_q->sources); // destroy channelizer firpfbch2_crcf_destroy(_q->ch); // free buffers free(_q->buf_freq); free(_q->buf_time); // free main object free(_q); return LIQUID_OK; } // reset msource internal state int MSOURCE(_reset)(MSOURCE() _q) { // reset all internal objects _q->read_index = _q->M/2; return LIQUID_OK; } // print int MSOURCE(_print)(MSOURCE() _q) { printf("\n", EXTENSION, _q->M, _q->m, _q->as, _q->num_samples); #if 0 unsigned int i; for (i=0; i<_q->num_sources; i++) QSOURCE(_print)(_q->sources[i]); #endif return LIQUID_OK; } // add user-defined source int MSOURCE(_add_user)(MSOURCE() _q, float _fc, float _bw, float _gain, void * _userdata, MSOURCE(_callback) _callback) { QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, _bw, _gain); QSOURCE(_init_user)(s, _userdata, (void*)_callback); return MSOURCE(_add_source)(_q, s); } // add tone source int MSOURCE(_add_tone)(MSOURCE() _q, float _fc, float _bw, float _gain) { QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, _bw, _gain); QSOURCE(_init_tone)(s); return MSOURCE(_add_source)(_q, s); } // add chirp source int MSOURCE(_add_chirp)(MSOURCE() _q, float _fc, float _bw, float _gain, float _duration, int _negate, int _single) { QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, _bw, _gain); QSOURCE(_init_chirp)(s, _duration, _negate, _single); return MSOURCE(_add_source)(_q, s); } // add noise source int MSOURCE(_add_noise)(MSOURCE() _q, float _fc, float _bw, float _gain) { QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, _bw, _gain); QSOURCE(_init_noise)(s); return MSOURCE(_add_source)(_q, s); } // add linear modem source int MSOURCE(_add_modem)(MSOURCE() _q, float _fc, float _bw, float _gain, int _ms, unsigned int _m, float _beta) { // create object with double the bandwidth to account for 2 samples/symbol QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, 2*_bw, _gain); QSOURCE(_init_modem)(s, _ms, _m, _beta); return MSOURCE(_add_source)(_q, s); } // add frequency-shift keying modem source int MSOURCE(_add_fsk)(MSOURCE() _q, float _fc, float _bw, float _gain, unsigned int _m, unsigned int _k) { // create object with double the bandwidth to account for 2 samples/symbol QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, 2*_bw, _gain); QSOURCE(_init_fsk)(s, _m, _k); return MSOURCE(_add_source)(_q, s); } // add GMSK modem source int MSOURCE(_add_gmsk)(MSOURCE() _q, float _fc, float _bw, float _gain, unsigned int _m, float _bt) { // create object with double the bandwidth to account for 2 samples/symbol QSOURCE() s = QSOURCE(_create)(_q->M, _q->m, _q->as, _fc, 2*_bw, _gain); QSOURCE(_init_gmsk)(s, _m, _bt); return MSOURCE(_add_source)(_q, s); } // remove signal int MSOURCE(_remove)(MSOURCE() _q, int _id) { // find source object matching id unsigned int i; int id_found = 0; for (i=0; i<_q->num_sources; i++) { if (QSOURCE(_get_id)(_q->sources[i]) == _id) { id_found = 1; break; } } // check to see if id was found if (!id_found) return liquid_error(LIQUID_EIRANGE,"msource%s_remove(), signal id (%d) not found",EXTENSION,_id); // delete source QSOURCE(_destroy)(_q->sources[i]); // _q->num_sources--; // shift sources down for (; i<_q->num_sources; i++) _q->sources[i] = _q->sources[i+1]; return LIQUID_OK; } // enable/disable signal int MSOURCE(_enable)(MSOURCE() _q, int _id) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_enable(), could not find source with id %u",EXTENSION,_id); // set source gain return QSOURCE(_enable)(source); } int MSOURCE(_disable)(MSOURCE() _q, int _id) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_disable(), could not find source with id %u",EXTENSION,_id); // set source gain return QSOURCE(_disable)(source); } // Get number of samples generated by the object so far unsigned long long int MSOURCE(_get_num_samples)(MSOURCE() _q) { return _q->num_samples; } // Get number of samples generated by specific source so far int MSOURCE(_get_num_samples_source)(MSOURCE() _q, int _id, unsigned long int * _num_samples) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_get_num_samples_source(), could not find source with id %u",EXTENSION,_id); *_num_samples = QSOURCE(_get_num_samples)(source); return LIQUID_OK; } // set signal gain // _q : msource object // _id : source id // _gain_dB: signal gain in dB int MSOURCE(_set_gain)(MSOURCE() _q, int _id, float _gain_dB) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_set_gain(), could not find source with id %u",EXTENSION,_id); // set source gain return QSOURCE(_set_gain)(source, _gain_dB); } // set signal gain // _q : msource object // _id : source id // _gain_dB: signal gain in dB int MSOURCE(_get_gain)(MSOURCE() _q, int _id, float * _gain_dB) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_get_gain(), could not find source with id %u",EXTENSION,_id); // set source gain *_gain_dB = QSOURCE(_get_gain)(source); return LIQUID_OK; } // set carrier offset to signal // _q : msource object // _id : source id // _fc : carrier offset, fc in [-0.5,0.5] int MSOURCE(_set_frequency)(MSOURCE() _q, int _id, float _dphi) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_set_frequency(), could not find source with id %u",EXTENSION,_id); // set source frequency return QSOURCE(_set_frequency)(source, _dphi); } // set carrier offset to signal // _q : msource object // _id : source id // _fc : carrier offset, fc in [-0.5,0.5] int MSOURCE(_get_frequency)(MSOURCE() _q, int _id, float * _dphi) { QSOURCE() source = MSOURCE(_get_source)(_q, _id); if (source == NULL) return liquid_error(LIQUID_EIRANGE,"msource%s_get_frequency(), could not find source with id %u",EXTENSION,_id); // set source frequency *_dphi = QSOURCE(_get_frequency)(source); return LIQUID_OK; } // write block of samples to output buffer // _q : synchronizer object // _buf : output buffer [size: _buf_len x 1] // _buf_len: output buffer size int MSOURCE(_write_samples)(MSOURCE() _q, TO * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // generate more samples if needed if (_q->read_index >= _q->M/2) { MSOURCE(_generate)(_q); } // write output sample and update counter _buf[i] = _q->buf_time[_q->read_index++]; } return LIQUID_OK; } // // internal msource methods // // find qsource object by id within list, return -1 if not found int MSOURCE(_find)(MSOURCE() _q, int _id) { unsigned int i; for (i=0; i<_q->num_sources; i++) { if (QSOURCE(_get_id)(_q->sources[i]) == _id) return (int)i; } return -1; } // get source by id QSOURCE() MSOURCE(_get_source)(MSOURCE() _q, int _id) { int index = MSOURCE(_find)(_q, _id); if (index < 0) return liquid_error_config("msource%s_get_source(), could not find source with id %u",EXTENSION,_id); return _q->sources[index]; } // add source to list int MSOURCE(_add_source)(MSOURCE() _q, QSOURCE() _s) { if (_s == NULL) return -1; // reallocate if (_q->num_sources == 0) { _q->sources = (QSOURCE()*) malloc(sizeof(QSOURCE())); } else { _q->sources = (QSOURCE()*) realloc(_q->sources, (_q->num_sources+1)*sizeof(QSOURCE())); } // append new object to end of list _q->sources[_q->num_sources] = _s; _q->num_sources++; // set id and increment internal counter int id = _q->id_counter; QSOURCE(_set_id)(_s, id); _q->id_counter++; // return id to user return id; } // generate samples internally int MSOURCE(_generate)(MSOURCE() _q) { // clear buffer memset(_q->buf_freq, 0, _q->M*sizeof(float complex)); // add sources into main frequency buffer unsigned int i; for (i=0; i<_q->num_sources; i++) QSOURCE(_generate_into)(_q->sources[i], _q->buf_freq); // run synthesis channelizer firpfbch2_crcf_execute(_q->ch, _q->buf_freq, _q->buf_time); // update state _q->read_index = 0; _q->num_blocks++; _q->num_samples += _q->M / 2; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/ofdmflexframegen.c000066400000000000000000000646541474751757600223160ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // OFDM flexible frame generator #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_OFDMFLEXFRAMEGEN 0 // reconfigure internal buffers, objects, etc. int ofdmflexframegen_reconfigure(ofdmflexframegen _q); // encode header int ofdmflexframegen_encode_header(ofdmflexframegen _q); // modulate header int ofdmflexframegen_modulate_header(ofdmflexframegen _q); // generate samples of assembled frame (internally) int ofdmflexframegen_gen_symbol (ofdmflexframegen _q); // (generic) int ofdmflexframegen_gen_S0a (ofdmflexframegen _q); // generate S0 symbol (first) int ofdmflexframegen_gen_S0b (ofdmflexframegen _q); // generate S0 symbol (second) int ofdmflexframegen_gen_S1 (ofdmflexframegen _q); // generate S1 symbol int ofdmflexframegen_gen_header (ofdmflexframegen _q); // generate header symbol int ofdmflexframegen_gen_payload(ofdmflexframegen _q); // generate payload symbol int ofdmflexframegen_gen_tail (ofdmflexframegen _q); // generate tail symbol int ofdmflexframegen_gen_zeros (ofdmflexframegen _q); // generate zeros // default ofdmflexframegen properties static ofdmflexframegenprops_s ofdmflexframegenprops_default = { LIQUID_CRC_32, // check LIQUID_FEC_NONE, // fec0 LIQUID_FEC_NONE, // fec1 LIQUID_MODEM_QPSK, // mod_scheme //64 // block_size }; static ofdmflexframegenprops_s ofdmflexframegenprops_header_default = { OFDMFLEXFRAME_H_CRC, OFDMFLEXFRAME_H_FEC0, OFDMFLEXFRAME_H_FEC1, OFDMFLEXFRAME_H_MOD, }; int ofdmflexframegenprops_init_default(ofdmflexframegenprops_s * _props) { memmove(_props, &ofdmflexframegenprops_default, sizeof(ofdmflexframegenprops_s)); return LIQUID_OK; } struct ofdmflexframegen_s { unsigned int M; // number of subcarriers unsigned int cp_len; // cyclic prefix length unsigned int taper_len; // taper length unsigned char * p; // subcarrier allocation (null, pilot, data) // constants unsigned int M_null; // number of null subcarriers unsigned int M_pilot; // number of pilot subcarriers unsigned int M_data; // number of data subcarriers unsigned int M_S0; // number of enabled subcarriers in S0 unsigned int M_S1; // number of enabled subcarriers in S1 unsigned int frame_len; // frame length (M + cp_len) // buffers float complex * X; // frequency-domain buffer float complex * buf_tx; // transmit buffer unsigned int buf_index; // buffer index // internal low-level objects ofdmframegen fg; // frame generator object // options/derived lengths unsigned int num_symbols_header; // number of header OFDM symbols unsigned int num_symbols_payload; // number of payload OFDM symbols // header modemcf mod_header; // header modulator packetizer p_header; // header packetizer unsigned char * header; // header data (uncoded) unsigned char * header_enc; // header data (encoded) unsigned char * header_mod; // header symbols unsigned int header_user_len; // header length (user) unsigned int header_dec_len; // header length (decoded) unsigned int header_enc_len; // header length (encoded) unsigned int header_sym_len; // header length (mod symbols) // payload packetizer p_payload; // payload packetizer unsigned int payload_dec_len; // payload length (num un-encoded bytes) modemcf mod_payload; // payload modulator unsigned char * payload_enc; // payload data (encoded bytes) unsigned char * payload_mod; // payload data (modulated symbols) unsigned int payload_enc_len; // length of encoded payload unsigned int payload_mod_len; // number of modulated symbols in payload // counters/states unsigned int symbol_number; // output symbol number enum { OFDMFLEXFRAMEGEN_STATE_S0a=0, // write S0 symbol (first) OFDMFLEXFRAMEGEN_STATE_S0b, // write S0 symbol (second) OFDMFLEXFRAMEGEN_STATE_S1, // write S1 symbol OFDMFLEXFRAMEGEN_STATE_HEADER, // write header symbols OFDMFLEXFRAMEGEN_STATE_PAYLOAD, // write payload symbols OFDMFLEXFRAMEGEN_STATE_TAIL, // write tail of last symbol OFDMFLEXFRAMEGEN_STATE_ZEROS // write zeros } state; int frame_assembled; // frame assembled flag int frame_complete; // frame completed flag unsigned int header_symbol_index; // unsigned int payload_symbol_index; // // properties ofdmflexframegenprops_s props; ofdmflexframegenprops_s header_props; }; // create OFDM flexible framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _fgprops : frame properties (modulation scheme, etc.) ofdmflexframegen ofdmflexframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmflexframegenprops_s * _fgprops) { // validate input if (_M < 8) return liquid_error_config("ofdmflexframegen_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmflexframegen_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmflexframegen_create(), cyclic prefix length cannot exceed number of subcarriers"); ofdmflexframegen q = (ofdmflexframegen) malloc(sizeof(struct ofdmflexframegen_s)); q->M = _M; // number of subcarriers q->cp_len = _cp_len; // cyclic prefix length q->taper_len = _taper_len; // taper length // allocate memory for transform buffers q->frame_len = q->M + q->cp_len; // frame length q->X = (float complex*) malloc((q->M )*sizeof(float complex)); q->buf_tx = (float complex*) malloc((q->frame_len)*sizeof(float complex)); q->buf_index = q->frame_len; // allocate memory for subcarrier allocation IDs q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { // initialize default subcarrier allocation ofdmframe_init_default_sctype(q->M, q->p); } else { // copy user-defined subcarrier allocation memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); // create internal OFDM frame generator object q->fg = ofdmframegen_create(q->M, q->cp_len, q->taper_len, q->p); // create header objects q->header = NULL; q->p_header = NULL; q->header_enc = NULL; q->header_mod = NULL; q->mod_header = NULL; q->header_user_len = OFDMFLEXFRAME_H_USER_DEFAULT; ofdmflexframegen_set_header_props(q, NULL); // initial memory allocation for payload q->payload_dec_len = 1; q->p_payload = packetizer_create(q->payload_dec_len, LIQUID_CRC_NONE, LIQUID_FEC_NONE, LIQUID_FEC_NONE); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_mod_len = 1; q->payload_mod = (unsigned char*) malloc(q->payload_mod_len*sizeof(unsigned char)); // create payload modem (initially QPSK, overridden by properties) q->mod_payload = modemcf_create(LIQUID_MODEM_QPSK); // initialize properties ofdmflexframegen_setprops(q, _fgprops); // reset ofdmflexframegen_reset(q); // return pointer to main object return q; } int ofdmflexframegen_destroy(ofdmflexframegen _q) { // destroy internal objects ofdmframegen_destroy(_q->fg); // OFDM frame generator packetizer_destroy(_q->p_header); // header packetizer modemcf_destroy(_q->mod_header); // header modulator packetizer_destroy(_q->p_payload); // payload packetizer modemcf_destroy(_q->mod_payload); // payload modulator // free buffers/arrays free(_q->payload_enc); // encoded payload bytes free(_q->payload_mod); // modulated payload symbols free(_q->X); // frequency-domain buffer free(_q->buf_tx); // transmit buffer free(_q->p); // subcarrier allocation free(_q->header); // decoded header free(_q->header_enc); // encoded header free(_q->header_mod); // modulated header // free main object memory free(_q); return LIQUID_OK; } int ofdmflexframegen_reset(ofdmflexframegen _q) { // reset symbol counter and state _q->symbol_number = 0; _q->state = OFDMFLEXFRAMEGEN_STATE_S0a; _q->frame_assembled = 0; _q->frame_complete = 0; _q->header_symbol_index = 0; _q->payload_symbol_index = 0; _q->buf_index = _q->frame_len; // reset internal OFDM frame generator object // NOTE: this is important for appropriately setting the pilot phases return ofdmframegen_reset(_q->fg); } // is frame assembled? int ofdmflexframegen_is_assembled(ofdmflexframegen _q) { return _q->frame_assembled; } int ofdmflexframegen_print(ofdmflexframegen _q) { printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); printf(", data=%u", _q->M_data); printf(", cp=%u", _q->cp_len); printf(", taper=%u", _q->taper_len); printf(">\n"); return LIQUID_OK; } // get ofdmflexframegen properties // _q : frame generator object // _props : frame generator properties structure pointer int ofdmflexframegen_getprops(ofdmflexframegen _q, ofdmflexframegenprops_s * _props) { // copy properties structure to output pointer memmove(_props, &_q->props, sizeof(ofdmflexframegenprops_s)); return LIQUID_OK; } int ofdmflexframegen_setprops(ofdmflexframegen _q, ofdmflexframegenprops_s * _props) { // if properties object is NULL, initialize with defaults if (_props == NULL) return ofdmflexframegen_setprops(_q, &ofdmflexframegenprops_default); // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported FEC scheme"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported modulation scheme"); // TODO : determine if re-configuration is necessary // copy properties to internal structure memmove(&_q->props, _props, sizeof(ofdmflexframegenprops_s)); // reconfigure internal buffers, objects, etc. return ofdmflexframegen_reconfigure(_q); } int ofdmflexframegen_set_header_len(ofdmflexframegen _q, unsigned int _len) { _q->header_user_len = _len; _q->header_dec_len = OFDMFLEXFRAME_H_DEC + _q->header_user_len; _q->header = realloc(_q->header, _q->header_dec_len*sizeof(unsigned char)); if (_q->p_header) { packetizer_destroy(_q->p_header); } _q->p_header = packetizer_create(_q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1); _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header); _q->header_enc = realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char)); unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps; div_t bps_d = div(_q->header_enc_len*8, bps); _q->header_sym_len = bps_d.quot + (bps_d.rem ? 1 : 0); _q->header_mod = realloc(_q->header_mod, _q->header_sym_len*sizeof(unsigned char)); // create header objects if (_q->mod_header) { modemcf_destroy(_q->mod_header); } _q->mod_header = modemcf_create(_q->header_props.mod_scheme); // compute number of header symbols div_t d = div(_q->header_sym_len, _q->M_data); _q->num_symbols_header = d.quot + (d.rem ? 1 : 0); return LIQUID_OK; } int ofdmflexframegen_set_header_props(ofdmflexframegen _q, ofdmflexframegenprops_s * _props) { // if properties object is NULL, initialize with defaults if (_props == NULL) { _props = &ofdmflexframegenprops_header_default; } // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported FEC scheme"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EICONFIG,"ofdmflexframegen_setprops(), invalid/unsupported modulation scheme"); // copy properties to internal structure memmove(&_q->header_props, _props, sizeof(ofdmflexframegenprops_s)); // reconfigure internal buffers, objects, etc. return ofdmflexframegen_set_header_len(_q, _q->header_user_len); } // get length of frame (symbols) // _q : OFDM frame generator object unsigned int ofdmflexframegen_getframelen(ofdmflexframegen _q) { // number of S0 symbols (2) // number of S1 symbols (1) // number of header symbols // number of payload symbols return 2 + // S0 symbols 1 + // S1 symbol _q->num_symbols_header + _q->num_symbols_payload; } // assemble a frame from an array of data (NULL pointers will use random data) // _q : OFDM frame generator object // _header : frame header // _payload : payload data [size: _payload_len x 1] // _payload_len : payload data length int ofdmflexframegen_assemble(ofdmflexframegen _q, const unsigned char * _header, const unsigned char * _payload, unsigned int _payload_len) { // reset state ofdmflexframegen_reset(_q); // check payload length and reconfigure if necessary if (_payload_len != _q->payload_dec_len) { _q->payload_dec_len = _payload_len; ofdmflexframegen_reconfigure(_q); } // set assembled flag _q->frame_assembled = 1; // copy user-defined header data if (_header == NULL) memset(_q->header, 0x00, _q->header_user_len*sizeof(unsigned char)); else memmove(_q->header, _header, _q->header_user_len*sizeof(unsigned char)); // encode full header ofdmflexframegen_encode_header(_q); // modulate header ofdmflexframegen_modulate_header(_q); // encode payload packetizer_encode(_q->p_payload, _payload, _q->payload_enc); // // pack modem symbols // // clear payload memset(_q->payload_mod, 0x00, _q->payload_mod_len); // repack 8-bit payload bytes into 'bps'-bit payload symbols unsigned int bps = modulation_types[_q->props.mod_scheme].bps; unsigned int num_written; liquid_repack_bytes(_q->payload_enc, 8, _q->payload_enc_len, _q->payload_mod, bps, _q->payload_mod_len, &num_written); #if DEBUG_OFDMFLEXFRAMEGEN printf("wrote %u symbols (expected %u)\n", num_written, _q->payload_mod_len); #endif return LIQUID_OK; } // write samples of assembled frame // _q : OFDM frame generator object // _buf : output buffer [size: _buf_len x 1] // _buf_len : output buffer length int ofdmflexframegen_write(ofdmflexframegen _q, float complex * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { if (_q->buf_index >= _q->frame_len) { ofdmflexframegen_gen_symbol(_q); _q->buf_index = 0; } // TODO: write samples appropriately _buf[i] = _q->buf_tx[_q->buf_index++]; } return _q->frame_complete; } // // internal // // reconfigure internal buffers, objects, etc. int ofdmflexframegen_reconfigure(ofdmflexframegen _q) { // re-create payload packetizer _q->p_payload = packetizer_recreate(_q->p_payload, _q->payload_dec_len, _q->props.check, _q->props.fec0, _q->props.fec1); // re-allocate memory for encoded message _q->payload_enc_len = packetizer_get_enc_msg_len(_q->p_payload); _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->payload_enc_len*sizeof(unsigned char)); #if DEBUG_OFDMFLEXFRAMEGEN //printf(">>>> payload : %u (%u encoded)\n", _q->props.payload_len, _q->payload_enc_len); #endif // re-create modem // TODO : only do this if necessary _q->mod_payload = modemcf_recreate(_q->mod_payload, _q->props.mod_scheme); // re-allocate memory for payload modem symbols unsigned int bps = modulation_types[_q->props.mod_scheme].bps; div_t d = div(8*_q->payload_enc_len, bps); _q->payload_mod_len = d.quot + (d.rem ? 1 : 0); _q->payload_mod = (unsigned char*)realloc(_q->payload_mod, _q->payload_mod_len*sizeof(unsigned char)); // re-compute number of payload OFDM symbols d = div(_q->payload_mod_len, _q->M_data); _q->num_symbols_payload = d.quot + (d.rem ? 1 : 0); return LIQUID_OK; } // encode header int ofdmflexframegen_encode_header(ofdmflexframegen _q) { // first 'n' bytes user data unsigned int n = _q->header_user_len; // first byte is for expansion/version validation _q->header[n+0] = OFDMFLEXFRAME_PROTOCOL; // add payload length _q->header[n+1] = (_q->payload_dec_len >> 8) & 0xff; _q->header[n+2] = (_q->payload_dec_len ) & 0xff; // add modulation scheme/depth (pack into single byte) _q->header[n+3] = _q->props.mod_scheme; // add CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] _q->header[n+4] = (_q->props.check & 0x07) << 5; _q->header[n+4] |= (_q->props.fec0) & 0x1f; _q->header[n+5] = (_q->props.fec1) & 0x1f; // run packet encoder packetizer_encode(_q->p_header, _q->header, _q->header_enc); // scramble header scramble_data(_q->header_enc, _q->header_enc_len); #if 0 // print header (decoded) unsigned int i; printf("header tx (dec) : "); for (i=0; iheader[i]); printf("\n"); // print header (encoded) printf("header tx (enc) : "); for (i=0; iheader_enc[i]); printf("\n"); #endif return LIQUID_OK; } // modulate header int ofdmflexframegen_modulate_header(ofdmflexframegen _q) { // repack 8-bit header bytes into 'bps'-bit payload symbols unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps; unsigned int num_written; liquid_repack_bytes(_q->header_enc, 8, _q->header_enc_len, _q->header_mod, bps, _q->header_sym_len, &num_written); return LIQUID_OK; } // generate transmit samples (fill internal buffer) int ofdmflexframegen_gen_symbol(ofdmflexframegen _q) { // increment symbol counter _q->symbol_number++; switch (_q->state) { case OFDMFLEXFRAMEGEN_STATE_S0a: return ofdmflexframegen_gen_S0a (_q); case OFDMFLEXFRAMEGEN_STATE_S0b: return ofdmflexframegen_gen_S0b (_q); case OFDMFLEXFRAMEGEN_STATE_S1: return ofdmflexframegen_gen_S1 (_q); case OFDMFLEXFRAMEGEN_STATE_HEADER: return ofdmflexframegen_gen_header (_q); case OFDMFLEXFRAMEGEN_STATE_PAYLOAD: return ofdmflexframegen_gen_payload(_q); case OFDMFLEXFRAMEGEN_STATE_TAIL: return ofdmflexframegen_gen_tail (_q); case OFDMFLEXFRAMEGEN_STATE_ZEROS: return ofdmflexframegen_gen_zeros (_q); default:; } return liquid_error(LIQUID_EINT,"ofdmflexframegen_writesymbol(), invalid internal state"); } // write first S0 symbol int ofdmflexframegen_gen_S0a(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing S0[a] symbol\n"); #endif // write S0 symbol into front of buffer ofdmframegen_write_S0a(_q->fg, _q->buf_tx); // update state _q->state = OFDMFLEXFRAMEGEN_STATE_S0b; return LIQUID_OK; } // write second S0 symbol int ofdmflexframegen_gen_S0b(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing S0[b] symbol\n"); #endif // write S0 symbol into front of buffer ofdmframegen_write_S0b(_q->fg, _q->buf_tx); // update state _q->state = OFDMFLEXFRAMEGEN_STATE_S1; return LIQUID_OK; } // write S1 symbol int ofdmflexframegen_gen_S1(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing S1 symbol\n"); #endif // write S1 symbol into end of buffer ofdmframegen_write_S1(_q->fg, _q->buf_tx); // update state _q->symbol_number = 0; _q->state = OFDMFLEXFRAMEGEN_STATE_HEADER; return LIQUID_OK; } // write header symbol int ofdmflexframegen_gen_header(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing header symbol\n"); #endif // load data onto data subcarriers unsigned int i; int sctype; for (i=0; i<_q->M; i++) { // sctype = _q->p[i]; // if (sctype == OFDMFRAME_SCTYPE_DATA) { // load... if (_q->header_symbol_index < _q->header_sym_len) { // modulate header symbol onto data subcarrier modemcf_modulate(_q->mod_header, _q->header_mod[_q->header_symbol_index++], &_q->X[i]); //printf(" writing symbol %3u / %3u (x = %8.5f + j%8.5f)\n", _q->header_symbol_index, OFDMFLEXFRAME_H_SYM, crealf(_q->X[i]), cimagf(_q->X[i])); } else { //printf(" random header symbol\n"); // load random symbol unsigned int sym = modemcf_gen_rand_sym(_q->mod_header); modemcf_modulate(_q->mod_header, sym, &_q->X[i]); } } else { // ignore subcarrier (ofdmframegen handles nulls and pilots) _q->X[i] = 0.0f; } } // write symbol ofdmframegen_writesymbol(_q->fg, _q->X, _q->buf_tx); // check state if (_q->symbol_number == _q->num_symbols_header) { _q->symbol_number = 0; _q->state = OFDMFLEXFRAMEGEN_STATE_PAYLOAD; } return LIQUID_OK; } // write payload symbol int ofdmflexframegen_gen_payload(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing payload symbol\n"); #endif // load data onto data subcarriers unsigned int i; int sctype; for (i=0; i<_q->M; i++) { // sctype = _q->p[i]; // if (sctype == OFDMFRAME_SCTYPE_DATA) { // load... if (_q->payload_symbol_index < _q->payload_mod_len) { // modulate payload symbol onto data subcarrier modemcf_modulate(_q->mod_payload, _q->payload_mod[_q->payload_symbol_index++], &_q->X[i]); } else { //printf(" random payload symbol\n"); // load random symbol unsigned int sym = modemcf_gen_rand_sym(_q->mod_payload); modemcf_modulate(_q->mod_payload, sym, &_q->X[i]); } } else { // ignore subcarrier (ofdmframegen handles nulls and pilots) _q->X[i] = 0.0f; } } // write symbol ofdmframegen_writesymbol(_q->fg, _q->X, _q->buf_tx); // check to see if this is the last symbol in the payload if (_q->symbol_number == _q->num_symbols_payload) _q->state = OFDMFLEXFRAMEGEN_STATE_TAIL; return LIQUID_OK; } // generate buffer of zeros int ofdmflexframegen_gen_tail(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing tail\n"); #endif // initialize buffer with zeros unsigned int i; for (i=0; i<_q->frame_len; i++) _q->buf_tx[i] = 0.0f; // write taper_len samples to buffer ofdmframegen_writetail(_q->fg, _q->buf_tx); // mark frame as complete _q->frame_complete = 1; _q->frame_assembled = 0; _q->state = OFDMFLEXFRAMEGEN_STATE_ZEROS; return LIQUID_OK; } // generate buffer of zeros int ofdmflexframegen_gen_zeros(ofdmflexframegen _q) { #if DEBUG_OFDMFLEXFRAMEGEN printf("writing zeros\n"); #endif memset(_q->buf_tx, 0x00, (_q->frame_len)*sizeof(float complex)); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/ofdmflexframesync.c000066400000000000000000000715241474751757600225130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // OFDM frame synchronizer #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_OFDMFLEXFRAMESYNC 0 #define OFDMFLEXFRAME_P_SOFT (1) // // ofdmflexframesync // // internal callback int ofdmflexframesync_internal_callback(float complex * _X, unsigned char * _p, unsigned int _M, void * _userdata); // receive header data int ofdmflexframesync_rxheader(ofdmflexframesync _q, float complex * _X); // decode header int ofdmflexframesync_decode_header(ofdmflexframesync _q); // receive payload data int ofdmflexframesync_rxpayload(ofdmflexframesync _q, float complex * _X); static ofdmflexframegenprops_s ofdmflexframesyncprops_header_default = { OFDMFLEXFRAME_H_CRC, OFDMFLEXFRAME_H_FEC0, OFDMFLEXFRAME_H_FEC1, OFDMFLEXFRAME_H_MOD, }; struct ofdmflexframesync_s { unsigned int M; // number of subcarriers unsigned int cp_len; // cyclic prefix length unsigned int taper_len; // taper length unsigned char * p; // subcarrier allocation (null, pilot, data) // constants unsigned int M_null; // number of null subcarriers unsigned int M_pilot; // number of pilot subcarriers unsigned int M_data; // number of data subcarriers unsigned int M_S0; // number of enabled subcarriers in S0 unsigned int M_S1; // number of enabled subcarriers in S1 // header int header_soft; // perform soft demod of header modemcf mod_header; // header modulator packetizer p_header; // header packetizer unsigned char * header; // header data (uncoded) unsigned char * header_enc; // header data (encoded) unsigned char * header_mod; // header symbols unsigned int header_user_len; // header length (user) unsigned int header_dec_len; // header length (uncoded) unsigned int header_enc_len; // header length (encoded) unsigned int header_sym_len; // header length (symbols) int header_valid; // valid header flag ofdmflexframegenprops_s header_props; // header properties // header properties modulation_scheme ms_payload; // payload modulation scheme unsigned int bps_payload; // payload modulation depth (bits/symbol) unsigned int payload_len; // payload length (number of bytes) crc_scheme check; // payload validity check fec_scheme fec0; // payload FEC (inner) fec_scheme fec1; // payload FEC (outer) // payload int payload_soft; // perform soft demod of payload packetizer p_payload; // payload packetizer modemcf mod_payload; // payload demodulator unsigned char * payload_enc; // payload data (encoded bytes) unsigned char * payload_dec; // payload data (decoded bytes) unsigned int payload_enc_len; // length of encoded payload unsigned int payload_mod_len; // number of payload modem symbols int payload_valid; // valid payload flag float complex * payload_syms; // received payload symbols // callback framesync_callback callback; // user-defined callback function void * userdata; // user-defined data structure framesyncstats_s framesyncstats; // frame statistic object (synchronizer, evm, etc.) framedatastats_s framedatastats; // frame statistic object (packet statistics) float evm_hat; // average error vector magnitude // internal synchronizer objects ofdmframesync fs; // internal OFDM frame synchronizer // counters/states unsigned int symbol_counter; // received symbol number enum { OFDMFLEXFRAMESYNC_STATE_HEADER, // extract header OFDMFLEXFRAMESYNC_STATE_PAYLOAD // extract payload symbols } state; unsigned int header_symbol_index; // number of header symbols received unsigned int payload_symbol_index; // number of payload symbols received unsigned int payload_buffer_index; // bit-level index of payload (pack array) }; // create ofdmflexframesync object // _M : number of subcarriers // _cp_len : length of cyclic prefix [samples] // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (PILOT/NULL/DATA) [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data structure passed to callback ofdmflexframesync ofdmflexframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, framesync_callback _callback, void * _userdata) { // validate input if (_M < 8) return liquid_error_config("ofdmflexframesync_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmflexframesync_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmflexframesync_create(), cyclic prefix length cannot exceed number of subcarriers"); // allocate memory for object and set internal properties ofdmflexframesync q = (ofdmflexframesync) malloc(sizeof(struct ofdmflexframesync_s)); q->M = _M; q->cp_len = _cp_len; q->taper_len = _taper_len; q->callback = _callback; q->userdata = _userdata; // allocate memory for subcarrier allocation IDs q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { // initialize default subcarrier allocation ofdmframe_init_default_sctype(q->M, q->p); } else { // copy user-defined subcarrier allocation memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data); // create internal framing object q->fs = ofdmframesync_create(_M, _cp_len, _taper_len, _p, ofdmflexframesync_internal_callback, (void*)q); // create header objects q->header = NULL; q->p_header = NULL; q->header_enc = NULL; q->header_mod = NULL; q->mod_header = NULL; q->header_user_len = OFDMFLEXFRAME_H_USER_DEFAULT; q->header_soft = 0; ofdmflexframesync_set_header_props(q, NULL); // frame properties (default values to be overwritten when frame // header is received and properly decoded) q->ms_payload = LIQUID_MODEM_QPSK; q->bps_payload = 2; q->payload_len = 1; q->check = LIQUID_CRC_NONE; q->fec0 = LIQUID_FEC_NONE; q->fec1 = LIQUID_FEC_NONE; // create payload objects (initially QPSK, etc but overridden by received properties) q->mod_payload = modemcf_create(q->ms_payload); q->payload_soft = 0; q->p_payload = packetizer_create(q->payload_len, q->check, q->fec0, q->fec1); q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload); q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char)); q->payload_dec = (unsigned char*) malloc(q->payload_len*sizeof(unsigned char)); q->payload_syms = (float complex *) malloc(q->payload_len*sizeof(float complex)); q->payload_mod_len = 0; // reset state ofdmflexframesync_reset_framedatastats(q); ofdmflexframesync_reset(q); // return object return q; } int ofdmflexframesync_destroy(ofdmflexframesync _q) { // destroy internal objects ofdmframesync_destroy(_q->fs); packetizer_destroy(_q->p_header); modemcf_destroy(_q->mod_header); packetizer_destroy(_q->p_payload); modemcf_destroy(_q->mod_payload); // free internal buffers/arrays free(_q->p); free(_q->payload_enc); free(_q->payload_dec); free(_q->payload_syms); free(_q->header); free(_q->header_enc); free(_q->header_mod); // free main object memory free(_q); return LIQUID_OK; } int ofdmflexframesync_print(ofdmflexframesync _q) { printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); printf(", data=%u", _q->M_data); printf(", cp=%u", _q->cp_len); printf(", taper=%u", _q->taper_len); printf(">\n"); return LIQUID_OK; } int ofdmflexframesync_set_header_len(ofdmflexframesync _q, unsigned int _len) { _q->header_user_len = _len; _q->header_dec_len = OFDMFLEXFRAME_H_DEC + _q->header_user_len; _q->header = realloc(_q->header, _q->header_dec_len*sizeof(unsigned char)); if (_q->p_header) { packetizer_destroy(_q->p_header); } _q->p_header = packetizer_create(_q->header_dec_len, _q->header_props.check, _q->header_props.fec0, _q->header_props.fec1); if (_q->header_soft) { _q->header_enc_len = 8*packetizer_get_enc_msg_len(_q->p_header); _q->header_sym_len = _q->header_enc_len; } else { _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header); unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps; div_t bps_d = div(_q->header_enc_len*8, bps); _q->header_sym_len = bps_d.quot + (bps_d.rem ? 1 : 0); } _q->header_enc = realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char)); _q->header_mod = realloc(_q->header_mod, _q->header_sym_len*sizeof(unsigned char)); // create header objects if (_q->mod_header) { modemcf_destroy(_q->mod_header); } _q->mod_header = modemcf_create(_q->header_props.mod_scheme); return LIQUID_OK; } int ofdmflexframesync_decode_header_soft(ofdmflexframesync _q, int _soft) { _q->header_soft = _soft; return ofdmflexframesync_set_header_len(_q, _q->header_user_len); } int ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q, int _soft) { _q->payload_soft = _soft; return LIQUID_OK; } int ofdmflexframesync_set_header_props(ofdmflexframesync _q, ofdmflexframegenprops_s * _props) { // if properties object is NULL, initialize with defaults if (_props == NULL) { _props = &ofdmflexframesyncprops_header_default; } // validate input if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_set_header_props(), invalid/unsupported CRC scheme"); if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_set_header_props(), invalid/unsupported FEC scheme"); if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_set_header_props(), invalid/unsupported modulation scheme"); // copy properties to internal structure memmove(&_q->header_props, _props, sizeof(ofdmflexframegenprops_s)); // reconfigure internal buffers, objects, etc. return ofdmflexframesync_set_header_len(_q, _q->header_user_len); } int ofdmflexframesync_reset(ofdmflexframesync _q) { // reset internal state _q->state = OFDMFLEXFRAMESYNC_STATE_HEADER; // reset internal counters _q->symbol_counter=0; _q->header_symbol_index=0; _q->payload_symbol_index=0; _q->payload_buffer_index=0; // reset error vector magnitude estimate _q->evm_hat = 1e-12f; // slight offset to ensure no log(0) // reset global data counters framesyncstats_init_default(&_q->framesyncstats); // reset internal OFDM frame synchronizer object return ofdmframesync_reset(_q->fs); } // set the callback int ofdmflexframesync_set_callback(ofdmflexframesync _q, framesync_callback _callback) { _q->callback = _callback; return LIQUID_OK; } // set the user-defined data field (context) int ofdmflexframesync_set_userdata(ofdmflexframesync _q, void * _userdata) { _q->userdata = _userdata; return LIQUID_OK; } int ofdmflexframesync_is_frame_open(ofdmflexframesync _q) { return ofdmframesync_is_frame_open(_q->fs); } // execute synchronizer object on buffer of samples int ofdmflexframesync_execute(ofdmflexframesync _q, float complex * _x, unsigned int _n) { // push samples through ofdmframesync object return ofdmframesync_execute(_q->fs, _x, _n); } // // query methods // // received signal strength indication float ofdmflexframesync_get_rssi(ofdmflexframesync _q) { return ofdmframesync_get_rssi(_q->fs); } // received carrier frequency offset float ofdmflexframesync_get_cfo(ofdmflexframesync _q) { return ofdmframesync_get_cfo(_q->fs); } // reset frame data statistics int ofdmflexframesync_reset_framedatastats(ofdmflexframesync _q) { return framedatastats_reset(&_q->framedatastats); } // retrieve frame data statistics framedatastats_s ofdmflexframesync_get_framedatastats(ofdmflexframesync _q) { return _q->framedatastats; } // // set methods // // received carrier frequency offset int ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo) { return ofdmframesync_set_cfo(_q->fs, _cfo); } // // debugging methods // // enable debugging for internal ofdm frame synchronizer int ofdmflexframesync_debug_enable(ofdmflexframesync _q) { return ofdmframesync_debug_enable(_q->fs); } // disable debugging for internal ofdm frame synchronizer int ofdmflexframesync_debug_disable(ofdmflexframesync _q) { return ofdmframesync_debug_disable(_q->fs); } // print debugging file for internal ofdm frame synchronizer int ofdmflexframesync_debug_print(ofdmflexframesync _q, const char * _filename) { return ofdmframesync_debug_print(_q->fs, _filename); } // // internal methods // // internal callback // _X : subcarrier symbols // _p : subcarrier allocation // _M : number of subcarriers // _userdata : user-defined data structure int ofdmflexframesync_internal_callback(float complex * _X, unsigned char * _p, unsigned int _M, void * _userdata) { #if DEBUG_OFDMFLEXFRAMESYNC printf("******* ofdmflexframesync callback invoked!\n"); #endif // type-cast userdata as ofdmflexframesync object ofdmflexframesync _q = (ofdmflexframesync) _userdata; _q->symbol_counter++; #if DEBUG_OFDMFLEXFRAMESYNC printf("received symbol %u\n", _q->symbol_counter); #endif // extract symbols switch (_q->state) { case OFDMFLEXFRAMESYNC_STATE_HEADER: return ofdmflexframesync_rxheader (_q, _X); case OFDMFLEXFRAMESYNC_STATE_PAYLOAD: return ofdmflexframesync_rxpayload(_q, _X); default:; } // return return liquid_error(LIQUID_EINT,"ofdmflexframesync_internal_callback(), invalid internal state"); } // receive header data int ofdmflexframesync_rxheader(ofdmflexframesync _q, float complex * _X) { #if DEBUG_OFDMFLEXFRAMESYNC printf(" ofdmflexframesync extracting header...\n"); #endif // demodulate header symbols unsigned int i; int sctype; for (i=0; i<_q->M; i++) { // subcarrier type (PILOT/NULL/DATA) sctype = _q->p[i]; // ignore pilot and null subcarriers if (sctype == OFDMFRAME_SCTYPE_DATA) { // unload header symbols // demodulate header symbol unsigned int sym; if (_q->header_soft) { unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps; modemcf_demodulate_soft(_q->mod_header, _X[i], &sym, &_q->header_mod[bps*_q->header_symbol_index]); } else { modemcf_demodulate(_q->mod_header, _X[i], &sym); _q->header_mod[_q->header_symbol_index] = sym; } _q->header_symbol_index++; //printf(" extracting symbol %3u / %3u (x = %8.5f + j%8.5f)\n", _q->header_symbol_index, _q->header_sym_len, crealf(_X[i]), cimagf(_X[i])); // get demodulator error vector magnitude float evm = modemcf_get_demodulator_evm(_q->mod_header); _q->evm_hat += evm*evm; // header extracted if (_q->header_symbol_index == _q->header_sym_len) { // decode header ofdmflexframesync_decode_header(_q); // update statistics _q->framesyncstats.evm = 10*log10f( _q->evm_hat/_q->header_sym_len ); _q->framedatastats.num_frames_detected++; // invoke callback if header is invalid if (_q->header_valid) { _q->state = OFDMFLEXFRAMESYNC_STATE_PAYLOAD; _q->framedatastats.num_headers_valid++; } else { //printf("**** header invalid!\n"); // set framesyncstats internals _q->framesyncstats.rssi = ofdmframesync_get_rssi(_q->fs); _q->framesyncstats.cfo = ofdmframesync_get_cfo(_q->fs); _q->framesyncstats.framesyms = NULL; _q->framesyncstats.num_framesyms = 0; _q->framesyncstats.mod_scheme = LIQUID_MODEM_UNKNOWN; _q->framesyncstats.mod_bps = 0; _q->framesyncstats.check = LIQUID_CRC_UNKNOWN; _q->framesyncstats.fec0 = LIQUID_FEC_UNKNOWN; _q->framesyncstats.fec1 = LIQUID_FEC_UNKNOWN; // ignore callback if set to NULL if (_q->callback == NULL) { ofdmflexframesync_reset(_q); break; } // invoke callback method _q->callback(_q->header, _q->header_valid, NULL, 0, 0, _q->framesyncstats, _q->userdata); ofdmflexframesync_reset(_q); } break; } } } return LIQUID_OK; } // decode header int ofdmflexframesync_decode_header(ofdmflexframesync _q) { _q->header_valid = 0; int header_ok = 0; if (_q->header_soft) { // TODO: ensure lengths are the same memmove(_q->header_enc, _q->header_mod, _q->header_enc_len); // unscramble header using soft bits unscramble_data_soft(_q->header_enc, _q->header_enc_len/8); // run packet decoder header_ok = packetizer_decode_soft(_q->p_header, _q->header_enc, _q->header); } else { // pack 1-bit header symbols into 8-bit bytes unsigned int num_written; unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps; liquid_repack_bytes(_q->header_mod, bps, _q->header_sym_len, _q->header_enc, 8, _q->header_enc_len, &num_written); assert(num_written==_q->header_enc_len); // unscramble header unscramble_data(_q->header_enc, _q->header_enc_len); // run packet decoder header_ok = packetizer_decode(_q->p_header, _q->header_enc, _q->header); } #if 0 // print header printf("header rx (enc) : "); for (i=0; i<_q->header_enc_len; i++) printf("%.2X ", _q->header_enc[i]); printf("\n"); // print header printf("header rx (dec) : "); for (i=0; i<_q->header_dec_len; i++) printf("%.2X ", _q->header[i]); printf("\n"); #endif #if DEBUG_OFDMFLEXFRAMESYNC printf("****** header extracted [%s]\n", header_ok ? "valid" : "INVALID!"); #endif if (!header_ok) return LIQUID_OK; unsigned int n = _q->header_user_len; // first byte is for expansion/version validation if (_q->header[n+0] != OFDMFLEXFRAME_PROTOCOL) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_decode_header(), invalid framing version"); // strip off payload length unsigned int payload_len = (_q->header[n+1] << 8) | (_q->header[n+2]); // strip off modulation scheme/depth unsigned int mod_scheme = _q->header[n+3]; if (mod_scheme == 0 || mod_scheme >= LIQUID_MODEM_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_decode_header(), invalid modulation scheme"); // strip off CRC, forward error-correction schemes // CRC : most-significant 3 bits of [n+4] // fec0 : least-significant 5 bits of [n+4] // fec1 : least-significant 5 bits of [n+5] unsigned int check = (_q->header[n+4] >> 5 ) & 0x07; unsigned int fec0 = (_q->header[n+4] ) & 0x1f; unsigned int fec1 = (_q->header[n+5] ) & 0x1f; // validate properties if (check >= LIQUID_CRC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_decode_header(), decoded CRC exceeds available"); if (fec0 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_decode_header(), decoded FEC (inner) exceeds available"); if (fec1 >= LIQUID_FEC_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"ofdmflexframesync_decode_header(), decoded FEC (outer) exceeds available"); // print results #if DEBUG_OFDMFLEXFRAMESYNC printf(" properties:\n"); printf(" * mod scheme : %s\n", modulation_types[mod_scheme].fullname); printf(" * fec (inner) : %s\n", fec_scheme_str[fec0][1]); printf(" * fec (outer) : %s\n", fec_scheme_str[fec1][1]); printf(" * CRC scheme : %s\n", crc_scheme_str[check][1]); printf(" * payload length : %u bytes\n", payload_len); #endif // at this point, header is valid _q->header_valid = 1; // configure modem if (mod_scheme != _q->ms_payload) { // set new properties _q->ms_payload = mod_scheme; _q->bps_payload = modulation_types[mod_scheme].bps; // recreate modem (destroy/create) _q->mod_payload = modemcf_recreate(_q->mod_payload, _q->ms_payload); } // set new packetizer properties _q->payload_len = payload_len; _q->check = check; _q->fec0 = fec0; _q->fec1 = fec1; // recreate packetizer object _q->p_payload = packetizer_recreate(_q->p_payload, _q->payload_len, _q->check, _q->fec0, _q->fec1); // re-compute payload encoded message length if (_q->payload_soft) { int packetizer_msg_len = packetizer_get_enc_msg_len(_q->p_payload); div_t d = div((int)8*packetizer_msg_len, (int)_q->bps_payload); _q->payload_mod_len = d.quot + (d.rem ? 1 : 0); _q->payload_enc_len = _q->bps_payload*_q->payload_mod_len; } else { _q->payload_enc_len = packetizer_get_enc_msg_len(_q->p_payload); // re-compute number of modulated payload symbols div_t d = div(8*_q->payload_enc_len, _q->bps_payload); _q->payload_mod_len = d.quot + (d.rem ? 1 : 0); } #if DEBUG_OFDMFLEXFRAMESYNC printf(" * payload encoded : %u bytes\n", _q->payload_enc_len); #endif // re-allocate buffers accordingly _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->payload_enc_len*sizeof(unsigned char)); _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, _q->payload_len*sizeof(unsigned char)); _q->payload_syms = (float complex*) realloc(_q->payload_syms, _q->payload_mod_len*sizeof(float complex)); #if DEBUG_OFDMFLEXFRAMESYNC printf(" * payload mod syms: %u symbols\n", _q->payload_mod_len); #endif return LIQUID_OK; } // receive payload data int ofdmflexframesync_rxpayload(ofdmflexframesync _q, float complex * _X) { // demodulate paylod symbols unsigned int i; int sctype; for (i=0; i<_q->M; i++) { // subcarrier type (PILOT/NULL/DATA) sctype = _q->p[i]; // ignore pilot and null subcarriers if (sctype == OFDMFRAME_SCTYPE_DATA) { // unload payload symbols unsigned int sym; // store received symbol _q->payload_syms[_q->payload_symbol_index] = _X[i]; if (_q->payload_soft) { modemcf_demodulate_soft(_q->mod_payload, _X[i], &sym, &_q->payload_enc[_q->bps_payload*_q->payload_symbol_index]); } else { modemcf_demodulate(_q->mod_payload, _X[i], &sym); // pack decoded symbol into array liquid_pack_array(_q->payload_enc, _q->payload_enc_len, _q->payload_buffer_index, _q->bps_payload, sym); // increment... _q->payload_buffer_index += _q->bps_payload; } // increment symbol counter _q->payload_symbol_index++; if (_q->payload_symbol_index == _q->payload_mod_len) { // payload extracted if (_q->payload_soft) { _q->payload_valid = packetizer_decode_soft(_q->p_payload, _q->payload_enc, _q->payload_dec); } else { // decode payload _q->payload_valid = packetizer_decode(_q->p_payload, _q->payload_enc, _q->payload_dec); } #if DEBUG_OFDMFLEXFRAMESYNC printf("****** payload extracted [%s]\n", _q->payload_valid ? "valid" : "INVALID!"); #endif // update statistics _q->framedatastats.num_payloads_valid += _q->payload_valid; _q->framedatastats.num_bytes_received += _q->payload_len; // set framesyncstats internals _q->framesyncstats.rssi = ofdmframesync_get_rssi(_q->fs); _q->framesyncstats.cfo = ofdmframesync_get_cfo(_q->fs); _q->framesyncstats.framesyms = _q->payload_syms; _q->framesyncstats.num_framesyms = _q->payload_mod_len; _q->framesyncstats.mod_scheme = _q->ms_payload; _q->framesyncstats.mod_bps = _q->bps_payload; _q->framesyncstats.check = _q->check; _q->framesyncstats.fec0 = _q->fec0; _q->framesyncstats.fec1 = _q->fec1; // ignore callback if set to NULL if (_q->callback == NULL) { ofdmflexframesync_reset(_q); break; } // invoke callback method _q->callback(_q->header, _q->header_valid, _q->payload_dec, _q->payload_len, _q->payload_valid, _q->framesyncstats, _q->userdata); // reset object ofdmflexframesync_reset(_q); break; } } } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/presync.proto.c000066400000000000000000000176301474751757600216220ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Binary pre-demod synchronizer // #include #include #include #include #include "liquid.internal.h" struct PRESYNC(_s) { unsigned int n; // sequence length unsigned int m; // number of binary synchronizers WINDOW() rx_i; // received pattern (in-phase) WINDOW() rx_q; // received pattern (quadrature) float * dphi; // array of frequency offsets [size: m x 1] DOTPROD() * sync_i; // synchronization pattern (in-phase) DOTPROD() * sync_q; // synchronization pattern (quadrature) float * rxy; // output correlation [size: m x 1] float n_inv; // 1/n (pre-computed for speed) }; // correlate input sequence with particular sequence index // _q : pre-demod synchronizer object // _id : sequence index // _rxy0 : positive frequency correlation output (non-conjugated) // _rxy1 : negative frequency correlation output (conjugated) int PRESYNC(_correlate)(PRESYNC() _q, unsigned int _id, float complex * _rxy0, float complex * _rxy1); /* create binary pre-demod synchronizer */ /* _v : baseband sequence */ /* _n : baseband sequence length */ /* _dphi_max : maximum absolute frequency deviation */ /* _m : number of correlators */ PRESYNC() PRESYNC(_create)(TC * _v, unsigned int _n, float _dphi_max, unsigned int _m) { // validate input if (_n < 1) return liquid_error_config("bpresync_%s_create(), invalid input length", EXTENSION_FULL); if (_m == 0) return liquid_error_config("bpresync_%s_create(), number of correlators must be at least 1", EXTENSION_FULL); // allocate main object memory and initialize PRESYNC() _q = (PRESYNC()) malloc(sizeof(struct PRESYNC(_s))); _q->n = _n; _q->m = _m; _q->n_inv = 1.0f / (float)(_q->n); unsigned int i; // create internal receive buffers _q->rx_i = WINDOW(_create)(_q->n); _q->rx_q = WINDOW(_create)(_q->n); // create internal array of frequency offsets _q->dphi = (float*) malloc( _q->m*sizeof(float) ); // create internal synchronizers _q->sync_i = (DOTPROD()*) malloc( _q->m*sizeof(DOTPROD()) ); _q->sync_q = (DOTPROD()*) malloc( _q->m*sizeof(DOTPROD()) ); // buffer T vi_prime[_n]; T vq_prime[_n]; for (i=0; i<_q->m; i++) { // generate signal with frequency offset _q->dphi[i] = (float)i / (float)(_q->m-1)*_dphi_max; unsigned int k; for (k=0; k<_q->n; k++) { vi_prime[k] = REAL( _v[k] * cexpf(-_Complex_I*k*_q->dphi[i]) ); vq_prime[k] = IMAG( _v[k] * cexpf(-_Complex_I*k*_q->dphi[i]) ); } _q->sync_i[i] = DOTPROD(_create)(vi_prime, _q->n); _q->sync_q[i] = DOTPROD(_create)(vq_prime, _q->n); } // allocate memory for cross-correlation _q->rxy = (float*) malloc( _q->m*sizeof(float) ); // reset object PRESYNC(_reset)(_q); return _q; } int PRESYNC(_destroy)(PRESYNC() _q) { unsigned int i; // free received symbol buffers WINDOW(_destroy)(_q->rx_i); WINDOW(_destroy)(_q->rx_q); // free internal syncrhonizer objects for (i=0; i<_q->m; i++) { DOTPROD(_destroy)(_q->sync_i[i]); DOTPROD(_destroy)(_q->sync_q[i]); } free(_q->sync_i); free(_q->sync_q); // free internal frequency offset array free(_q->dphi); // free internal cross-correlation array free(_q->rxy); // free main object memory free(_q); return LIQUID_OK; } int PRESYNC(_print)(PRESYNC() _q) { printf("\n", EXTENSION_FULL, _q->n); return LIQUID_OK; } int PRESYNC(_reset)(PRESYNC() _q) { WINDOW(_reset)(_q->rx_i); WINDOW(_reset)(_q->rx_q); return LIQUID_OK; } /* push input sample into pre-demod synchronizer */ /* _q : pre-demod synchronizer object */ /* _x : input sample */ int PRESYNC(_push)(PRESYNC() _q, TI _x) { // push symbol into buffers WINDOW(_push)(_q->rx_i, REAL(_x)); WINDOW(_push)(_q->rx_q, REAL(_x)); return LIQUID_OK; } /* correlate input sequence */ /* _q : pre-demod synchronizer object */ /* _rxy : output cross correlation */ /* _dphi_hat : output frequency offset estimate */ int PRESYNC(_execute)(PRESYNC() _q, TO * _rxy, float * _dphi_hat) { unsigned int i; float complex rxy_max = 0; // maximum cross-correlation float abs_rxy_max = 0; // absolute value of rxy_max float complex rxy0; float complex rxy1; float dphi_hat = 0.0f; for (i=0; i<_q->m; i++) { PRESYNC(_correlate)(_q, i, &rxy0, &rxy1); // check non-conjugated value if ( ABS(rxy0) > abs_rxy_max ) { rxy_max = rxy0; abs_rxy_max = ABS(rxy0); dphi_hat = _q->dphi[i]; } // check conjugated value if ( ABS(rxy1) > abs_rxy_max ) { rxy_max = rxy1; abs_rxy_max = ABS(rxy1); dphi_hat = -_q->dphi[i]; } } *_rxy = rxy_max; *_dphi_hat = dphi_hat; return LIQUID_OK; } // // internal methods // // correlate input sequence with particular sequence index // _q : pre-demod synchronizer object // _id : sequence index // _rxy0 : positive frequency correlation output (non-conjugated) // _rxy1 : negative frequency correlation output (conjugated) int PRESYNC(_correlate)(PRESYNC() _q, unsigned int _id, float complex * _rxy0, float complex * _rxy1) { // validate input... if (_id >= _q->m) return liquid_error(LIQUID_EICONFIG,"bpresync_%s_correlatex(), invalid id", EXTENSION_FULL); // get buffer pointers T * ri = NULL; T * rq = NULL; WINDOW(_read)(_q->rx_i, &ri); WINDOW(_read)(_q->rx_q, &rq); // compute correlations T rxy_ii; DOTPROD(_execute)(_q->sync_i[_id], ri, &rxy_ii); T rxy_qq; DOTPROD(_execute)(_q->sync_q[_id], rq, &rxy_qq); T rxy_iq; DOTPROD(_execute)(_q->sync_i[_id], rq, &rxy_iq); T rxy_qi; DOTPROD(_execute)(_q->sync_q[_id], ri, &rxy_qi); // non-conjugated T rxy_i0 = rxy_ii - rxy_qq; T rxy_q0 = rxy_iq + rxy_qi; *_rxy0 = (rxy_i0 + rxy_q0 * _Complex_I) * _q->n_inv; // conjugated T rxy_i1 = rxy_ii + rxy_qq; T rxy_q1 = rxy_iq - rxy_qi; *_rxy1 = (rxy_i1 + rxy_q1 * _Complex_I) * _q->n_inv; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/qdetector.proto.c000066400000000000000000000624421474751757600221320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Frame detector #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_QDETECTOR 0 #define DEBUG_QDETECTOR_PRINT 0 #define DEBUG_QDETECTOR_FILENAME "qdetector_cccf_debug.m" // seek signal (initial detection) int QDETECTOR(_execute_seek)(QDETECTOR() _q, TI _x); // align signal in time, compute offset estimates int QDETECTOR(_execute_align)(QDETECTOR() _q, TI _x); // main object definition struct QDETECTOR(_s) { unsigned int s_len; // template (time) length: k * (sequence_len + 2*m) TI * s; // template (time), [size: s_len x 1] TI * S; // template (freq), [size: nfft x 1] float s2_sum; // sum{ s^2 } TI * buf_time_0; // time-domain buffer (FFT) TI * buf_freq_0; // frequence-domain buffer (FFT) TI * buf_freq_1; // frequence-domain buffer (IFFT) TI * buf_time_1; // time-domain buffer (IFFT) unsigned int nfft; // fft size FFT_PLAN fft; // FFT object: buf_time_0 > buf_freq_0 FFT_PLAN ifft; // IFFT object: buf_freq_1 > buf_freq_1 unsigned int counter; // sample counter for determining when to compute FFTs float threshold; // detection threshold float dphi_max; // carrier offset search range (radians/sample) int range; // carrier offset search range (subcarriers) unsigned int num_transforms; // number of transforms taken (debugging) float x2_sum_0; // sum{ |x|^2 } of first half of buffer float x2_sum_1; // sum{ |x|^2 } of second half of buffer float rxy; // peak correlation output int offset; // FFT offset index for peak correlation (coarse carrier estimate) float tau_hat; // timing offset estimate float gamma_hat; // signal level estimate (channel gain) float dphi_hat; // carrier frequency offset estimate float phi_hat; // carrier phase offset estimate enum { QDETECTOR_STATE_SEEK, // seek sequence QDETECTOR_STATE_ALIGN, // align sequence } state; // execution state int frame_detected; // frame detected? }; // create detector with generic sequence // _s : sample sequence // _s_len : length of sample sequence QDETECTOR() QDETECTOR(_create)(TI * _s, unsigned int _s_len) { // validate input if (_s_len == 0) return liquid_error_config("QDETECTOR(_create)(), sequence length cannot be zero"); // allocate memory for main object and set internal properties QDETECTOR() q = (QDETECTOR()) malloc(sizeof(struct QDETECTOR(_s))); q->s_len = _s_len; // allocate memory and copy sequence q->s = (TI*) malloc(q->s_len * sizeof(TI)); memmove(q->s, _s, q->s_len*sizeof(TI)); q->s2_sum = liquid_sumsqcf(q->s, q->s_len); // compute sum{ s^2 } // prepare transforms q->nfft = 1 << liquid_nextpow2( (unsigned int)( 2 * q->s_len ) ); // NOTE: must be even q->buf_time_0 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); q->buf_freq_0 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); q->buf_freq_1 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); q->buf_time_1 = (TI*) FFT_MALLOC(q->nfft * sizeof(TI)); q->fft = FFT_CREATE_PLAN(q->nfft, q->buf_time_0, q->buf_freq_0, FFT_DIR_FORWARD, 0); q->ifft = FFT_CREATE_PLAN(q->nfft, q->buf_freq_1, q->buf_time_1, FFT_DIR_BACKWARD, 0); // create frequency-domain template by taking nfft-point transform on 's', storing in 'S' q->S = (TI*) malloc(q->nfft * sizeof(TI)); memset(q->buf_time_0, 0x00, q->nfft*sizeof(TI)); memmove(q->buf_time_0, q->s, q->s_len*sizeof(TI)); FFT_EXECUTE(q->fft); memmove(q->S, q->buf_freq_0, q->nfft*sizeof(TI)); // reset state variables q->counter = q->nfft/2; q->num_transforms = 0; q->x2_sum_0 = 0.0f; q->x2_sum_1 = 0.0f; q->state = QDETECTOR_STATE_SEEK; q->frame_detected = 0; memset(q->buf_time_0, 0x00, q->nfft*sizeof(TI)); // reset estimates q->rxy = 0.0f; q->tau_hat = 0.0f; q->gamma_hat = 0.0f; q->dphi_hat = 0.0f; q->phi_hat = 0.0f; QDETECTOR(_set_threshold)(q,0.5f); QDETECTOR(_set_range )(q,0.3f); // set initial range for higher detection // return object return q; } // create detector from sequence of symbols using internal linear interpolator // _sequence : symbol sequence // _sequence_len : length of symbol sequence // _ftype : filter prototype (e.g. LIQUID_FIRFILT_RRC) // _k : samples/symbol // _m : filter delay // _beta : excess bandwidth factor QDETECTOR() QDETECTOR(_create_linear)(TI * _sequence, unsigned int _sequence_len, int _ftype, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_sequence_len == 0) return liquid_error_config("QDETECTOR(_create_linear)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) return liquid_error_config("QDETECTOR(_create_linear)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) return liquid_error_config("QDETECTOR(_create_linear)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("QDETECTOR(_create_linear)(), excess bandwidth factor must be in [0,1]"); // create time-domain template unsigned int s_len = _k * (_sequence_len + 2*_m); TI * s = (TI*) malloc(s_len * sizeof(TI)); firinterp_crcf interp = firinterp_crcf_create_prototype(_ftype, _k, _m, _beta, 0); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) firinterp_crcf_execute(interp, i < _sequence_len ? _sequence[i] : 0, &s[_k*i]); firinterp_crcf_destroy(interp); // create main object QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); // return object return q; } // create detector from sequence of symbols using internal linear interpolator // _sequence : bit sequence // _sequence_len : length of bit sequence // _k : samples/symbol // _m : filter delay // _beta : excess bandwidth factor QDETECTOR() QDETECTOR(_create_gmsk)(unsigned char * _sequence, unsigned int _sequence_len, unsigned int _k, unsigned int _m, float _beta) { // validate input if (_sequence_len == 0) return liquid_error_config("QDETECTOR(_create_gmsk)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) return liquid_error_config("QDETECTOR(_create_gmsk)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) return liquid_error_config("QDETECTOR(_create_gmsk)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("QDETECTOR(_create_gmsk)(), excess bandwidth factor must be in [0,1]"); // create time-domain template using GMSK modem unsigned int s_len = _k * (_sequence_len + 2*_m); TI * s = (TI*) malloc(s_len * sizeof(TI)); gmskmod mod = gmskmod_create(_k, _m, _beta); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) gmskmod_modulate(mod, i < _sequence_len ? _sequence[i] : 0, &s[_k*i]); gmskmod_destroy(mod); // create main object QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); // return object return q; } // create detector from sequence of CP-FSK symbols (assuming one bit/symbol) // _sequence : bit sequence // _sequence_len : length of bit sequence // _bps : bits per symbol, 0 < _bps <= 8 // _h : modulation index, _h > 0 // _k : samples/symbol // _m : filter delay // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) QDETECTOR() QDETECTOR(_create_cpfsk)(unsigned char * _sequence, unsigned int _sequence_len, unsigned int _bps, float _h, unsigned int _k, unsigned int _m, float _beta, int _type) { // validate input if (_sequence_len == 0) return liquid_error_config("QDETECTOR(_create_cpfsk)(), sequence length cannot be zero"); if (_k < 2 || _k > 80) return liquid_error_config("QDETECTOR(_create_cpfsk)(), samples per symbol must be in [2,80]"); if (_m < 1 || _m > 100) return liquid_error_config("QDETECTOR(_create_cpfsk)(), filter delay must be in [1,100]"); if (_beta < 0.0f || _beta > 1.0f) return liquid_error_config("QDETECTOR(_create_cpfsk)(), excess bandwidth factor must be in [0,1]"); // create time-domain template using GMSK modem unsigned int s_len = _k * (_sequence_len + 2*_m); TI * s = (TI*) malloc(s_len * sizeof(TI)); cpfskmod mod = cpfskmod_create(_bps, _h, _k, _m, _beta, _type); unsigned int i; for (i=0; i<_sequence_len + 2*_m; i++) cpfskmod_modulate(mod, i < _sequence_len ? _sequence[i] : 0, &s[_k*i]); cpfskmod_destroy(mod); // create main object QDETECTOR() q = QDETECTOR(_create)(s, s_len); // free allocated temporary array free(s); // return object return q; } // copy object QDETECTOR() QDETECTOR(_copy)(QDETECTOR() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", EXTENSION_FULL); // create new object from internal sequence QDETECTOR() q_copy = QDETECTOR(_create)(q_orig->s, q_orig->s_len); // copy buffer contents memmove(q_copy->buf_time_0, q_orig->buf_time_0, q_orig->nfft*sizeof(TI)); memmove(q_copy->buf_freq_0, q_orig->buf_freq_0, q_orig->nfft*sizeof(TI)); memmove(q_copy->buf_time_1, q_orig->buf_time_1, q_orig->nfft*sizeof(TI)); memmove(q_copy->buf_freq_1, q_orig->buf_freq_1, q_orig->nfft*sizeof(TI)); // copy internal state q_copy->counter = q_orig->counter; q_copy->threshold = q_orig->threshold; q_copy->dphi_max = q_orig->dphi_max; q_copy->range = q_orig->range; q_copy->num_transforms = q_orig->num_transforms; // buffer power magnitude q_copy->x2_sum_0 = q_orig->x2_sum_0; q_copy->x2_sum_1 = q_orig->x2_sum_1; // state variables q_copy->state = q_orig->state; q_copy->frame_detected = q_orig->frame_detected; // return new object return q_copy; } int QDETECTOR(_destroy)(QDETECTOR() _q) { // free allocated arrays free(_q->s); free(_q->S); FFT_FREE(_q->buf_time_0); FFT_FREE(_q->buf_freq_0); FFT_FREE(_q->buf_freq_1); FFT_FREE(_q->buf_time_1); // destroy objects FFT_DESTROY_PLAN(_q->fft); FFT_DESTROY_PLAN(_q->ifft); // free main object memory free(_q); return LIQUID_OK; } int QDETECTOR(_print)(QDETECTOR() _q) { printf("s_len); printf(", nfft=%u", _q->nfft); printf(", dphi_max=%g",_q->dphi_max); printf(", thresh=%g", _q->threshold); printf(", energy=%g\n", _q->s2_sum); printf(">\n"); return LIQUID_OK; } int QDETECTOR(_reset)(QDETECTOR() _q) { return LIQUID_OK; } void * QDETECTOR(_execute)(QDETECTOR() _q, TI _x) { switch (_q->state) { case QDETECTOR_STATE_SEEK: // seek signal QDETECTOR(_execute_seek)(_q, _x); break; case QDETECTOR_STATE_ALIGN: // align signal QDETECTOR(_execute_align)(_q, _x); break; } // check if frame was detected if (_q->frame_detected) { // clear flag _q->frame_detected = 0; // return pointer to internal buffer of saved samples return (void*)(_q->buf_time_1); } // frame not yet ready return NULL; } // get detection threshold float QDETECTOR(_get_threshold)(QDETECTOR() _q) { return _q->threshold; } // set detection threshold (should be between 0 and 1, good starting point is 0.5) int QDETECTOR(_set_threshold)(QDETECTOR() _q, float _threshold) { if (_threshold <= 0.0f || _threshold > 2.0f) return liquid_error(LIQUID_EICONFIG,"threshold (%12.4e) out of range; ignoring", _threshold); // set internal threshold value _q->threshold = _threshold; return LIQUID_OK; } // get carrier offset search range float QDETECTOR(_get_range)(QDETECTOR() _q) { return _q->dphi_max; } // set carrier offset search range int QDETECTOR(_set_range)(QDETECTOR() _q, float _dphi_max) { if (_dphi_max < 0.0f || _dphi_max > 0.5f) return liquid_error(LIQUID_EICONFIG,"carrier offset search range (%12.4e) out of range; ignoring", _dphi_max); // set internal search range _q->dphi_max = _dphi_max; _q->range = (int)(_q->dphi_max * _q->nfft / (2*M_PI)); _q->range = _q->range < 0 ? 0 : _q->range; //printf("range: %d / %u\n", _q->range, _q->nfft); return LIQUID_OK; } // get sequence length unsigned int QDETECTOR(_get_seq_len)(QDETECTOR() _q) { return _q->s_len; } // pointer to sequence const void * QDETECTOR(_get_sequence)(QDETECTOR() _q) { return (const void*) _q->s; } // buffer length unsigned int QDETECTOR(_get_buf_len)(QDETECTOR() _q) { return _q->nfft; } // correlator output float QDETECTOR(_get_rxy)(QDETECTOR() _q) { return _q->rxy; } // fractional timing offset estimate float QDETECTOR(_get_tau)(QDETECTOR() _q) { return _q->tau_hat; } // channel gain float QDETECTOR(_get_gamma)(QDETECTOR() _q) { return _q->gamma_hat; } // carrier frequency offset estimate float QDETECTOR(_get_dphi)(QDETECTOR() _q) { return _q->dphi_hat; } // carrier phase offset estimate float QDETECTOR(_get_phi)(QDETECTOR() _q) { return _q->phi_hat; } // // internal methods // // seek signal (initial detection) int QDETECTOR(_execute_seek)(QDETECTOR() _q, TI _x) { // write sample to buffer and increment counter _q->buf_time_0[_q->counter++] = _x; // accumulate signal magnitude _q->x2_sum_1 += crealf(_x)*crealf(_x) + cimagf(_x)*cimagf(_x); if (_q->counter < _q->nfft) return LIQUID_OK; // reset counter (last half of time buffer) _q->counter = _q->nfft/2; // run forward transform FFT_EXECUTE(_q->fft); // compute scaling factor (TODO: use median rather than mean signal level) float g0; if (_q->x2_sum_0 == 0.f) { g0 = sqrtf(_q->x2_sum_1) * sqrtf((float)(_q->s_len) / (float)(_q->nfft / 2)); } else { g0 = sqrtf(_q->x2_sum_0 + _q->x2_sum_1) * sqrtf((float)(_q->s_len) / (float)(_q->nfft)); } if (g0 < 1e-10) { memmove(_q->buf_time_0, _q->buf_time_0 + _q->nfft / 2, (_q->nfft / 2) * sizeof(liquid_float_complex)); // swap accumulated signal levels _q->x2_sum_0 = _q->x2_sum_1; _q->x2_sum_1 = 0.0f; return LIQUID_OK; } float g = 1.0f / ((float)(_q->nfft) * g0 * sqrtf(_q->s2_sum)); // sweep over carrier frequency offset range int offset; unsigned int i; float rxy_peak = 0.0f; unsigned int rxy_index = 0; int rxy_offset = 0; // NOTE: this offset may be coarse as a fine carrier estimate is computed later for (offset=-_q->range; offset<=_q->range; offset++) { // cross-multiply, aligning appropriately for (i=0; i<_q->nfft; i++) { // shifted index unsigned int j = (i + _q->nfft - offset) % _q->nfft; _q->buf_freq_1[i] = _q->buf_freq_0[i] * conjf(_q->S[j]); } // run inverse transform FFT_EXECUTE(_q->ifft); // scale output appropriately liquid_vectorcf_mulscalar(_q->buf_time_1, _q->nfft, g, _q->buf_time_1); #if DEBUG_QDETECTOR // debug output char filename[64]; sprintf(filename,"qdetector_out_%u_%d.m", _q->num_transforms, offset+2); FILE * fid = fopen(filename, "w"); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"nfft = %u;\n", _q->nfft); for (i=0; i<_q->nfft; i++) fprintf(fid,"rxy(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(_q->buf_time_1[i]), cimagf(_q->buf_time_1[i])); fprintf(fid,"figure;\n"); fprintf(fid,"t=[0:(nfft-1)];\n"); fprintf(fid,"plot(t,abs(rxy));\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([0 %u 0 1.5]);\n", _q->nfft); fprintf(fid,"[v i] = max(abs(rxy));\n"); fprintf(fid,"title(sprintf('peak of %%12.8f at index %%u', v, i));\n"); fclose(fid); printf("debug: %s\n", filename); #endif // search for peak // TODO: only search over range [-nfft/2, nfft/2) for (i=0; i<_q->nfft; i++) { float rxy_abs = cabsf(_q->buf_time_1[i]); if (rxy_abs > rxy_peak) { rxy_peak = rxy_abs; rxy_index = i; rxy_offset = offset; } } } // increment number of transforms (debugging) _q->num_transforms++; if (rxy_peak > _q->threshold && rxy_index < _q->nfft - _q->s_len) { #if DEBUG_QDETECTOR_PRINT printf("*** frame detected! rxy = %12.8f, time index=%u, freq. offset=%d\n", rxy_peak, rxy_index, rxy_offset); #endif // update state, reset counter, copy buffer appropriately _q->state = QDETECTOR_STATE_ALIGN; _q->offset = rxy_offset; _q->rxy = rxy_peak; // note that this is a coarse estimate // TODO: check for edge case where rxy_index is zero (signal already aligned) // copy last part of fft input buffer to front memmove(_q->buf_time_0, _q->buf_time_0 + rxy_index, (_q->nfft - rxy_index)*sizeof(TI)); _q->counter = _q->nfft - rxy_index; return LIQUID_OK; } #if DEBUG_QDETECTOR_PRINT printf(" no detect, rxy = %12.8f, time index=%u, freq. offset=%d\n", rxy_peak, rxy_index, rxy_offset); #endif // copy last half of fft input buffer to front memmove(_q->buf_time_0, _q->buf_time_0 + _q->nfft/2, (_q->nfft/2)*sizeof(TI)); // swap accumulated signal levels _q->x2_sum_0 = _q->x2_sum_1; _q->x2_sum_1 = 0.0f; return LIQUID_OK; } // align signal in time, compute offset estimates int QDETECTOR(_execute_align)(QDETECTOR() _q, TI _x) { // write sample to buffer and increment counter _q->buf_time_0[_q->counter++] = _x; if (_q->counter < _q->nfft) return LIQUID_OK; //printf("signal is aligned!\n"); // estimate timing offset FFT_EXECUTE(_q->fft); // cross-multiply frequency-domain components, aligning appropriately with // estimated FFT offset index due to carrier frequency offset in received signal unsigned int i; for (i=0; i<_q->nfft; i++) { // shifted index unsigned int j = (i + _q->nfft - _q->offset) % _q->nfft; _q->buf_freq_1[i] = _q->buf_freq_0[i] * conjf(_q->S[j]); } FFT_EXECUTE(_q->ifft); // time aligned to index 0 // NOTE: taking the sqrt removes bias in the timing estimate, but messes up gamma estimate float yneg = cabsf(_q->buf_time_1[_q->nfft-1]); yneg = sqrtf(yneg); float y0 = cabsf(_q->buf_time_1[ 0]); y0 = sqrtf(y0 ); float ypos = cabsf(_q->buf_time_1[ 1]); ypos = sqrtf(ypos); // compute timing offset estimate from quadratic polynomial fit // y = a x^2 + b x + c, [xneg = -1, x0 = 0, xpos = +1] float a = 0.5f*(ypos + yneg) - y0; float b = 0.5f*(ypos - yneg); float c = y0; _q->tau_hat = -b / (2.0f*a); //-0.5f*(ypos - yneg) / (ypos + yneg - 2*y0); float g_hat = (a*_q->tau_hat*_q->tau_hat + b*_q->tau_hat + c); _q->gamma_hat = g_hat * g_hat / ((float)(_q->nfft) * _q->s2_sum); // g_hat^2 because of sqrt for yneg/y0/ypos // TODO: revise estimate of rxy here // copy buffer to preserve data integrity memmove(_q->buf_time_1, _q->buf_time_0, _q->nfft*sizeof(TI)); // estimate carrier frequency offset for (i=0; i<_q->nfft; i++) _q->buf_time_0[i] *= i < _q->s_len ? conjf(_q->s[i]) : 0.0f; FFT_EXECUTE(_q->fft); #if DEBUG_QDETECTOR // debug output char filename[64]; sprintf(filename,"qdetector_fft.m"); FILE * fid = fopen(filename, "w"); fprintf(fid,"clear all; close all;\n"); fprintf(fid,"nfft = %u;\n", _q->nfft); for (i=0; i<_q->nfft; i++) fprintf(fid,"V(%6u) = %12.4e + 1i*%12.4e;\n", i+1, crealf(_q->buf_freq_0[i]), cimagf(_q->buf_freq_0[i])); fprintf(fid,"V = fftshift(V) / max(abs(V));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"f=[0:(nfft-1)] - nfft/2;\n"); fprintf(fid,"plot(f,abs(V),'-x');\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"axis([-10 10 0 1.2]);\n"); fclose(fid); printf("debug: %s\n", filename); #endif // search for peak (NOTE: should be at: _q->offset) // TODO: don't search for peak but just use internal offset float v0 = 0.0f; unsigned int i0 = 0; for (i=0; i<_q->nfft; i++) { float v_abs = cabsf(_q->buf_freq_0[i]); if (v_abs > v0) { v0 = v_abs; i0 = i; } } // interpolate using quadratic polynomial for carrier frequency estimate unsigned int ineg = (i0 + _q->nfft - 1)%_q->nfft; unsigned int ipos = (i0 + 1)%_q->nfft; float vneg = cabsf(_q->buf_freq_0[ineg]); float vpos = cabsf(_q->buf_freq_0[ipos]); a = 0.5f*(vpos + vneg) - v0; b = 0.5f*(vpos - vneg); //c = v0; float idx = -b / (2.0f*a); //-0.5f*(vpos - vneg) / (vpos + vneg - 2*v0); float index = (float)i0 + idx; _q->dphi_hat = (i0 > _q->nfft/2 ? index-(float)_q->nfft : index) * 2*M_PI / (float)(_q->nfft); // estimate carrier phase offset #if 0 // METHOD 1: linear interpolation of phase in FFT output buffer float p0 = cargf(_q->buf_freq_0[ idx < 0 ? ineg : i0 ]); float p1 = cargf(_q->buf_freq_0[ idx < 0 ? i0 : ipos ]); float xp = idx < 0 ? 1+idx : idx; _q->phi_hat = (p1-p0)*xp + p0; //printf("v0 = %12.8f, v1 = %12.8f, xp = %12.8f\n", v0, v1, xp); #else // METHOD 2: compute metric by de-rotating signal and measuring resulting phase // NOTE: this is possibly more accurate than the above method but might also // be more computationally complex TI metric = 0; for (i=0; i<_q->s_len; i++) metric += _q->buf_time_0[i] * cexpf(-_Complex_I*_q->dphi_hat*i); //printf("metric : %12.8f <%12.8f>\n", cabsf(metric), cargf(metric)); _q->phi_hat = cargf(metric); #endif #if DEBUG_QDETECTOR_PRINT printf(" y[ -1] : %12.8f\n", yneg); printf(" y[ 0] : %12.8f\n", y0 ); printf(" y[ +1] : %12.8f\n", ypos); printf(" tau-hat : %12.8f\n", _q->tau_hat); //printf(" g-hat: : %12.8f\n", g_hat); printf(" gamma-hat : %12.8f\n", _q->gamma_hat); printf(" v[%4u-1] : %12.8f\n", i0,vneg); printf(" v[%4u+0] : %12.8f\n", i0,v0 ); printf(" v[%4u+1] : %12.8f\n", i0,vpos); printf(" dphi-hat : %12.8f\n", _q->dphi_hat); printf(" phi-hat : %12.8f\n", _q->phi_hat); #endif // set flag _q->frame_detected = 1; // reset state // copy saved buffer state (last half of buf_time_1 to front half of buf_time_0) memmove(_q->buf_time_0, _q->buf_time_1 + _q->nfft/2, (_q->nfft/2)*sizeof(TI)); _q->state = QDETECTOR_STATE_SEEK; _q->x2_sum_0 = liquid_sumsqcf(_q->buf_time_0, _q->nfft/2); _q->x2_sum_1 = 0; _q->counter = _q->nfft/2; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/qdsync.proto.c000066400000000000000000000330531474751757600214350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Frame detector and synchronizer; uses a novel correlation method to // detect a synchronization pattern, estimate carrier frequency and // phase offsets as well as timing phase, then correct for these // impairments in a simple interface suitable for custom frame recovery. #include #include #include #include #include #include "liquid.internal.h" // push samples through detection stage int QDSYNC(_execute_detect)(QDSYNC() _q, float complex _x); // step receiver mixer, matched filter, decimator // _q : frame synchronizer // _x : input sample int QDSYNC(_step)(QDSYNC() _q, float complex _x); // append sample to output buffer int QDSYNC(_buf_append)(QDSYNC() _q, float complex _x); // main object definition struct QDSYNC(_s) { unsigned int seq_len; // preamble sequence length int ftype; // filter type unsigned int k; // samples per symbol unsigned int m; // filter semi-length float beta; // excess bandwidth factor QDSYNC(_callback) callback; // user-defined callback function void * context; // user-defined context object QDETECTOR() detector; // detector // status variables enum { QDSYNC_STATE_DETECT=0, // detect frame QDSYNC_STATE_SYNC, // apply carrier offset correction and matched filter } state; // frame synchronization state unsigned int symbol_counter;// counter: total number of symbols received including preamble sequence nco_crcf mixer; // coarse carrier frequency recovery // timing recovery objects, states firpfb_crcf mf; // matched filter/decimator unsigned int npfb; // number of filters in symsync int mf_counter; // matched filter output timer unsigned int pfb_index; // filterbank index // symbol buffer unsigned int buf_out_len;// output buffer length float complex * buf_out; // output buffer unsigned int buf_out_counter; // output counter }; // create detector with generic sequence QDSYNC() QDSYNC(_create_linear)(TI * _seq, unsigned int _seq_len, int _ftype, unsigned int _k, unsigned int _m, float _beta, QDSYNC(_callback) _callback, void * _context) { // validate input if (_seq_len == 0) return liquid_error_config("QDSYNC(_create)(), sequence length cannot be zero"); // allocate memory for main object and set internal properties QDSYNC() q = (QDSYNC()) malloc(sizeof(struct QDSYNC(_s))); q->seq_len = _seq_len; q->ftype = _ftype; q->k = _k; q->m = _m; q->beta = _beta; // create detector q->detector = QDETECTOR(_create_linear)(_seq, _seq_len, _ftype, _k, _m, _beta); // create down-coverters for carrier phase tracking q->mixer = nco_crcf_create(LIQUID_NCO); // create symbol timing recovery filters q->npfb = 256; // number of filters in the bank q->mf = firpfb_crcf_create_rnyquist(q->ftype, q->npfb, q->k, q->m, q->beta); // allocate buffer for storing output samples q->buf_out_len = 64; // user can re-size this later q->buf_out = (float complex*) malloc(q->buf_out_len*sizeof(float complex)); // set callback and context values QDSYNC(_set_callback)(q, _callback); QDSYNC(_set_context )(q, _context ); // reset and return object QDSYNC(_reset)(q); return q; } // copy object QDSYNC() QDSYNC(_copy)(QDSYNC() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qdetector_%s_copy(), object cannot be NULL", "cccf"); // create new object and copy base parameters QDSYNC() q_copy = (QDSYNC())malloc(sizeof(struct QDSYNC(_s))); memmove(q_copy, q_orig, sizeof(struct QDSYNC(_s))); // set callback and userdata fields q_copy->callback = q_orig->callback; q_copy->context = q_orig->context; // copy sub-objects q_copy->detector = QDETECTOR(_copy)(q_orig->detector); q_copy->mixer = nco_crcf_copy (q_orig->mixer); q_copy->mf = firpfb_crcf_copy (q_orig->mf); // copy memory in new allocation q_copy->buf_out = (float complex*)liquid_malloc_copy(q_orig->buf_out, q_orig->buf_out_len, sizeof(float complex)); // return new object return q_copy; } int QDSYNC(_destroy)(QDSYNC() _q) { // destroy internal objects QDETECTOR(_destroy)(_q->detector); nco_crcf_destroy(_q->mixer); firpfb_crcf_destroy(_q->mf); // free output buffer free(_q->buf_out); // free main object memory free(_q); return LIQUID_OK; } int QDSYNC(_reset)(QDSYNC() _q) { QDETECTOR(_reset)(_q->detector); _q->state = QDSYNC_STATE_DETECT; _q->symbol_counter = 0; _q->buf_out_counter = 0; firpfb_crcf_reset(_q->mf); return LIQUID_OK; } int QDSYNC(_print)(QDSYNC() _q) { printf("\n", _q->seq_len); return LIQUID_OK; } // get detection state int QDSYNC(_is_detected)(QDSYNC() _q) { return _q->state == QDSYNC_STATE_SYNC; } // get detection threshold float QDSYNC(_get_threshold)(QDSYNC() _q) { return QDETECTOR(_get_threshold)(_q->detector); } // set detection threshold int QDSYNC(_set_threshold)(QDSYNC() _q, float _threshold) { return QDETECTOR(_set_threshold)(_q->detector, _threshold); } // get carrier offset search range float QDSYNC(_get_range)(QDSYNC() _q) { return QDETECTOR(_get_range)(_q->detector); } // set carrier offset search range int QDSYNC(_set_range)(QDSYNC() _q, float _dphi_max) { return QDETECTOR(_set_range)(_q->detector, _dphi_max); } // set callback method int QDSYNC(_set_callback)(QDSYNC() _q, QDSYNC(_callback) _callback) { _q->callback = _callback; return LIQUID_OK; } // set context value int QDSYNC(_set_context)(QDSYNC() _q, void * _context) { _q->context = _context; return LIQUID_OK; } // Set callback buffer size (the number of symbol provided to the callback // whenever it is invoked). int QDSYNC(_set_buf_len)(QDSYNC() _q, unsigned int _buf_len) { if (_buf_len == 0) return liquid_error(LIQUID_EICONFIG,"QDSYNC(_set_buf_len)(), buffer length must be greater than 0"); // check current state if (_q->buf_out_counter < _buf_len) { // buffer might not be empty, but we aren't resizing within this space; // ok to resize so long as old samples are copied _q->buf_out_len = _buf_len; float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); if (buf_new == NULL) return liquid_error(LIQUID_EIMEM,"QDSYNC(_set_buf_len)(), could not allocate %u samples", _buf_len); _q->buf_out = buf_new; } else { // we are shrinking the buffer below the number of samples it currently // holds; invoke the callback as many times as needed to reduce its size unsigned int index = 0; while (_q->buf_out_counter >= _buf_len) { if (_q->callback != NULL) _q->callback(_q->buf_out + index, _buf_len, _q->context); // adjust counters index += _buf_len; _q->buf_out_counter -= _buf_len; } // copy old values to front of buffer memmove(_q->buf_out, _q->buf_out + index, _q->buf_out_counter*sizeof(float complex)); // now resize the buffer appropriately _q->buf_out_len = _buf_len; float complex * buf_new = (float complex*)realloc(_q->buf_out, _q->buf_out_len*sizeof(float complex)); if (buf_new == NULL) return liquid_error(LIQUID_EIMEM,"QDSYNC(_set_buf_len)(), could not allocate %u samples", _buf_len); _q->buf_out = buf_new; } return LIQUID_OK; } // execute synchronizer on a block of samples int QDSYNC(_execute)(QDSYNC() _q, TI * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { switch (_q->state) { case QDSYNC_STATE_DETECT: // detect frame (look for p/n sequence) QDSYNC(_execute_detect)(_q, _buf[i]); break; case QDSYNC_STATE_SYNC: // receive preamble sequence symbols QDSYNC(_step)(_q, _buf[i]); break; default: return liquid_error(LIQUID_EINT,"QDSYNC(_exeucte)(), unknown/unsupported state"); } } return LIQUID_OK; } int QDSYNC(_is_open)(QDSYNC() _q) { return _q->state == QDSYNC_STATE_DETECT ? 0 : 1; } // correlator output float QDSYNC(_get_rxy)(QDSYNC() _q) { return QDETECTOR(_get_rxy)(_q->detector); } // fractional timing offset estimate float QDSYNC(_get_tau)(QDSYNC() _q) { return QDETECTOR(_get_tau)(_q->detector); } // channel gain float QDSYNC(_get_gamma)(QDSYNC() _q) { return QDETECTOR(_get_gamma)(_q->detector); } // carrier frequency offset estimate float QDSYNC(_get_dphi)(QDSYNC() _q) { return QDETECTOR(_get_dphi)(_q->detector); } // carrier phase offset estimate float QDSYNC(_get_phi)(QDSYNC() _q) { return QDETECTOR(_get_phi)(_q->detector); } // // internal methods // // execute synchronizer, seeking preamble sequence // _q : frame synchronizer object // _x : input sample // _sym : demodulated symbol int QDSYNC(_execute_detect)(QDSYNC() _q, TI _x) { // push through pre-demod synchronizer float complex * v = QDETECTOR(_execute)(_q->detector, _x); // check if frame has been detected if (v != NULL) { // get estimates float tau_hat = QDETECTOR(_get_tau) (_q->detector); float gamma_hat = QDETECTOR(_get_gamma)(_q->detector); float dphi_hat = QDETECTOR(_get_dphi) (_q->detector); float phi_hat = QDETECTOR(_get_phi) (_q->detector); // set appropriate filterbank index _q->mf_counter = _q->k - 2; _q->pfb_index = 0; int index = (int)(tau_hat * _q->npfb); if (index < 0) { _q->mf_counter++; index += _q->npfb; } _q->pfb_index = index; //printf("* qdsync detected! tau:%6.3f, dphi:%12.4e, phi:%6.3f, gamma:%6.2f dB, mf:%u, pfb idx:%u\n", // tau_hat, dphi_hat, phi_hat, 20*log10f(gamma_hat), _q->mf_counter, _q->pfb_index); // output filter scale firpfb_crcf_set_scale(_q->mf, 1.0f / (_q->k * gamma_hat)); // set frequency/phase of mixer nco_crcf_set_frequency(_q->mixer, dphi_hat); nco_crcf_set_phase (_q->mixer, phi_hat ); // update state _q->state = QDSYNC_STATE_SYNC; // run buffered samples through synchronizer unsigned int buf_len = QDETECTOR(_get_buf_len)(_q->detector); QDSYNC(_execute)(_q, v, buf_len); } return LIQUID_OK; } // step receiver mixer, matched filter, decimator // _q : frame synchronizer // _x : input sample // _y : output symbol int QDSYNC(_step)(QDSYNC() _q, TI _x) { // mix sample down float complex v; nco_crcf_mix_down(_q->mixer, _x, &v); nco_crcf_step (_q->mixer); // push sample into filterbank firpfb_crcf_push (_q->mf, v); firpfb_crcf_execute(_q->mf, _q->pfb_index, &v); // increment counter to determine if sample is available _q->mf_counter++; int sample_available = (_q->mf_counter >= _q->k-1) ? 1 : 0; // set output sample if available if (sample_available) { // decrement counter by k=2 samples/symbol _q->mf_counter -= _q->k; // append to output QDSYNC(_buf_append)(_q, v); } // return flag return LIQUID_OK; } // append sample to output buffer int QDSYNC(_buf_append)(QDSYNC() _q, TO _x) { // account for filter delay _q->symbol_counter++; if (_q->symbol_counter <= 2*_q->m) return LIQUID_OK; // append sample to end of buffer _q->buf_out[_q->buf_out_counter] = _x; _q->buf_out_counter++; // check if buffer is full if (_q->buf_out_counter == _q->buf_out_len) { // reset counter _q->buf_out_counter = 0; // invoke callback if (_q->callback != NULL) { int rc = _q->callback(_q->buf_out, _q->buf_out_len, _q->context); if (rc) return QDSYNC(_reset)(_q); } } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/qpacketmodem.proto.c000066400000000000000000000343771474751757600226200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // qpacketmodem: convenient modulator/demodulator and packet encoder/decoder combination #include #include #include #include #include #include #include "liquid.internal.h" struct QPACKETMODEM(_s) { // properties MODEM() mod_payload; // payload modulator/demodulator packetizer p; // packet encoder/decoder unsigned int bits_per_symbol; // modulator bits/symbol unsigned int payload_dec_len; // number of decoded payload bytes unsigned char * payload_enc; // payload data (encoded bytes) unsigned char * payload_mod; // payload symbols (modulator output, demod input) unsigned int payload_enc_len; // number of encoded payload bytes unsigned int payload_bit_len; // number of bits in encoded payload unsigned int payload_mod_len; // number of symbols in encoded payload unsigned int n; // index into partially-received payload data float evm; // estimated error vector magnitude }; // create packet encoder QPACKETMODEM() QPACKETMODEM(_create)() { // allocate memory for main object QPACKETMODEM() q = (QPACKETMODEM()) malloc(sizeof(struct QPACKETMODEM(_s))); // create payload modem (initially QPSK, overridden by properties) q->mod_payload = MODEM(_create)(LIQUID_MODEM_QPSK); q->bits_per_symbol = 2; // initial memory allocation for payload q->payload_dec_len = 1; q->p = packetizer_create(q->payload_dec_len, LIQUID_CRC_NONE, LIQUID_FEC_NONE, LIQUID_FEC_NONE); // number of bytes in encoded payload q->payload_enc_len = packetizer_get_enc_msg_len(q->p); // number of bits in encoded payload q->payload_bit_len = 8*q->payload_enc_len; // number of symbols in encoded payload div_t d = div(q->payload_bit_len, q->bits_per_symbol); q->payload_mod_len = d.quot + (d.rem ? 1 : 0); // soft demodulator uses one byte to represent each soft bit q->payload_enc = (unsigned char*) malloc(q->bits_per_symbol*q->payload_mod_len*sizeof(unsigned char)); // set symbol length appropriately q->payload_mod_len = q->payload_enc_len * q->bits_per_symbol; // for QPSK q->payload_mod = (unsigned char*) malloc(q->payload_mod_len*sizeof(unsigned char)); q->n = 0; // return pointer to main object return q; } // copy object QPACKETMODEM() QPACKETMODEM(_copy)(QPACKETMODEM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qpacketmodem_copy(), object cannot be NULL"); // create new object QPACKETMODEM() q_copy = QPACKETMODEM(_create)(); // configure identically as original unsigned int payload_len = q_orig->payload_dec_len; crc_scheme check = packetizer_get_crc (q_orig->p); fec_scheme fec0 = packetizer_get_fec0(q_orig->p); fec_scheme fec1 = packetizer_get_fec1(q_orig->p); int ms = MODEM(_get_scheme )(q_orig->mod_payload); QPACKETMODEM(_configure)(q_copy, payload_len, check, fec0, fec1, ms); // return new object return q_copy; } // destroy object, freeing all internal arrays int QPACKETMODEM(_destroy)(QPACKETMODEM() _q) { // free objects packetizer_destroy(_q->p); MODEM(_destroy)(_q->mod_payload); // free arrays free(_q->payload_enc); free(_q->payload_mod); free(_q); return LIQUID_OK; } // reset object int QPACKETMODEM(_reset)(QPACKETMODEM() _q) { return MODEM(_reset)(_q->mod_payload); } // print object internals int QPACKETMODEM(_print)(QPACKETMODEM() _q) { printf("p)][0]); printf(", fec_0=\"%s\"", fec_scheme_str[packetizer_get_fec0(_q->p)][0]); printf(", fec_1=\"%s\"", fec_scheme_str[packetizer_get_fec1(_q->p)][0]); printf(", ms=\"%s\"", modulation_types[MODEM(_get_scheme)(_q->mod_payload)].name); printf(", dec=%u", _q->payload_dec_len); printf(", enc=%u", _q->payload_enc_len); printf(", bit=%u", _q->payload_bit_len); printf(", mod=%u", _q->payload_mod_len); printf(">\n"); return LIQUID_OK; } // int QPACKETMODEM(_configure)(QPACKETMODEM() _q, unsigned int _payload_len, crc_scheme _check, fec_scheme _fec0, fec_scheme _fec1, int _ms) { // set new decoded message length _q->payload_dec_len = _payload_len; // recreate modem object and get new bits per symbol _q->mod_payload = MODEM(_recreate)(_q->mod_payload, _ms); _q->bits_per_symbol = MODEM(_get_bps)(_q->mod_payload); // recreate packetizer object and compute new encoded payload length _q->p = packetizer_recreate(_q->p, _q->payload_dec_len, _check, _fec0, _fec1); _q->payload_enc_len = packetizer_get_enc_msg_len(_q->p); // number of bits in encoded payload _q->payload_bit_len = 8*_q->payload_enc_len; // number of symbols in encoded payload div_t d = div(_q->payload_bit_len, _q->bits_per_symbol); _q->payload_mod_len = d.quot + (d.rem ? 1 : 0); // encoded payload array (leave room for soft-decision decoding) _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->bits_per_symbol*_q->payload_mod_len*sizeof(unsigned char)); // reallocate memory for modem symbols _q->payload_mod = (unsigned char*) realloc(_q->payload_mod, _q->payload_mod_len*sizeof(unsigned char)); _q->n = 0; _q->evm = 0.0f; return LIQUID_OK; } // get length of encoded frame in symbols unsigned int QPACKETMODEM(_get_frame_len)(QPACKETMODEM() _q) { return _q->payload_mod_len; } // get unencoded/decoded payload length (bytes) unsigned int QPACKETMODEM(_get_payload_len)(QPACKETMODEM() _q) { // number of decoded payload bytes return _q->payload_dec_len; } unsigned int QPACKETMODEM(_get_crc)(QPACKETMODEM() _q) { return packetizer_get_crc(_q->p); } unsigned int QPACKETMODEM(_get_fec0)(QPACKETMODEM() _q) { return packetizer_get_fec0(_q->p); } unsigned int QPACKETMODEM(_get_fec1)(QPACKETMODEM() _q) { return packetizer_get_fec1(_q->p); } unsigned int QPACKETMODEM(_get_modscheme)(QPACKETMODEM() _q) { return MODEM(_get_scheme)(_q->mod_payload); } float QPACKETMODEM(_get_demodulator_phase_error)(QPACKETMODEM() _q) { return MODEM(_get_demodulator_phase_error)(_q->mod_payload); } float QPACKETMODEM(_get_demodulator_evm)(QPACKETMODEM() _q) { return _q->evm; } // encode packet into un-modulated frame symbol indices // _q : qpacketmodem object // _payload : unencoded payload bytes // _syms : encoded but un-modulated payload symbol indices int QPACKETMODEM(_encode_syms)(qpacketmodem _q, const unsigned char * _payload, unsigned char * _syms) { // encode payload packetizer_encode(_q->p, _payload, _q->payload_enc); // clear internal payload memset(_q->payload_mod, 0x00, _q->payload_mod_len); // repack 8-bit payload bytes into 'bps'-bit payload symbols unsigned int bps = _q->bits_per_symbol; unsigned int num_written; liquid_repack_bytes(_q->payload_enc, 8, _q->payload_enc_len, _syms, bps, _q->payload_mod_len, &num_written); if (num_written != _q->payload_mod_len) return liquid_error(LIQUID_EINT,"qpacketmodem_encode_syms(), internal unexpected number of symbols"); return LIQUID_OK; } // decode packet from demodulated frame symbol indices (hard-decision decoding) // _q : qpacketmodem object // _syms : received hard-decision symbol indices // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode_syms)(qpacketmodem _q, unsigned char * _syms, unsigned char * _payload) { // pack bytes into payload array unsigned int bps = _q->bits_per_symbol; unsigned int num_written; liquid_repack_bytes(_syms, bps, _q->payload_mod_len, _q->payload_enc, 8, _q->payload_mod_len, // NOTE: payload_enc allocation is actually payload_mod_len bytes &num_written); //assert(num_written == _q->payload_enc_len); // NOTE: this will fail for bps in {3,5,6,7} // decode payload return packetizer_decode(_q->p, _q->payload_enc, _payload); } // decode packet from demodulated frame bits (soft-decision decoding) // _q : qpacketmodem object // _bits : received soft-decision bits // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode_bits)(qpacketmodem _q, unsigned char * _bits, unsigned char * _payload) { // decode payload (soft-decision) return packetizer_decode_soft(_q->p, _bits, _payload); } // encode and modulate packet into modulated frame samples // _q : qpacketmodem object // _payload : unencoded payload bytes // _frame : encoded/modulated payload symbols int QPACKETMODEM(_encode)(qpacketmodem _q, const unsigned char * _payload, TO * _frame) { // encode payload symbols into internal buffer QPACKETMODEM(_encode_syms)(_q, _payload, _q->payload_mod); // modulate symbols unsigned int i; for (i=0; i<_q->payload_mod_len; i++) MODEM(_modulate)(_q->mod_payload, _q->payload_mod[i], &_frame[i]); return LIQUID_OK; } // decode packet from modulated frame samples, returning flag if CRC passed // _q : qpacketmodem object // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode)(qpacketmodem _q, TO * _frame, unsigned char * _payload) { unsigned int i; // demodulate and pack bytes into decoder input buffer unsigned int sym; //memset(_q->payload_enc, 0x00, _q->payload_enc_len*sizeof(unsigned char)); _q->evm = 0.0f; for (i=0; i<_q->payload_mod_len; i++) { // demodulate symbol MODEM(_demodulate)(_q->mod_payload, _frame[i], &sym); // accumulate error vector magnitude estimate float e = MODEM(_get_demodulator_evm)(_q->mod_payload); _q->evm += e*e; // pack decoded symbol into array liquid_pack_array(_q->payload_enc, _q->payload_enc_len, i * _q->bits_per_symbol, _q->bits_per_symbol, sym); } // update internal error vector magnitude estimate _q->evm = 10*log10f(_q->evm / (float)(_q->payload_mod_len)); // decode payload, returning flag if decoded payload is valid return packetizer_decode(_q->p, _q->payload_enc, _payload); } // decode packet from modulated frame samples, returning flag if CRC passed // _q : qpacketmodem object // _frame : encoded/modulated payload symbols // _payload : recovered decoded payload bytes int QPACKETMODEM(_decode_soft)(qpacketmodem _q, TO * _frame, unsigned char * _payload) { unsigned int i; // demodulate and pack bytes into decoder input buffer unsigned int sym; //memset(_q->payload_enc, 0x00, _q->payload_enc_len*sizeof(unsigned char)); unsigned int n = 0; _q->evm = 0.0f; for (i=0; i<_q->payload_mod_len; i++) { // demodulate symbol MODEM(_demodulate_soft)(_q->mod_payload, _frame[i], &sym, _q->payload_enc+n); n += _q->bits_per_symbol; // accumulate error vector magnitude estimate float e = MODEM(_get_demodulator_evm)(_q->mod_payload); _q->evm += e*e; } //printf("received %u bits (expected %u)\n", n, _q->payload_mod_len * _q->bits_per_symbol); assert( n == _q->payload_mod_len * _q->bits_per_symbol); // update internal error vector magnitude estimate _q->evm = 10*log10f(_q->evm / (float)(_q->payload_mod_len)); // decode payload, returning flag if decoded payload is valid return packetizer_decode_soft(_q->p, _q->payload_enc, _payload); } // decode symbol from modulated frame samples, returning flag if all symbols received int QPACKETMODEM(_decode_soft_sym)(qpacketmodem _q, TO _symbol) { unsigned int sym; MODEM(_demodulate_soft)(_q->mod_payload, _symbol, &sym, _q->payload_enc + _q->n); _q->n += _q->bits_per_symbol; return _q->n == _q->payload_mod_len * _q->bits_per_symbol; } int QPACKETMODEM(_decode_soft_payload)(qpacketmodem _q, unsigned char * _payload) { if ( _q->n != _q->payload_mod_len * _q->bits_per_symbol) { liquid_error(LIQUID_ENOINIT,"qpacketmodem_decode_soft_payload(), insufficient number of symbols received"); return 0; } _q->n = 0; return packetizer_decode_soft(_q->p, _q->payload_enc, _payload); } liquid-dsp-1.7.0/src/framing/src/qpilotgen.c000066400000000000000000000135031474751757600207720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // pilot injection #include #include #include #include #include #include #include #include "liquid.internal.h" // get number of pilots in frame unsigned int qpilot_num_pilots(unsigned int _payload_len, unsigned int _pilot_spacing) { if (_payload_len == 0 || _pilot_spacing < 2) return 0; div_t d = div(_payload_len,(_pilot_spacing - 1)); return d.quot + (d.rem ? 1 : 0); } // get length of frame with a particular payload length and pilot spacing unsigned int qpilot_frame_len(unsigned int _payload_len, unsigned int _pilot_spacing) { return _payload_len + qpilot_num_pilots(_payload_len, _pilot_spacing); } struct qpilotgen_s { // properties unsigned int payload_len; // number of samples in payload unsigned int pilot_spacing; // spacing between pilot symbols unsigned int num_pilots; // total number of pilot symbols unsigned int frame_len; // total number of frame symbols float complex * pilots; // pilot sequence }; // create packet encoder qpilotgen qpilotgen_create(unsigned int _payload_len, unsigned int _pilot_spacing) { // validate input if (_payload_len == 0) return liquid_error_config("qpilotgen_create(), frame length must be at least 1 symbol"); if (_pilot_spacing < 2) return liquid_error_config("qpilotgen_create(), pilot spacing must be at least 2 symbols"); unsigned int i; // allocate memory for main object qpilotgen q = (qpilotgen) malloc(sizeof(struct qpilotgen_s)); // set internal properties q->payload_len = _payload_len; q->pilot_spacing = _pilot_spacing; // derived values q->num_pilots = qpilot_num_pilots(q->payload_len, q->pilot_spacing); q->frame_len = q->payload_len + q->num_pilots; // allocate memory for pilots q->pilots = (float complex*) malloc(q->num_pilots*sizeof(float complex)); // find appropriate sequence size unsigned int m = liquid_nextpow2(q->num_pilots); // generate pilot sequence msequence seq = msequence_create_default(m); for (i=0; inum_pilots; i++) { // generate symbol unsigned int s = msequence_generate_symbol(seq, 2); // save modulated symbol float theta = (2 * M_PI * (float)s / 4.0f) + M_PI / 4.0f; q->pilots[i] = cexpf(_Complex_I*theta); } msequence_destroy(seq); // reset and return pointer to main object qpilotgen_reset(q); return q; } // recreate packet encoder qpilotgen qpilotgen_recreate(qpilotgen _q, unsigned int _payload_len, unsigned int _pilot_spacing) { // TODO: only re-generate objects as necessary // destroy object if (_q != NULL) qpilotgen_destroy(_q); // create new object return qpilotgen_create(_payload_len, _pilot_spacing); } // Copy object including all internal objects and state qpilotgen qpilotgen_copy(qpilotgen q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qpilotgen_copy(), object cannot be NULL"); // create new object from parameters return qpilotgen_create(q_orig->payload_len, q_orig->pilot_spacing); } int qpilotgen_destroy(qpilotgen _q) { free(_q->pilots); // free arrays free(_q); // free main object memory return LIQUID_OK; } int qpilotgen_reset(qpilotgen _q) { return LIQUID_OK; } int qpilotgen_print(qpilotgen _q) { printf("\n", _q->payload_len, _q->frame_len, _q->num_pilots); return LIQUID_OK; } // get length of frame in symbols unsigned int qpilotgen_get_frame_len(qpilotgen _q) { return _q->frame_len; } // encode packet into modulated frame samples // TODO: include method with just symbol indices? would be useful for // non-linear modulation types int qpilotgen_execute(qpilotgen _q, float complex * _payload, float complex * _frame) { unsigned int i; unsigned int n = 0; unsigned int p = 0; for (i=0; i<_q->frame_len; i++) { if ( (i % _q->pilot_spacing)==0 ) _frame[i] = _q->pilots[p++]; else _frame[i] = _payload[n++]; } //printf("n = %u (expected %u)\n", n, _q->payload_len); //printf("p = %u (expected %u)\n", p, _q->num_pilots); if (n != _q->payload_len) return liquid_error(LIQUID_EINT,"qpilotgen_execute(), unexpected internal payload length"); if (p != _q->num_pilots) return liquid_error(LIQUID_EINT,"qpilotgen_execute(), unexpected internal number of pilots"); return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/qpilotsync.c000066400000000000000000000251051474751757600211760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // symbol recovery with interleaved pilots #include #include #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_QPILOTSYNC 0 struct qpilotsync_s { // properties unsigned int payload_len; // number of samples in payload unsigned int pilot_spacing; // spacing between pilot symbols unsigned int num_pilots; // total number of pilot symbols unsigned int frame_len; // total number of frame symbols float complex * pilots; // pilot sequence unsigned int nfft; // FFT size float complex * buf_time; // FFT time buffer float complex * buf_freq; // FFT freq buffer FFT_PLAN fft; // transform object float dphi_hat; // carrier frequency offset estimate float phi_hat; // carrier phase offset estimate float g_hat; // gain correction estimate float evm_hat; // error-vector magnitude estimate (from pilots) }; // create packet encoder qpilotsync qpilotsync_create(unsigned int _payload_len, unsigned int _pilot_spacing) { // validate input if (_payload_len == 0) return liquid_error_config("qpilotsync_create(), frame length must be at least 1 symbol"); if (_pilot_spacing < 2) return liquid_error_config("qpilotsync_create(), pilot spacing must be at least 2 symbols"); // allocate memory for main object qpilotsync q = (qpilotsync) malloc(sizeof(struct qpilotsync_s)); // set internal properties q->payload_len = _payload_len; q->pilot_spacing = _pilot_spacing; // derived values q->num_pilots = qpilot_num_pilots(q->payload_len, q->pilot_spacing); q->frame_len = q->payload_len + q->num_pilots; // allocate memory for pilots q->pilots = (float complex*) malloc(q->num_pilots*sizeof(float complex)); // find appropriate sequence size unsigned int m = liquid_nextpow2(q->num_pilots); // generate pilot sequence unsigned int i; msequence seq = msequence_create_default(m); for (i=0; inum_pilots; i++) { // generate symbol unsigned int s = msequence_generate_symbol(seq, 2); // save modulated symbol float theta = (2 * M_PI * (float)s / 4.0f) + M_PI / 4.0f; q->pilots[i] = cexpf(_Complex_I*theta); } msequence_destroy(seq); // compute fft size and create transform objects q->nfft = 1 << liquid_nextpow2(q->num_pilots + (q->num_pilots>>1)); q->buf_time = (float complex*) FFT_MALLOC(q->nfft*sizeof(float complex)); q->buf_freq = (float complex*) FFT_MALLOC(q->nfft*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->nfft, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, 0); // reset and return pointer to main object qpilotsync_reset(q); return q; } // recreate packet encoder qpilotsync qpilotsync_recreate(qpilotsync _q, unsigned int _payload_len, unsigned int _pilot_spacing) { // TODO: only re-generate objects as necessary // destroy object if (_q != NULL) qpilotsync_destroy(_q); // create new object return qpilotsync_create(_payload_len, _pilot_spacing); } // Copy object including all internal objects and state qpilotsync qpilotsync_copy(qpilotsync q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qpilotsync_copy(), object cannot be NULL"); // create new object from parameters return qpilotsync_create(q_orig->payload_len, q_orig->pilot_spacing); } int qpilotsync_destroy(qpilotsync _q) { // free arrays free(_q->pilots); FFT_FREE(_q->buf_time); FFT_FREE(_q->buf_freq); // destroy objects FFT_DESTROY_PLAN(_q->fft); // free main object memory free(_q); return LIQUID_OK; } int qpilotsync_reset(qpilotsync _q) { // clear FFT input buffer unsigned int i; for (i=0; i<_q->nfft; i++) _q->buf_time[i] = 0.0f; // reset estimates _q->dphi_hat = 0.0f; _q->phi_hat = 0.0f; _q->g_hat = 1.0f; return LIQUID_OK; } int qpilotsync_print(qpilotsync _q) { printf("\n", _q->payload_len, _q->frame_len, _q->num_pilots, _q->nfft); return LIQUID_OK; } // get length of frame in symbols unsigned int qpilotsync_get_frame_len(qpilotsync _q) { return _q->frame_len; } // encode packet into modulated frame samples // TODO: include method with just symbol indices? would be useful for // non-linear modulation types int qpilotsync_execute(qpilotsync _q, float complex * _frame, float complex * _payload) { unsigned int i; unsigned int n = 0; unsigned int p = 0; // extract pilots and de-rotate with known sequence for (i=0; i<_q->num_pilots; i++) { _q->buf_time[i] = _frame[i*_q->pilot_spacing] * conjf(_q->pilots[i]); #if DEBUG_QPILOTSYNC printf("(%8.4f,%8.4f) = (%8.4f,%8.4f) * conj(%8.4f,%8.4f)\n", crealf(_q->buf_time[i]), cimagf(_q->buf_time[i]), crealf(_frame[i*_q->pilot_spacing]), cimagf(_frame[i*_q->pilot_spacing]), crealf(_q->pilots[i]), cimagf(_q->pilots[i])); #endif } // compute frequency offset by computing transform and finding peak FFT_EXECUTE(_q->fft); unsigned int i0 = 0; float y0 = 0; for (i=0; i<_q->nfft; i++) { #if DEBUG_QPILOTSYNC printf("X(%3u) = %12.8f + 1i*%12.8f; %% %12.8f\n", i+1, crealf(_q->buf_freq[i]), cimagf(_q->buf_freq[i]), cabsf(_q->buf_freq[i])); #endif if (i==0 || cabsf(_q->buf_freq[i]) > y0) { i0 = i; y0 = cabsf(_q->buf_freq[i]); } } // interpolate and recover frequency unsigned int ineg = (i0 + _q->nfft - 1) % _q->nfft; unsigned int ipos = (i0 + 1) % _q->nfft; float ypos = cabsf(_q->buf_freq[ipos]); float yneg = cabsf(_q->buf_freq[ineg]); float a = 0.5f*(ypos + yneg) - y0; float b = 0.5f*(ypos - yneg); //float c = y0; float idx = -b / (2.0f*a); //-0.5f*(ypos - yneg) / (ypos + yneg - 2*y0); float index = (float)i0 + idx; _q->dphi_hat = (i0 > _q->nfft/2 ? index-(float)_q->nfft : index) * 2*M_PI / (float)(_q->nfft * _q->pilot_spacing); #if DEBUG_QPILOTSYNC printf("X[%3u] = %12.8f <%12.8f>\n", ineg, yneg, cargf(_q->buf_freq[ineg])); printf("X[%3u] = %12.8f <%12.8f>\n", i0, y0, cargf(_q->buf_freq[i0])); printf("X[%3u] = %12.8f <%12.8f>\n", ipos, ypos, cargf(_q->buf_freq[ipos])); printf("yneg = %12.8f;\n", yneg); printf("ypos = %12.8f;\n", ypos); printf("y0 = %12.8f;\n", y0); printf("interpolated peak at %12.8f (%u + %12.8f)\n", index, i0, idx); #endif // estimate carrier phase offset #if 0 // METHOD 1: linear interpolation of phase in FFT output buffer float v0 = cargf(_q->buf_freq[ idx < 0 ? ineg : i0 ]); float v1 = cargf(_q->buf_freq[ idx < 0 ? i0 : ipos ]); float xp = idx < 0 ? 1+idx : idx; float phi_hat = (v1-v0)*xp + v0; //printf("v0 = %12.8f, v1 = %12.8f, xp = %12.8f\n", v0, v1, xp); // channel gain: use quadratic interpolation of FFT amplitude to find peak // correlation output in the frequency domain float g_hat = (a*idx*idx + b*idx + c) / (float)(_q->num_pilots); #else // METHOD 2: compute metric by de-rotating pilots and measuring resulting phase // NOTE: this is possibly more accurate than the above method but might also // be more computationally complex float complex metric = 0; for (i=0; i<_q->num_pilots; i++) metric += _q->buf_time[i] * cexpf(-_Complex_I*_q->dphi_hat*i*(float)(_q->pilot_spacing)); //printf("metric : %12.8f <%12.8f>\n", cabsf(metric), cargf(metric)); _q->phi_hat = cargf(metric); _q->g_hat = cabsf(metric) / (float)(_q->num_pilots); #endif // frequency correction float g = 1.0f / _q->g_hat; // recover frame symbols _q->evm_hat = 0.0f; for (i=0; i<_q->frame_len; i++) { float complex v = g * _frame[i] * cexpf(-_Complex_I*(_q->dphi_hat*i + _q->phi_hat)); if ( (i % _q->pilot_spacing)==0 ) { // pilot symbol float complex e = _q->pilots[p] - v; _q->evm_hat += crealf( e * conjf(e) ); p++; } else { // data symbol _payload[n++] = v; } } _q->evm_hat = 10*log10f( _q->evm_hat / (float)(_q->num_pilots) ); #if DEBUG_QPILOTSYNC // print estimates of carrier frequency, phase, gain printf("dphi-hat : %12.8f\n", _q->dphi_hat); printf(" phi-hat : %12.8f\n", _q->phi_hat); printf(" g-hat : %12.8f\n", _q->g_hat); printf(" evm-hat : %12.8f\n", _q->evm_hat); #endif if (n != _q->payload_len) return liquid_error(LIQUID_EINT,"qpilotsync_execute(), unexpected internal payload length"); if (p != _q->num_pilots) return liquid_error(LIQUID_EINT,"qpilotsync_execute(), unexpected internal number of pilots"); return LIQUID_OK; } // get estimates float qpilotsync_get_dphi(qpilotsync _q) { return _q->dphi_hat; } float qpilotsync_get_phi(qpilotsync _q) { return _q->phi_hat; } float qpilotsync_get_gain(qpilotsync _q) { return _q->g_hat; } float qpilotsync_get_evm(qpilotsync _q) { return _q->evm_hat; } liquid-dsp-1.7.0/src/framing/src/qsource.proto.c000066400000000000000000000451711474751757600216210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Generic single signal source generator // #include #include #include #include #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) // internal structure (single source) struct QSOURCE(_s) { // common parameters int id; // unique id unsigned int M; // number of channels in parent object's synthesis channelizer unsigned int P; // number of channels in this object's analysis channelizer unsigned int m; // channelizer filter semi-length float as; // channelizer filter stop-band suppression (dB) float fc; // signal normalized center frequency float bw; // signal normalized bandwidth unsigned int index; // base index resamp_crcf resamp; // arbitrary rate resampler nco_crcf mixer; // fine frequency adjustment float gain; // signal gain (user defined) float gain_ch; // channelizer gain unsigned int buf_len; // temporary buffer for resampler output float complex * buf; // sample buffer (resamp output), [size: buf_len x 1] float complex * buf_time; // channelizer input buffer, [size: P/2 x 1] float complex * buf_freq; // channelizer input buffer, [size: P x 1] firpfbch2_crcf ch; // analysis channelizer int enabled; // signal enabled? uint64_t num_samples;// total number of output samples generated // signal type enum { QSOURCE_UNKNOWN=0, QSOURCE_USER, QSOURCE_TONE, QSOURCE_CHIRP, QSOURCE_NOISE, QSOURCE_MODEM, QSOURCE_FSK, QSOURCE_GMSK, } type; // memory object for specific signal sources union { struct { void * userdata; MSOURCE(_callback) callback; } user; struct { } tone; struct { NCO() nco; float df; int negate, single; uint64_t num, timer; } chirp; struct { } noise; struct { SYMSTREAM() symstream; } linmod; struct { fskmod mod; float complex * buf; unsigned int len, index, mask; } fsk; struct { gmskmod mod; float complex buf[2]; int index; } gmsk; } source; }; QSOURCE() QSOURCE(_create)(unsigned int _M, unsigned int _m, float _as, float _fc, float _bw, float _gain) { // validate input if (_M < 2 || (_M % 2)) return liquid_error_config("qsource%s_create(), invalid channelizer size (%u); must be even and greater than 1",EXTENSION,_M); if (_m == 0) return liquid_error_config("qsource%s_create(), invalid channelizer filter semi-length (%u); must be greater than 0",EXTENSION,_m); if (_fc < -0.5f || _fc > 0.5f) return liquid_error_config("qsource%s_create(), invalid frequency offset (%f); must be in [-0.5,0.5]",EXTENSION,_fc); if (_bw < 0.0f || _bw > 1.0f) return liquid_error_config("qsource%s_create(), invalid bandwidth (%f); must be in [0,1]",EXTENSION,_fc); // allocate memory for main object QSOURCE() q = (QSOURCE()) malloc( sizeof(struct QSOURCE(_s)) ); // initialize state q->id = -1; // default identifier q->type = QSOURCE_UNKNOWN; // default type q->gain = powf(10.0f, _gain/20.0f); // user-defined gain q->enabled = 1; // enabled by default q->num_samples = 0; // no output samples generated yet q->fc = _fc; // center frequency (relative to sample rate) q->bw = _bw; // bandwidth (relative to sample rate) // set channelizer values appropriately q->M = _M; q->P = 2*(unsigned int)ceilf( 0.5 * _bw * _M ); q->P = max(2, q->P); // allow P to exceed M for cases where wider bandwidth is needed (e.g. modem) q->m = _m; q->as= _as; // create resampler to correct for rate offset float rate = _bw == 0 ? 1.0f : _bw * (float)(q->M) / (float)(q->P); q->resamp = resamp_crcf_create(rate, 12, 0.45f, q->as, 64); // create mixer for frequency offset correction q->mixer = NCO(_create)(LIQUID_VCO); QSOURCE(_set_frequency)(q, _fc); // create buffers q->buf_len = 64; q->buf = (float complex*) malloc(q->buf_len * sizeof(float complex)); q->buf_time = (float complex*) malloc(q->P/2 * sizeof(float complex)); q->buf_freq = (float complex*) malloc(q->P * sizeof(float complex)); // create channelizer q->ch = firpfbch2_crcf_create_kaiser(LIQUID_ANALYZER, q->P, q->m, q->as); // channelizer gain correction q->gain_ch = sqrtf((float)(q->P)/(float)(q->M)); // reset and return main object QSOURCE(_reset)(q); return q; } // copy object QSOURCE() QSOURCE(_copy)(QSOURCE() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("qsource%s_copy(), object cannot be NULL", EXTENSION); // create filter object and copy base parameters QSOURCE() q_copy = (QSOURCE()) malloc(sizeof(struct QSOURCE(_s))); memmove(q_copy, q_orig, sizeof(struct QSOURCE(_s))); // copy main objects q_copy->resamp = resamp_crcf_copy(q_orig->resamp); q_copy->mixer = nco_crcf_copy (q_orig->mixer); q_copy->buf = (float complex*) liquid_malloc_copy(q_orig->buf, q_orig->buf_len, sizeof(float complex)); q_copy->buf_time = (float complex*) liquid_malloc_copy(q_orig->buf_time, q_orig->P/2, sizeof(float complex)); q_copy->buf_freq = (float complex*) liquid_malloc_copy(q_orig->buf_freq, q_orig->P, sizeof(float complex)); q_copy->ch = firpfbch2_crcf_copy(q_orig->ch); // copy type-specific values // free internal type-specific objects switch (q_copy->type) { case QSOURCE_UNKNOWN: break; case QSOURCE_USER: break; case QSOURCE_TONE: break; case QSOURCE_CHIRP: q_copy->source.chirp.nco = NCO(_copy)(q_orig->source.chirp.nco); break; case QSOURCE_NOISE: break; case QSOURCE_MODEM: q_copy->source.linmod.symstream = SYMSTREAM(_copy)(q_orig->source.linmod.symstream); break; case QSOURCE_FSK: q_copy->source.fsk.mod = fskmod_copy(q_orig->source.fsk.mod); q_copy->source.fsk.buf = (float complex*)liquid_malloc_copy( q_orig->source.fsk.buf, q_orig->source.fsk.len, sizeof(float complex)); break; case QSOURCE_GMSK: q_copy->source.gmsk.mod = gmskmod_copy(q_orig->source.gmsk.mod); break; default: return liquid_error_config("qsource%s_copy(), invalid internal state",EXTENSION); } return q_copy; } int QSOURCE(_destroy)(QSOURCE() _q) { // free internal type-specific objects switch (_q->type) { case QSOURCE_UNKNOWN: break; case QSOURCE_USER: break; case QSOURCE_TONE: break; case QSOURCE_CHIRP: NCO(_destroy)(_q->source.chirp.nco); break; case QSOURCE_NOISE: break; case QSOURCE_MODEM: SYMSTREAM(_destroy)(_q->source.linmod.symstream); break; case QSOURCE_FSK: fskmod_destroy(_q->source.fsk.mod); free(_q->source.fsk.buf); break; case QSOURCE_GMSK: gmskmod_destroy(_q->source.gmsk.mod); break; default: return liquid_error(LIQUID_EINT,"qsource%s_destroy(), invalid internal state",EXTENSION); } // free buffers free(_q->buf); free(_q->buf_time); free(_q->buf_freq); // destroy main internal objects firpfbch2_crcf_destroy(_q->ch); resamp_crcf_destroy (_q->resamp); NCO(_destroy) (_q->mixer); // free main object memory free(_q); return LIQUID_OK; } // initialize source with user-defined callback for generating samples int QSOURCE(_init_user)(QSOURCE() _q, void * _userdata, void * _callback) { _q->type = QSOURCE_USER; _q->source.user.userdata = _userdata; _q->source.user.callback = (MSOURCE(_callback))_callback; return LIQUID_OK; } // initialize source with tone source int QSOURCE(_init_tone)(QSOURCE() _q) { _q->type = QSOURCE_TONE; return LIQUID_OK; } // Add chirp to signal generator, returning id of signal // _q : signal source object // _duration : duration of chirp [samples] // _negate : negate frequency direction // _single : run single chirp? or repeatedly int QSOURCE(_init_chirp)(QSOURCE() _q, float _duration, int _negate, int _single) { _q->type = QSOURCE_CHIRP; _q->source.chirp.nco = NCO(_create)(LIQUID_VCO); _q->source.chirp.negate = _negate ? 1 : 0; _q->source.chirp.single = _single ? 1 : 0; _q->source.chirp.num = (uint64_t) roundf(_duration * _q->bw); _q->source.chirp.df = 2*M_PI / (float)(_q->source.chirp.num) * (_q->source.chirp.negate ? -1 : 1); // initialize properties NCO(_set_frequency)(_q->source.chirp.nco, _q->source.chirp.negate ? M_PI : -M_PI); _q->source.chirp.timer = _q->source.chirp.num; return LIQUID_OK; } // initialize source with noise source int QSOURCE(_init_noise)(QSOURCE() _q) { _q->type = QSOURCE_NOISE; return LIQUID_OK; } // initialize source with linear modulation generator int QSOURCE(_init_modem)(QSOURCE() _q, int _ms, unsigned int _m, float _beta) { _q->type = QSOURCE_MODEM; _q->source.linmod.symstream=SYMSTREAM(_create_linear)(LIQUID_FIRFILT_ARKAISER,2,_m,_beta,_ms); return LIQUID_OK; } // initialize source with frequency-shift keying modem int QSOURCE(_init_fsk)(QSOURCE() _q, unsigned int _m, unsigned int _k) { _q->type = QSOURCE_FSK; _q->source.fsk.mod = fskmod_create(_m, _k, 0.25f); _q->source.fsk.len = _k; // buffer length _q->source.fsk.buf = (float complex*)malloc(_k*sizeof(float complex)); _q->source.fsk.mask = (1 << _m) - 1; _q->source.fsk.index= 0; return LIQUID_OK; } // initialize source with Gauss minimum-shift keying modem int QSOURCE(_init_gmsk)(QSOURCE() _q, unsigned int _m, float _bt) { _q->type = QSOURCE_GMSK; _q->source.gmsk.mod = gmskmod_create(2,_m,_bt); _q->source.gmsk.index = 0; return LIQUID_OK; } // print basic info to stdout int QSOURCE(_print)(QSOURCE() _q) { // TODO: print generic parameters printf("id); // print type-specific parameters float bw = _q->bw; switch (_q->type) { case QSOURCE_USER: printf(", type=\"user\""); break; case QSOURCE_TONE: printf(", type=\"tone\""); break; case QSOURCE_CHIRP: printf(", type=\"chirp\""); break; case QSOURCE_NOISE: printf(", type=\"noise\""); break; case QSOURCE_MODEM: printf(", type=\"modem\""); bw *= 0.5f; break; case QSOURCE_FSK: printf(", type=\"fsk\""); bw *= 0.5f; break; case QSOURCE_GMSK: printf(", type=\"gmsk\""); bw *= 0.5f; break; default: return liquid_error(LIQUID_EINT,"qsource%s_print(), invalid internal state",EXTENSION); } printf(", fc=%g, bw=%g, P=%u, m=%u, as=%g, gain=%g, enabled=%u>\n", _q->fc, bw, _q->P, _q->m, _q->as, QSOURCE(_get_gain)(_q), _q->enabled); return LIQUID_OK; } // reset object internals // NOTE: placeholder for future functionality int QSOURCE(_reset)(QSOURCE() _q) { return LIQUID_OK; } // set internal object identifier int QSOURCE(_set_id)(QSOURCE() _q, int _id) { _q->id = _id; return LIQUID_OK; } // get internal object identifier int QSOURCE(_get_id)(QSOURCE() _q) { return _q->id; } // enable source generation int QSOURCE(_enable)(QSOURCE() _q) { _q->enabled = 1; return LIQUID_OK; } // disable source generation int QSOURCE(_disable)(QSOURCE() _q) { _q->enabled = 0; return LIQUID_OK; } // get number of samples generated by the object so far uint64_t QSOURCE(_get_num_samples)(QSOURCE() _q) { return _q->num_samples; } // set signal gain in dB int QSOURCE(_set_gain)(QSOURCE() _q, float _gain_dB) { // convert from dB _q->gain = powf(10.0f, _gain_dB/20.0f); return LIQUID_OK; } // get signal gain in dB float QSOURCE(_get_gain)(QSOURCE() _q) { return 20*log10f(_q->gain); } // set signal center frequency by adjusting index and NCO frequency int QSOURCE(_set_frequency)(QSOURCE() _q, float _fc) { // set channelizer index appropriately _q->index = (unsigned int)roundf((_fc < 0.0f ? _fc + 1.0f : _fc) * _q->M) % _q->M; // compute frequency applied by channelizer alignment float fc_index = QSOURCE(_get_frequency_index)(_q); // compute residual frequency needed by mixer float fc_mixer = _fc - fc_index; // apply mixer frequency (in radians), scaled by resampling ratio NCO(_set_frequency)(_q->mixer, 2*M_PI*fc_mixer * (float)(_q->M) / (float)(_q->P)); #if 0 // debug print printf("fc : %12.8f (index: %4u, P:%4u, M:%4u), actual : %12.8f = %12.8f + %12.8f, e : %12.8f\n", _fc, _q->index, _q->P, _q->M, fc_index+fc_mixer, fc_index, fc_mixer, _fc-(fc_index+fc_mixer)); #endif return LIQUID_OK; } // get mixer frequency float QSOURCE(_get_frequency)(QSOURCE() _q) { // get frequency of signal due to channelizer alignment float fc_index = QSOURCE(_get_frequency_index)(_q); // get frequency from NCO float fc_mixer = NCO(_get_frequency)(_q->mixer) * (float)(_q->P) / (2*M_PI*(float)(_q->M)); // true center frequency is the combination of the two offsets return fc_index + fc_mixer; } // get center frequency of signal applied by channelizer alignment float QSOURCE(_get_frequency_index)(QSOURCE() _q) { return (float)(_q->index) / (float)(_q->M) + (_q->index < _q->M/2 ? 0 : -1); } // generate a single sample int QSOURCE(_generate)(QSOURCE() _q, TO * _v) { // generate type-specific sample TO sample; switch (_q->type) { case QSOURCE_USER: _q->source.user.callback(_q->source.user.userdata, &sample, 1); break; case QSOURCE_TONE: sample = 1.0f; break; case QSOURCE_CHIRP: NCO(_cexpf) (_q->source.chirp.nco, &sample); NCO(_adjust_frequency)(_q->source.chirp.nco, _q->source.chirp.df); NCO(_step) (_q->source.chirp.nco); _q->source.chirp.timer--; if (_q->source.chirp.timer==0) { _q->source.chirp.timer = _q->source.chirp.num; // reset timer // disable for just one instance if (_q->source.chirp.single) QSOURCE(_disable)(_q); // reset NCO frequency NCO(_set_frequency)(_q->source.chirp.nco, _q->source.chirp.negate ? M_PI : -M_PI); } break; case QSOURCE_NOISE: sample = (randnf() + _Complex_I*randnf()) * M_SQRT1_2; break; case QSOURCE_MODEM: SYMSTREAM(_write_samples)(_q->source.linmod.symstream, &sample, 1); sample *= M_SQRT1_2; // compensate for 2 samples/symbol break; case QSOURCE_FSK: // fill buffer when necessary if (_q->source.fsk.index==0) fskmod_modulate(_q->source.fsk.mod, rand() & _q->source.fsk.mask, _q->source.fsk.buf); // compensate for k samples/symbol sample = _q->source.fsk.buf[ _q->source.fsk.index++ ]; // * M_SQRT1_2; _q->source.fsk.index %= _q->source.fsk.len; // reset index every k samples break; case QSOURCE_GMSK: // fill buffer when necessary if (_q->source.gmsk.index==0) gmskmod_modulate(_q->source.gmsk.mod, rand() & 1, _q->source.gmsk.buf); // compensate for 2 samples/symbol sample = _q->source.gmsk.buf[ _q->source.gmsk.index++ ] * M_SQRT1_2; _q->source.gmsk.index &= 1; // reset index every 2 samples break; default: return liquid_error(LIQUID_EINT,"qsource%s_generate(), invalid internal state",EXTENSION); } if (!_q->enabled) sample = 0.0f; // TODO: push through resampler // mix sample up NCO(_mix_up)(_q->mixer, sample, _v); // step mixer NCO(_step)(_q->mixer); return LIQUID_OK; } // generate a block of samples, convert to frequency domain, and write // result into parent channelizer buffer at appropriate frequency location int QSOURCE(_generate_into)(QSOURCE() _q, TO * _buf) { // add into output buffer, applying appropriate scaling unsigned int i; unsigned int P2 = _q->P/2; // fill input buffer for channelizer for (i=0; ibuf_time+i); // run analysis channelizer firpfbch2_crcf_execute(_q->ch, _q->buf_time, _q->buf_freq); // aggregate gain float g = _q->gain * _q->gain_ch; // copy upper frequency band (base index = _q->index) unsigned int base_index = _q->index; for (i=0; iM ] += _q->buf_freq[i] * g; // copy lower frequency band (base index = _q->index-P/2) base_index = _q->index; while (base_index <= P2) base_index += _q->M; base_index -= P2; for (i=0; iM ] += _q->buf_freq[i+P2] * g; _q->num_samples += P2; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/symstream.proto.c000066400000000000000000000174741474751757600221710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Symbol streaming generator #include #include #include #include // internal structure struct SYMSTREAM(_s) { int filter_type; // filter type (e.g. LIQUID_FIRFILT_RRC) unsigned int k; // samples/symbol unsigned int m; // filter semi-length float beta; // filter excess bandwidth int mod_scheme; // demodulator MODEM() mod; // modulator float gain; // gain before interpolation FIRINTERP() interp; // interpolator TO * buf; // output buffer unsigned int buf_index; // output buffer sample index }; // create symstream object using default parameters SYMSTREAM() SYMSTREAM(_create)() { return SYMSTREAM(_create_linear)(LIQUID_FIRFILT_ARKAISER, 2, // samples/symbol 7, // filter delay 0.3f, // filter excess bandwidth LIQUID_MODEM_QPSK); } // create symstream object with linear modulation // _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples per symbol // _m : filter delay (symbols) // _beta : filter excess bandwidth // _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK) SYMSTREAM() SYMSTREAM(_create_linear)(int _ftype, unsigned int _k, unsigned int _m, float _beta, int _ms) { // validate input if (_k < 2) return liquid_error_config("symstream%s_create(), samples/symbol must be at least 2", EXTENSION); if (_m == 0) return liquid_error_config("symstream%s_create(), filter delay must be greater than zero", EXTENSION); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("symstream%s_create(), filter excess bandwidth must be in (0,1]", EXTENSION); if (_ms == LIQUID_MODEM_UNKNOWN || _ms >= LIQUID_MODEM_NUM_SCHEMES) return liquid_error_config("symstream%s_create(), invalid modulation scheme", EXTENSION); // allocate memory for main object SYMSTREAM() q = (SYMSTREAM()) malloc( sizeof(struct SYMSTREAM(_s)) ); // set input parameters q->filter_type = _ftype; q->k = _k; q->m = _m; q->beta = _beta; q->mod_scheme = _ms; q->gain = 1.0f; // modulator q->mod = MODEM(_create)(q->mod_scheme); // interpolator q->interp = FIRINTERP(_create_prototype)(q->filter_type, q->k, q->m, q->beta, 0); // sample buffer q->buf = (TO*) malloc(q->k*sizeof(TO)); // reset and return main object SYMSTREAM(_reset)(q); return q; } // copy object SYMSTREAM() SYMSTREAM(_copy)(SYMSTREAM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("symstream%s_copy(), object cannot be NULL", EXTENSION); // create object and copy base parameters SYMSTREAM() q_copy = (SYMSTREAM()) malloc(sizeof(struct SYMSTREAM(_s))); memmove(q_copy, q_orig, sizeof(struct SYMSTREAM(_s))); // copy internal objects q_copy->mod = MODEM (_copy)(q_orig->mod ); q_copy->interp = FIRINTERP(_copy)(q_orig->interp); // copy output buffer state q_copy->buf = (TO *) liquid_malloc_copy(q_orig->buf, q_orig->k, sizeof(TO)); return q_copy; } // destroy symstream object, freeing all internal memory int SYMSTREAM(_destroy)(SYMSTREAM() _q) { // destroy objects MODEM (_destroy)(_q->mod); FIRINTERP(_destroy)(_q->interp); free(_q->buf); // free main object free(_q); return LIQUID_OK; } // print symstream object's parameters int SYMSTREAM(_print)(SYMSTREAM() _q) { printf("k); printf(", m=%u", _q->m); printf(", beta=%.3f", _q->beta); printf(", ms=\"%s\"", modulation_types[_q->mod_scheme].name); printf(", gain=%g", _q->gain); printf(">\n"); return LIQUID_OK; } // reset symstream internal state int SYMSTREAM(_reset)(SYMSTREAM() _q) { // reset objects and counter MODEM(_reset)(_q->mod); FIRINTERP(_reset)(_q->interp); _q->buf_index = 0; return LIQUID_OK; } // Get internal filter type int SYMSTREAM(_get_ftype)(SYMSTREAM() _q) { return _q->filter_type; } // Get internal signal bandwidth (symbol rate) float SYMSTREAM(_get_k)(SYMSTREAM() _q) { return _q->k; } // Get internal filter semi-length unsigned int SYMSTREAM(_get_m)(SYMSTREAM() _q) { return _q->m; } // Get internal filter excess bandwidth factor float SYMSTREAM(_get_beta)(SYMSTREAM() _q) { return _q->beta; } // Set internal linear modulation scheme, leaving the filter parameters // (interpolator) unmodified int SYMSTREAM(_set_scheme)(SYMSTREAM() _q, int _ms) { _q->mod = MODEM(_recreate)(_q->mod, _ms); return LIQUID_OK; } // Get internal linear modulation scheme int SYMSTREAM(_get_scheme)(SYMSTREAM() _q) { return MODEM(_get_scheme)(_q->mod); } // Set internal linear gain (before interpolation) int SYMSTREAM(_set_gain)(SYMSTREAM() _q, float _gain) { _q->gain = _gain; return LIQUID_OK; } // Get internal linear gain (before interpolation) float SYMSTREAM(_get_gain)(SYMSTREAM() _q) { return _q->gain; } // Get delay in samples unsigned int SYMSTREAM(_get_delay)(SYMSTREAM() _q) { return _q->k*_q->m; } // fill buffer with samples int SYMSTREAM(_fill_buffer)(SYMSTREAM() _q) { // generate random symbol unsigned int sym = MODEM(_gen_rand_sym)(_q->mod); // modulate TO v; MODEM(_modulate)(_q->mod, sym, &v); // apply gain v *= _q->gain; // interpolate FIRINTERP(_execute)(_q->interp, v, _q->buf); return LIQUID_OK; } // write block of samples to output buffer // _q : synchronizer object // _buf : output buffer [size: _buf_len x 1] // _buf_len: output buffer size int SYMSTREAM(_write_samples)(SYMSTREAM() _q, TO * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // check to see if buffer needs samples if (_q->buf_index==0) { if (SYMSTREAM(_fill_buffer)(_q)) return liquid_error(LIQUID_EINT,"symstream%s_write_samples(), could not fill internal buffer\n", EXTENSION); } // write output sample from internal buffer _buf[i] = _q->buf[_q->buf_index]; // increment internal index _q->buf_index = (_q->buf_index + 1) % _q->k; } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/symstreamr.proto.c000066400000000000000000000205261474751757600223430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Symbol streaming generator with arbitrary sample rate #include #include #include #include // internal structure struct SYMSTREAMR(_s) { SYMSTREAM() symstream; // half-band interpolator MSRESAMP() resamp; // arbitrary rate resampler TO * buf; // resampled output buffer unsigned int buf_len; // resampled output buffer: num allocated unsigned int buf_size; // resampled output buffer: num elements unsigned int buf_index; // resampled output buffer: sample index }; // create symstream object using default parameters SYMSTREAMR() SYMSTREAMR(_create)() { return SYMSTREAMR(_create_linear)(LIQUID_FIRFILT_ARKAISER, 0.5f, // samples/symbol 7, // filter delay 0.3f, // filter excess bandwidth LIQUID_MODEM_QPSK); } // create symstream object with linear modulation // _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) // _bw : relative signal bandwidth, 0.001 <= _bw <= 1.0 // _m : filter delay (symbols) // _beta : filter excess bandwidth // _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK) SYMSTREAMR() SYMSTREAMR(_create_linear)(int _ftype, float _bw, unsigned int _m, float _beta, int _ms) { float bw_min = 0.001f; float bw_max = 1.000f; // validate input if (_bw < bw_min || _bw > bw_max) return liquid_error_config("symstreamr%s_create(), symbol bandwidth (%g) must be in [%g,%g]", EXTENSION, _bw, bw_min, bw_max); // create base streaming object symstreamcf s = SYMSTREAM(_create_linear)(_ftype, 2, _m, _beta, _ms); if (s == NULL) return liquid_error_config("symstreamr%s_create(), could not create streaming object", EXTENSION); // allocate memory for main object SYMSTREAMR() q = (SYMSTREAMR()) malloc( sizeof(struct SYMSTREAMR(_s)) ); q->symstream = s; // create arbitrary rate resampler float rate = 0.5f / _bw; q->resamp = MSRESAMP(_create)(rate, 60.0f); // sample buffer // NOTE: buffer size must be at least 2^nextpow2( 0.5/bw ) q->buf_len = 1 << liquid_nextpow2((unsigned int)ceilf(0.5f/_bw)); q->buf = (TO*) malloc(q->buf_len*sizeof(TO)); // reset and return main object SYMSTREAMR(_reset)(q); return q; } // copy object SYMSTREAMR() SYMSTREAMR(_copy)(SYMSTREAMR() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("symstreamr%s_copy(), object cannot be NULL", EXTENSION); // create filter object and copy base parameters SYMSTREAMR() q_copy = (SYMSTREAMR()) malloc(sizeof(struct SYMSTREAMR(_s))); memmove(q_copy, q_orig, sizeof(struct SYMSTREAMR(_s))); // copy internal objects q_copy->symstream = SYMSTREAM(_copy)(q_orig->symstream); q_copy->resamp = MSRESAMP (_copy)(q_orig->resamp ); // copy internal buffer q_copy->buf = (TO *) liquid_malloc_copy(q_orig->buf, q_orig->buf_len, sizeof(TO)); return q_copy; } // destroy symstream object, freeing all internal memory int SYMSTREAMR(_destroy)(SYMSTREAMR() _q) { // destroy objects SYMSTREAM(_destroy)(_q->symstream); MSRESAMP(_destroy)(_q->resamp); // free buffer free(_q->buf); // free main object free(_q); return LIQUID_OK; } // print symstream object's parameters int SYMSTREAMR(_print)(SYMSTREAMR() _q) { printf("\n", EXTENSION, liquid_firfilt_type_str[SYMSTREAMR(_get_ftype)(_q)][0], SYMSTREAMR(_get_bw) (_q), SYMSTREAMR(_get_m) (_q), SYMSTREAMR(_get_beta)(_q), modulation_types[SYMSTREAMR(_get_scheme)(_q)].name, SYMSTREAMR(_get_gain)(_q)); return LIQUID_OK; } // reset symstream internal state int SYMSTREAMR(_reset)(SYMSTREAMR() _q) { // reset objects and counter SYMSTREAM(_reset)(_q->symstream); MSRESAMP (_reset)(_q->resamp); _q->buf_size = 0; _q->buf_index = 0; return LIQUID_OK; } // Get internal filter type int SYMSTREAMR(_get_ftype)(SYMSTREAMR() _q) { return SYMSTREAM(_get_ftype)(_q->symstream); } // Get internal signal bandwidth (symbol rate) float SYMSTREAMR(_get_bw)(SYMSTREAMR() _q) { return 1.0f / (MSRESAMP(_get_rate)(_q->resamp) * (float)SYMSTREAM(_get_k)(_q->symstream)); } // Get internal filter semi-length unsigned int SYMSTREAMR(_get_m)(SYMSTREAMR() _q) { return SYMSTREAM(_get_m)(_q->symstream); } // Get internal filter excess bandwidth factor float SYMSTREAMR(_get_beta)(SYMSTREAMR() _q) { return SYMSTREAM(_get_beta)(_q->symstream); } // Set internal linear modulation scheme, leaving the filter parameters // (interpolator) unmodified int SYMSTREAMR(_set_scheme)(SYMSTREAMR() _q, int _ms) { return SYMSTREAM(_set_scheme)(_q->symstream, _ms); } // Get internal linear modulation scheme int SYMSTREAMR(_get_scheme)(SYMSTREAMR() _q) { return SYMSTREAM(_get_scheme)(_q->symstream); } // Set internal linear gain (before interpolation) int SYMSTREAMR(_set_gain)(SYMSTREAMR() _q, float _gain) { return SYMSTREAM(_set_gain)(_q->symstream, _gain); } // Get internal linear gain (before interpolation) float SYMSTREAMR(_get_gain)(SYMSTREAMR() _q) { return SYMSTREAM(_get_gain)(_q->symstream); } // Get delay in samples float SYMSTREAMR(_get_delay)(SYMSTREAMR() _q) { float p = SYMSTREAM(_get_delay)(_q->symstream); float d = MSRESAMP (_get_delay)(_q->resamp ); float r = MSRESAMP (_get_rate) (_q->resamp ); return (p + d)*r; } // fill buffer with samples int SYMSTREAMR(_fill_buffer)(SYMSTREAMR() _q) { if (_q->buf_index != _q->buf_size) return liquid_error(LIQUID_EINT,"symstreamr%s_write_samples(), buffer not empty\n", EXTENSION); // reset counters _q->buf_size = 0; _q->buf_index = 0; // continue running until at least one sample is generated while (!_q->buf_size) { // generate base sample TO sample; SYMSTREAM(_write_samples)(_q->symstream, &sample, 1); // resample MSRESAMP(_execute)(_q->resamp, &sample, 1, _q->buf, &_q->buf_size); } return LIQUID_OK; } // write block of samples to output buffer // _q : synchronizer object // _buf : output buffer [size: _buf_len x 1] // _buf_len: output buffer size int SYMSTREAMR(_write_samples)(SYMSTREAMR() _q, TO * _buf, unsigned int _buf_len) { unsigned int i; for (i=0; i<_buf_len; i++) { // check to see if buffer needs samples if (_q->buf_index==_q->buf_size) { if (SYMSTREAMR(_fill_buffer)(_q)) return liquid_error(LIQUID_EINT,"symstreamr%s_write_samples(), could not fill internal buffer\n", EXTENSION); } // write output sample from internal buffer _buf[i] = _q->buf[_q->buf_index]; // increment internal index _q->buf_index++; } return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/src/symtrack.proto.c000066400000000000000000000326121474751757600217710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Symbol tracker/synchronizer // #include #include #include #include #define DEBUG_SYMTRACK 0 #define DEBUG_SYMTRACK_PRINT 0 #define DEBUG_SYMTRACK_FILENAME "symtrack_internal_debug.m" #define DEBUG_BUFFER_LEN (1024) // // forward declaration of internal methods // // internal structure struct SYMTRACK(_s) { // parameters int filter_type; // filter type (e.g. LIQUID_FIRFILT_RRC) unsigned int k; // samples/symbol unsigned int m; // filter semi-length float beta; // filter excess bandwidth int mod_scheme; // demodulator float bw; // tracking bandwidth // automatic gain control AGC() agc; // agc object float agc_bandwidth; // agc bandwidth // symbol timing recovery SYMSYNC() symsync; // symbol timing recovery object float symsync_bandwidth; // symsync loop bandwidth TO symsync_buf[8]; // symsync output buffer unsigned int symsync_index; // symsync output sample index // equalizer/decimator EQLMS() eq; // equalizer (LMS) unsigned int eq_len; // equalizer length float eq_bandwidth; // equalizer bandwidth enum { SYMTRACK_EQ_CM, // equalizer strategy: constant modulus SYMTRACK_EQ_DD, // equalizer strategy: decision directed SYMTRACK_EQ_OFF, // equalizer strategy: disabled } eq_strategy; // nco/phase-locked loop NCO() nco; // nco (carrier recovery) float pll_bandwidth; // phase-locked loop bandwidth // demodulator MODEM() demod; // linear modem demodulator // state and counters unsigned int num_syms_rx; // number of symbols recovered }; // create symtrack object with basic parameters // _ftype : filter type (e.g. LIQUID_FIRFILT_RRC) // _k : samples per symbol // _m : filter delay (symbols) // _beta : filter excess bandwidth // _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK) SYMTRACK() SYMTRACK(_create)(int _ftype, unsigned int _k, unsigned int _m, float _beta, int _ms) { // validate input if (_k < 2) return liquid_error_config("symtrack_%s_create(), filter samples/symbol must be at least 2", EXTENSION_FULL); if (_m == 0) return liquid_error_config("symtrack_%s_create(), filter delay must be greater than zero", EXTENSION_FULL); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("symtrack_%s_create(), filter excess bandwidth must be in (0,1]", EXTENSION_FULL); if (_ms == LIQUID_MODEM_UNKNOWN || _ms >= LIQUID_MODEM_NUM_SCHEMES) return liquid_error_config("symtrack_%s_create(), invalid modulation scheme", EXTENSION_FULL); // allocate memory for main object SYMTRACK() q = (SYMTRACK()) malloc( sizeof(struct SYMTRACK(_s)) ); // set input parameters q->filter_type = _ftype; q->k = _k; q->m = _m; q->beta = _beta; q->mod_scheme = _ms == LIQUID_MODEM_UNKNOWN ? LIQUID_MODEM_BPSK : _ms; // create automatic gain control q->agc = AGC(_create)(); // create symbol synchronizer (output rate: 2 samples per symbol) if (q->filter_type == LIQUID_FIRFILT_UNKNOWN) q->symsync = SYMSYNC(_create_kaiser)(q->k, q->m, 0.9f, 16); else q->symsync = SYMSYNC(_create_rnyquist)(q->filter_type, q->k, q->m, q->beta, 16); SYMSYNC(_set_output_rate)(q->symsync, 2); // create equalizer as default low-pass filter with integer symbol delay (2 samples/symbol) q->eq_len = 2 * 4 + 1; q->eq = EQLMS(_create_lowpass)(q->eq_len,0.45f); q->eq_strategy = SYMTRACK_EQ_CM; // nco and phase-locked loop q->nco = NCO(_create)(LIQUID_VCO); // demodulator q->demod = MODEM(_create)(q->mod_scheme); // set default bandwidth SYMTRACK(_set_bandwidth)(q, 0.9f); // reset and return main object SYMTRACK(_reset)(q); return q; } // create symtrack object using default parameters SYMTRACK() SYMTRACK(_create_default)() { return SYMTRACK(_create)(LIQUID_FIRFILT_ARKAISER, 2, // samples/symbol 7, // filter delay 0.3f, // filter excess bandwidth LIQUID_MODEM_QPSK); } // destroy symtrack object, freeing all internal memory int SYMTRACK(_destroy)(SYMTRACK() _q) { // destroy objects AGC (_destroy)(_q->agc); SYMSYNC(_destroy)(_q->symsync); EQLMS (_destroy)(_q->eq); NCO (_destroy)(_q->nco); MODEM (_destroy)(_q->demod); // free main object free(_q); return LIQUID_OK; } // print symtrack object's parameters int SYMTRACK(_print)(SYMTRACK() _q) { #if 0 printf("symtrack_%s:\n", EXTENSION_FULL); printf(" k:%u, m:%u, beta:%.3f, ms:%s\n", _q->k, _q->m, _q->beta, modulation_types[_q->mod_scheme].name); printf(" equalization strategy: "); switch (_q->eq_strategy) { case SYMTRACK_EQ_CM: printf("constant modulus\n"); break; case SYMTRACK_EQ_DD: printf("decision directed\n"); break; case SYMTRACK_EQ_OFF: printf("disabled\n"); break; default: printf("?\n"); return liquid_error(LIQUID_EINT,"symtrack_%s_print(), invalid equalization strategy"); } #else printf("\n", _q->k, _q->m, _q->beta, modulation_types[_q->mod_scheme].name); #endif return LIQUID_OK; } // reset symtrack internal state int SYMTRACK(_reset)(SYMTRACK() _q) { // reset objects AGC (_reset)(_q->agc); SYMSYNC(_reset)(_q->symsync); EQLMS (_reset)(_q->eq); NCO (_reset)(_q->nco); MODEM (_reset)(_q->demod); // reset internal counters _q->symsync_index = 0; _q->num_syms_rx = 0; return LIQUID_OK; } // get symtrack filter type int SYMTRACK(_get_ftype)(SYMTRACK() _q) { return _q->filter_type; } // get symtrack samples per symbol unsigned int SYMTRACK(_get_k)(SYMTRACK() _q) { return _q->k; } // get symtrack filter semi-length [symbols] unsigned int SYMTRACK(_get_m)(SYMTRACK() _q) { return _q->m; } // get symtrack filter excess bandwidth factor float SYMTRACK(_get_beta)(SYMTRACK() _q) { return _q->beta; } // get symtrack modulation scheme int SYMTRACK(_get_modscheme)(SYMTRACK() _q) { return _q->mod_scheme; } // set symtrack modulation scheme int SYMTRACK(_set_modscheme)(SYMTRACK() _q, int _ms) { // validate input if (_ms >= LIQUID_MODEM_NUM_SCHEMES) return liquid_error(LIQUID_EICONFIG,"symtrack_%s_set_modscheme(), invalid/unsupported modulation scheme", EXTENSION_FULL); // set internal modulation scheme _q->mod_scheme = _ms == LIQUID_MODEM_UNKNOWN ? LIQUID_MODEM_BPSK : _ms; // re-create modem _q->demod = MODEM(_recreate)(_q->demod, _q->mod_scheme); return LIQUID_OK; } // set symtrack internal bandwidth int SYMTRACK(_set_bandwidth)(SYMTRACK() _q, float _bw) { // validate input if (_bw < 0) return liquid_error(LIQUID_EICONFIG,"symtrack_%s_set_bandwidth(), bandwidth must be in [0,1]", EXTENSION_FULL); _q->bw = _bw; // set bandwidths accordingly float agc_bandwidth = 0.02f * _q->bw; float symsync_bandwidth = 0.001f * _q->bw; float eq_bandwidth = 0.02f * _q->bw; float pll_bandwidth = 0.001f * _q->bw; // automatic gain control AGC(_set_bandwidth)(_q->agc, agc_bandwidth); // symbol timing recovery SYMSYNC(_set_lf_bw)(_q->symsync, symsync_bandwidth); // equalizer EQLMS(_set_bw)(_q->eq, eq_bandwidth); // phase-locked loop NCO(_pll_set_bandwidth)(_q->nco, pll_bandwidth); return LIQUID_OK; } // get symtrack internal bandwidth float SYMTRACK(_get_bandwidth)(SYMTRACK() _q) { return _q->bw; } // adjust internal nco by requested frequency int SYMTRACK(_adjust_frequency)(SYMTRACK() _q, T _dphi) { return NCO(_adjust_frequency)(_q->nco, _dphi); } // adjust internal nco by requested phase int SYMTRACK(_adjust_phase)(SYMTRACK() _q, T _phi) { return NCO(_adjust_phase)(_q->nco, _phi); } // set equalization strategy to constant modulus (default) int SYMTRACK(_set_eq_cm)(SYMTRACK() _q) { _q->eq_strategy = SYMTRACK_EQ_CM; return LIQUID_OK; } // set equalization strategy to decision directed int SYMTRACK(_set_eq_dd)(SYMTRACK() _q) { _q->eq_strategy = SYMTRACK_EQ_DD; return LIQUID_OK; } // disable equalization int SYMTRACK(_set_eq_off)(SYMTRACK() _q) { _q->eq_strategy = SYMTRACK_EQ_OFF; return LIQUID_OK; } // execute synchronizer on single input sample // _q : synchronizer object // _x : input data sample // _y : output data array // _ny : number of samples written to output buffer int SYMTRACK(_execute)(SYMTRACK() _q, TI _x, TO * _y, unsigned int * _ny) { TO v; // output sample unsigned int i; unsigned int num_outputs = 0; // run sample through automatic gain control AGC(_execute)(_q->agc, _x, &v); // symbol synchronizer unsigned int nw = 0; SYMSYNC(_execute)(_q->symsync, &v, 1, _q->symsync_buf, &nw); // process each output sample for (i=0; inco); nco_crcf_mix_down(_q->nco, _q->symsync_buf[i], &v); // equalizer/decimator EQLMS(_push)(_q->eq, v); // decimate result, noting that symsync outputs at exactly 2 samples/symbol _q->symsync_index++; if ( !(_q->symsync_index % 2) ) continue; // increment number of symbols received _q->num_syms_rx++; // compute equalizer filter output; updating coefficients is dependent upon strategy TO d_hat; EQLMS(_execute)(_q->eq, &d_hat); // demodulate result, apply phase correction unsigned int sym_out; MODEM(_demodulate)(_q->demod, d_hat, &sym_out); float phase_error = MODEM(_get_demodulator_phase_error)(_q->demod); // update pll NCO(_pll_step)(_q->nco, phase_error); // update equalizer independent of the signal: estimate error // assuming constant modulus signal // TODO: check lock conditions of previous object to determine when to run equalizer float complex d_prime = 0.0f; if (_q->num_syms_rx > 200 && _q->eq_strategy != SYMTRACK_EQ_OFF) { switch (_q->eq_strategy) { case SYMTRACK_EQ_CM: d_prime = d_hat/cabsf(d_hat); break; case SYMTRACK_EQ_DD: MODEM(_get_demodulator_sample)(_q->demod, &d_prime); break; default: return liquid_error(LIQUID_EINT,"symtrack_%s_execute(), invalid equalizer strategy", EXTENSION_FULL); } EQLMS(_step)(_q->eq, d_prime, d_hat); } // save result to output _y[num_outputs++] = d_hat; } #if DEBUG_SYMTRACK printf("symsync wrote %u samples, %u outputs\n", nw, num_outputs); #endif // *_ny = num_outputs; return LIQUID_OK; } // execute synchronizer on input data array // _q : synchronizer object // _x : input data array // _nx : number of input samples // _y : output data array // _ny : number of samples written to output buffer int SYMTRACK(_execute_block)(SYMTRACK() _q, TI * _x, unsigned int _nx, TO * _y, unsigned int * _ny) { // unsigned int i; unsigned int num_written = 0; // for (i=0; i<_nx; i++) { unsigned int nw = 0; SYMTRACK(_execute)(_q, _x[i], &_y[num_written], &nw); num_written += nw; } // *_ny = num_written; return LIQUID_OK; } liquid-dsp-1.7.0/src/framing/tests/000077500000000000000000000000001474751757600171755ustar00rootroot00000000000000liquid-dsp-1.7.0/src/framing/tests/bpacketsync_autotest.c000066400000000000000000000064561474751757600236120ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" static int bpacketsync_autotest_callback(unsigned char * _payload, int _payload_valid, unsigned int _payload_len, framesyncstats_s _stats, void * _userdata) { if (!_payload_valid) return 0; unsigned int * num_packets_found = (unsigned int *) _userdata; *num_packets_found += 1; return 0; } // // AUTOTEST: bpacketsync // void autotest_bpacketsync() { // options unsigned int num_packets = 50; // number of packets to encode unsigned int dec_msg_len = 64; // original data message length crc_scheme check = LIQUID_CRC_32; // data integrity check fec_scheme fec0 = LIQUID_FEC_HAMMING74; // inner code fec_scheme fec1 = LIQUID_FEC_NONE; // outer code // create packet generator bpacketgen pg = bpacketgen_create(0, dec_msg_len, check, fec0, fec1); if (liquid_autotest_verbose) bpacketgen_print(pg); // compute packet length unsigned int enc_msg_len = bpacketgen_get_packet_len(pg); // initialize arrays unsigned char msg_org[dec_msg_len]; // original message unsigned char msg_enc[enc_msg_len]; // encoded message unsigned int num_packets_found=0; // create packet synchronizer bpacketsync ps = bpacketsync_create(0, bpacketsync_autotest_callback, (void*)&num_packets_found); unsigned int i; unsigned int n; for (n=0; n #include #include #include #include "autotest/autotest.h" #include "liquid.h" void autotest_dsssframe64sync() { // create objects unsigned int context = 0; dsssframe64gen fg = dsssframe64gen_create(); dsssframe64sync fs = dsssframe64sync_create(framing_autotest_callback, (void*)&context); // generate the frame unsigned int frame_len = dsssframe64gen_get_frame_len(fg); float complex * frame = (float complex *)malloc(frame_len*sizeof(float complex)); dsssframe64gen_execute(fg, NULL, NULL, frame); // add some noise unsigned int i; for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" void autotest_dsssframesync() { unsigned int _payload_len = 400; // create dsssframegen object dsssframegenprops_s fgprops; fgprops.check = LIQUID_CRC_32; fgprops.fec0 = LIQUID_FEC_NONE; fgprops.fec1 = LIQUID_FEC_NONE; dsssframegen fg = dsssframegen_create(&fgprops); // assemble the frame dsssframegen_assemble(fg, NULL, NULL, _payload_len); // create dsssframesync object unsigned int context = 0; dsssframesync fs = dsssframesync_create(framing_autotest_callback, (void*)&context); // generate the frame int frame_complete = 0; unsigned int buf_len = 256; float complex buf[buf_len]; while (!frame_complete) { // write samples to buffer frame_complete = dsssframegen_write_samples(fg, buf, buf_len); // run through frame synchronizer dsssframesync_execute(fs, buf, buf_len); } // get frame data statistics if (liquid_autotest_verbose) dsssframesync_print(fs); // check to see that frame was recovered #if 0 framedatastats_s stats = dsssframesync_get_framedatastats(fs); CONTEND_EQUALITY( stats.num_frames_detected, 1 ); CONTEND_EQUALITY( stats.num_headers_valid, 1 ); CONTEND_EQUALITY( stats.num_payloads_valid, 1 ); CONTEND_EQUALITY( stats.num_bytes_received, _payload_len ); #endif CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); // destroy objects dsssframegen_destroy(fg); dsssframesync_destroy(fs); } liquid-dsp-1.7.0/src/framing/tests/flexframesync_autotest.c000066400000000000000000000063321474751757600241430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST : test simple recovery of frame in noise // void autotest_flexframesync() { unsigned int i; unsigned int _payload_len = 400; int _ms = LIQUID_MODEM_QPSK; int _fec0 = LIQUID_FEC_NONE; int _fec1 = LIQUID_FEC_NONE; int _check = LIQUID_CRC_32; // create flexframegen object flexframegenprops_s fgprops; flexframegenprops_init_default(&fgprops); fgprops.mod_scheme = _ms; fgprops.check = _check; fgprops.fec0 = _fec0; fgprops.fec1 = _fec1; flexframegen fg = flexframegen_create(&fgprops); // create flexframesync object unsigned int context = 0; flexframesync fs = flexframesync_create(framing_autotest_callback, (void*)&context); // initialize header and payload unsigned char header[14] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; unsigned char payload[_payload_len]; for (i=0; i<_payload_len; i++) payload[i] = rand() & 0xff; // assemble the frame flexframegen_assemble(fg, header, payload, _payload_len); if (liquid_autotest_verbose) flexframegen_print(fg); // generate the frame int frame_complete = 0; float complex buf[2]; while (!frame_complete) { // write samples to buffer frame_complete = flexframegen_write_samples(fg, buf, 2); // run through frame synchronizer flexframesync_execute(fs, buf, 2); } // get frame data statistics framedatastats_s stats = flexframesync_get_framedatastats(fs); if (liquid_autotest_verbose) flexframesync_print(fs); // ensure callback was invoked CONTEND_EQUALITY(context, FRAMING_AUTOTEST_SECRET); // check to see that frame was recovered CONTEND_EQUALITY( stats.num_frames_detected, 1 ); CONTEND_EQUALITY( stats.num_headers_valid, 1 ); CONTEND_EQUALITY( stats.num_payloads_valid, 1 ); CONTEND_EQUALITY( stats.num_bytes_received, _payload_len ); // destroy objects flexframegen_destroy(fg); flexframesync_destroy(fs); } liquid-dsp-1.7.0/src/framing/tests/framesync64_autotest.c000066400000000000000000000264741474751757600234470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "autotest/autotest.h" #include "liquid.h" // AUTOTEST : test simple recovery of frame in noise void autotest_framesync64() { unsigned int i; // create objects unsigned int context = 0; framegen64 fg = framegen64_create(); framesync64 fs = framesync64_create(framing_autotest_callback, (void*)&context); // generate the frame float complex frame[LIQUID_FRAME64_LEN]; framegen64_execute(fg, NULL, NULL, frame); // add some noise for (i=0; i #include #include #include #include "autotest/autotest.h" #include "liquid.h" // AUTOTEST : test simple recovery of frame in noise void autotest_fskframesync() { // options float SNRdB = 20.0f; // signal-to-noise ratio float noise_floor = -20.0f; // noise floor //float dphi = 0.01f; // carrier frequency offset //float theta = 0.0f; // carrier phase offset //float dt = -0.2f; // fractional sample timing offset crc_scheme check = LIQUID_CRC_32; // data validity check fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner) fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer) // derived values float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev. float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain unsigned int i; unsigned int context = 0; // create objects fskframegen fg = fskframegen_create(); fskframesync fs = fskframesync_create(framing_autotest_callback, (void*)&context); // assemble the frame unsigned char header [ 8]; unsigned char payload[200]; for (i=0; i< 8; i++) header [i] = i; for (i=0; i<200; i++) payload[i] = rand() & 0xff; fskframegen_assemble(fg, header, payload, 200, check, fec0, fec1); // allocate memory for the frame samples unsigned int buf_len = 256; float complex buf_tx[buf_len]; // receive buffer float complex buf_rx[buf_len]; // transmit buffer // try to receive the frame (operate in blocks) int frame_complete = 0; while (!frame_complete) { // generate frame samples frame_complete = fskframegen_write_samples(fg, buf_tx, buf_len); // add noise, channel gain for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" // test simple recovery of GMSK frame void autotest_gmskframesync_process() { // initialization and options unsigned int msg_len= 40; // message length [bytes] crc_scheme crc = LIQUID_CRC_32; fec_scheme fec0 = LIQUID_FEC_NONE; fec_scheme fec1 = LIQUID_FEC_NONE; unsigned int context = 0; // create objects gmskframegen fg = gmskframegen_create(); // create frame synchronizer gmskframesync fs = gmskframesync_create(framing_autotest_callback, (void*)&context); if (liquid_autotest_verbose) { gmskframegen_print(fg); gmskframesync_print(fs); } // assemble frame with specific data CONTEND_EQUALITY(gmskframegen_is_assembled(fg), 0); unsigned int i; unsigned char header[8]; unsigned char msg [msg_len]; for (i=0; i<8; i++) header[i] = i; for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" // AUTOTEST : test simple recovery of frame in noise void testbench_ofdmflexframe(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned int _payload_len, modulation_scheme _ms) { // create frame generator/synchronizer unsigned int context = 0; ofdmflexframegenprops_s fgprops; ofdmflexframegenprops_init_default(&fgprops); fgprops.check = LIQUID_CRC_32; fgprops.fec0 = LIQUID_FEC_NONE; fgprops.fec1 = LIQUID_FEC_NONE; fgprops.mod_scheme = _ms; ofdmflexframegen fg = ofdmflexframegen_create( _M, _cp_len, _taper_len, NULL, &fgprops); ofdmflexframesync fs = ofdmflexframesync_create(_M, _cp_len, _taper_len, NULL, framing_autotest_callback, (void*)&context); // initialize header and payload unsigned char header[8] = {0, 1, 2, 3, 4, 5, 6, 7}; unsigned char payload[_payload_len]; memset(payload, 0x00, _payload_len); // assemble the frame ofdmflexframegen_assemble(fg, header, payload, _payload_len); if (liquid_autotest_verbose) ofdmflexframegen_print(fg); // generate the frame unsigned int buf_len = 1024; float complex buf[buf_len]; int frame_complete = 0; while (!frame_complete) { frame_complete = ofdmflexframegen_write(fg, buf, buf_len); ofdmflexframesync_execute(fs, buf, buf_len); } // get frame data statistics if (liquid_autotest_verbose) ofdmflexframesync_print(fs); // verify callback was invoked CONTEND_EQUALITY( context, FRAMING_AUTOTEST_SECRET ); // verify frame data statistics framedatastats_s stats = ofdmflexframesync_get_framedatastats(fs); CONTEND_EQUALITY( stats.num_frames_detected, 1 ); CONTEND_EQUALITY( stats.num_headers_valid, 1 ); CONTEND_EQUALITY( stats.num_payloads_valid, 1 ); CONTEND_EQUALITY( stats.num_bytes_received, _payload_len ); // destroy objects ofdmflexframegen_destroy(fg); ofdmflexframesync_destroy(fs); } // ID M CP TP PAYL modulation scheme void autotest_ofdmflexframe_00() { testbench_ofdmflexframe( 32, 8, 4, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_01() { testbench_ofdmflexframe( 64, 8, 4, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_02() { testbench_ofdmflexframe( 256, 8, 4, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_03() { testbench_ofdmflexframe(1024, 16, 8, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_04() { testbench_ofdmflexframe(2048, 32, 16, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_05() { testbench_ofdmflexframe(4096, 64, 32, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_06() { testbench_ofdmflexframe(8192, 80, 40, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_07() { testbench_ofdmflexframe(1200, 40, 20, 1, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_08() { testbench_ofdmflexframe(1200, 0, 0, 800, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframe_09() { testbench_ofdmflexframe(1200, 40, 20, 8217, LIQUID_MODEM_QPSK); } void autotest_ofdmflexframegen_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping ofdmflexframegen config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check invalid function calls //CONTEND_ISNULL(ofdmflexframegen_copy(NULL)); CONTEND_ISNULL(ofdmflexframegen_create( 0, 16, 4, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmflexframegen_create( 7, 16, 4, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmflexframegen_create(65, 16, 4, NULL, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmflexframegen_create(64, 66, 4, NULL, NULL)) // cyclic prefix length too large // create proper object and test configurations ofdmflexframegen q = ofdmflexframegen_create(64, 16, 4, NULL, NULL); CONTEND_EQUALITY(LIQUID_OK, ofdmflexframegen_print(q)) ofdmflexframegen_destroy(q); } void autotest_ofdmflexframesync_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping ofdmflexframesync config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check invalid function calls //CONTEND_ISNULL(ofdmflexframesync_copy(NULL)); CONTEND_ISNULL(ofdmflexframesync_create( 0, 16, 4, NULL, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmflexframesync_create( 7, 16, 4, NULL, NULL, NULL)) // too few subcarriers CONTEND_ISNULL(ofdmflexframesync_create(65, 16, 4, NULL, NULL, NULL)) // odd-length subcarriers CONTEND_ISNULL(ofdmflexframesync_create(64, 66, 4, NULL, NULL, NULL)) // cyclic prefix length too large // create proper object and test configurations ofdmflexframesync q = ofdmflexframesync_create(64, 16, 4, NULL, NULL, NULL); CONTEND_EQUALITY(LIQUID_OK, ofdmflexframesync_print(q)) ofdmflexframesync_destroy(q); } liquid-dsp-1.7.0/src/framing/tests/qdetector_cccf_autotest.c000066400000000000000000000173421474751757600242500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper functions // _sequence_len : sequence length void qdetector_cccf_runtest_linear(unsigned int _sequence_len); void qdetector_cccf_runtest_gmsk (unsigned int _sequence_len); // run test given initialized object void qdetector_cccf_runtest(qdetector_cccf _q); // linear tests void autotest_qdetector_cccf_linear_n64() { qdetector_cccf_runtest_linear( 64); } void autotest_qdetector_cccf_linear_n83() { qdetector_cccf_runtest_linear( 83); } void autotest_qdetector_cccf_linear_n128() { qdetector_cccf_runtest_linear( 128); } void autotest_qdetector_cccf_linear_n167() { qdetector_cccf_runtest_linear( 167); } void autotest_qdetector_cccf_linear_n256() { qdetector_cccf_runtest_linear( 256); } void autotest_qdetector_cccf_linear_n335() { qdetector_cccf_runtest_linear( 335); } void autotest_qdetector_cccf_linear_n512() { qdetector_cccf_runtest_linear( 512); } void autotest_qdetector_cccf_linear_n671() { qdetector_cccf_runtest_linear( 671); } void autotest_qdetector_cccf_linear_n1024() { qdetector_cccf_runtest_linear(1024); } void autotest_qdetector_cccf_linear_n1341() { qdetector_cccf_runtest_linear(1341); } // gmsk tests void autotest_qdetector_cccf_gmsk_n64() { qdetector_cccf_runtest_gmsk ( 64); } void autotest_qdetector_cccf_gmsk_n83() { qdetector_cccf_runtest_gmsk ( 83); } void autotest_qdetector_cccf_gmsk_n128() { qdetector_cccf_runtest_gmsk ( 128); } void autotest_qdetector_cccf_gmsk_n167() { qdetector_cccf_runtest_gmsk ( 167); } void autotest_qdetector_cccf_gmsk_n256() { qdetector_cccf_runtest_gmsk ( 256); } void autotest_qdetector_cccf_gmsk_n335() { qdetector_cccf_runtest_gmsk ( 335); } void autotest_qdetector_cccf_gmsk_n512() { qdetector_cccf_runtest_gmsk ( 512); } void autotest_qdetector_cccf_gmsk_n671() { qdetector_cccf_runtest_gmsk ( 671); } void autotest_qdetector_cccf_gmsk_n1024() { qdetector_cccf_runtest_gmsk (1024); } void autotest_qdetector_cccf_gmsk_n1341() { qdetector_cccf_runtest_gmsk (1341); } // autotest helper function // _sequence_len : sequence length void qdetector_cccf_runtest_linear(unsigned int _sequence_len) { unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; // filter type // generate synchronization sequence (QPSK symbols) unsigned int i; float complex sequence[_sequence_len]; for (i=0; i<_sequence_len; i++) { sequence[i] = (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 + (rand() % 2 ? 1.0f : -1.0f) * M_SQRT1_2 * _Complex_I; } // create detector qdetector_cccf q = qdetector_cccf_create_linear(sequence, _sequence_len, ftype, k, m, beta); // run test qdetector_cccf_runtest(q); // destroy objects qdetector_cccf_destroy(q); } // autotest helper function // _sequence_len : sequence length void qdetector_cccf_runtest_gmsk(unsigned int _sequence_len) { unsigned int k = 2; // samples per symbol unsigned int m = 7; // filter delay [symbols] float beta = 0.3f; // excess bandwidth factor // generate synchronization sequence (QPSK symbols) unsigned char sequence[_sequence_len]; unsigned int i; for (i=0; i<_sequence_len; i++) sequence[i] = rand() & 0x01; // create detector qdetector_cccf q = qdetector_cccf_create_gmsk(sequence, _sequence_len, k, m, beta); // run test qdetector_cccf_runtest(q); // destroy objects qdetector_cccf_destroy(q); } // autotest helper function void qdetector_cccf_runtest(qdetector_cccf _q) { if (liquid_autotest_verbose) qdetector_cccf_print(_q); float gamma = 1.0f; // channel gain float tau = 0.0f; // fractional sample timing offset float dphi = -0.000f; // carrier frequency offset (zero for now) float phi = 0.5f; // carrier phase offset float complex * seq = (float complex*)qdetector_cccf_get_sequence(_q); unsigned int sequence_len = qdetector_cccf_get_seq_len(_q); unsigned int num_samples = 8*sequence_len; float complex buf_rx[num_samples]; // add channel impairments unsigned int i; for (i=0; i #include #include "autotest/autotest.h" #include "liquid.h" // test that the complete internal state of one detector can be copied to a new // object, and that both return identical results when provided the same input void autotest_qdetector_cccf_copy() { // generate random-ish sequence unsigned int sequence_len = 64; float complex sequence[sequence_len]; unsigned int i; for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" // common structure for relaying information to/from callback typedef struct { int id; float complex * buf; unsigned int buf_len; unsigned int count; } autotest_qdsync_s; // synchronization callback, return 0:continue, 1:reset int autotest_qdsync_callback(float complex * _buf, unsigned int _buf_len, void * _context) { // save samples to buffer as appropriate autotest_qdsync_s * q = (autotest_qdsync_s *) _context; if (liquid_autotest_verbose) printf("[%d] qdsync callback got %u samples\n", q->id, _buf_len); unsigned int i; for (i=0; i<_buf_len; i++) { if (q->count == q->buf_len) return 1; // buffer full; reset synchronizer // save payload q->buf[q->count++] = _buf[i]; } return 0; } void testbench_qdsync_linear(unsigned int _k, unsigned int _m, float _beta) { // options unsigned int seq_len = 1200; // total number of sync symbols unsigned int k = _k; // samples/symbol unsigned int m = _m; // filter delay [symbols] float beta = _beta; // excess bandwidth factor int ftype = LIQUID_FIRFILT_ARKAISER; float nstd = 0.001f; float tau = 0.400f; // fractional sample timing offset // generate synchronization sequence (QPSK symbols) float complex seq_tx[seq_len]; // transmitted float complex seq_rx[seq_len]; // received with initial correction unsigned int i; for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST : test simple recovery of frame // void qpacketmodem_modulated(unsigned int _payload_len, int _check, int _fec0, int _fec1, int _ms) { // derived values unsigned int i; // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, _payload_len, _check, _fec0, _fec1, _ms); if (liquid_autotest_verbose) qpacketmodem_print(q); // initialize payload unsigned char payload_tx[_payload_len]; unsigned char payload_rx[_payload_len]; // initialize payload for (i=0; i<_payload_len; i++) { payload_tx[i] = rand() & 0xff; payload_rx[i] = rand() & 0xff; } // get frame length unsigned int frame_len = qpacketmodem_get_frame_len(q); // allocate memory for frame samples float complex frame[frame_len]; // encode frame qpacketmodem_encode(q, payload_tx, frame); // decode frame int crc_pass = qpacketmodem_decode_soft(q, frame, payload_rx); // destroy object qpacketmodem_destroy(q); // check to see that frame was recovered CONTEND_EQUALITY( crc_pass, 1 ); CONTEND_SAME_DATA( payload_tx, payload_rx, _payload_len ); } void autotest_qpacketmodem_bpsk() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_QPSK); } void autotest_qpacketmodem_qpsk() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_QPSK); } void autotest_qpacketmodem_psk8() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_PSK8); } void autotest_qpacketmodem_qam16() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_QAM16); } void autotest_qpacketmodem_sqam32() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_SQAM32); } void autotest_qpacketmodem_qam64() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_QAM64); } void autotest_qpacketmodem_sqam128(){ qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_SQAM128); } void autotest_qpacketmodem_qam256() { qpacketmodem_modulated(400,LIQUID_CRC_32,LIQUID_FEC_NONE,LIQUID_FEC_NONE, LIQUID_MODEM_QAM256); } // test error vector magnitude estimation void autotest_qpacketmodem_evm() { unsigned int payload_len = 800; int check = LIQUID_CRC_32; int fec0 = LIQUID_FEC_NONE; int fec1 = LIQUID_FEC_NONE; int ms = LIQUID_MODEM_QPSK; float SNRdB = 25.0f; // create and configure packet encoder/decoder object qpacketmodem q = qpacketmodem_create(); qpacketmodem_configure(q, payload_len, check, fec0, fec1, ms); // initialize payload unsigned char payload_rx[payload_len]; // get frame length and allocate memory for frame samples unsigned int frame_len = qpacketmodem_get_frame_len(q); float complex frame[frame_len]; // encode frame (random bits) qpacketmodem_encode(q, NULL, frame); // add noise float nstd = powf(10.0f, -SNRdB/20.0f); unsigned int i; for (i=0; i #include #include #include "autotest/autotest.h" #include "liquid.h" #define DEBUG_QPILOTSYNC_AUTOTEST 1 // test simple recovery of frame in noise void qpilotsync_test(modulation_scheme _ms, unsigned int _payload_len, unsigned int _pilot_spacing, float _dphi, float _phi, float _gamma, float _SNRdB) { unsigned int i; // derived values float nstd = powf(10.0f, -_SNRdB/20.0f); // create pilot generator and synchronizer objects qpilotgen pg = qpilotgen_create( _payload_len, _pilot_spacing); qpilotsync ps = qpilotsync_create(_payload_len, _pilot_spacing); // get frame length unsigned int frame_len = qpilotgen_get_frame_len(pg); CONTEND_EQUALITY(frame_len, qpilotsync_get_frame_len(ps)); // allocate arrays unsigned char payload_sym_tx[_payload_len]; // transmitted payload symbols float complex payload_tx [_payload_len]; // transmitted payload samples float complex frame_tx [frame_len]; // transmitted frame samples float complex frame_rx [frame_len]; // received frame samples float complex payload_rx [_payload_len]; // received payload samples unsigned char payload_sym_rx[_payload_len]; // received payload symbols // create modem objects for payload modemcf mod = modemcf_create(_ms); modemcf dem = modemcf_create(_ms); // assemble payload symbols for (i=0; i<_payload_len; i++) { // generate random symbol payload_sym_tx[i] = modemcf_gen_rand_sym(mod); // modulate modemcf_modulate(mod, payload_sym_tx[i], &payload_tx[i]); } // assemble frame qpilotgen_execute(pg, payload_tx, frame_tx); // add channel impairments for (i=0; i #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper functions void testbench_symstreamcf_psd(unsigned int _k, unsigned int _m, float _beta) { // create object int ftype = LIQUID_FIRFILT_ARKAISER; int ms = LIQUID_MODEM_QPSK; symstreamcf gen = symstreamcf_create_linear(ftype,_k,_m,_beta,ms); symstreamcf_set_gain(gen, 1.0f/sqrtf(_k)); // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 192000*_k; // number of samples // create spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); unsigned int buf_len = 1337; float complex buf[buf_len]; unsigned int n = 0; while (n < num_samples) { // fill buffer symstreamcf_write_samples(gen, buf, buf_len); n += buf_len; // run through spectral estimation object spgramcf_write(periodogram, buf, buf_len); } // compute power spectral density output float psd[nfft]; spgramcf_get_psd(periodogram, psd); // destroy objects symstreamcf_destroy(gen); spgramcf_destroy(periodogram); // verify spectrum float f0 = 0.5 * (1.0f - _beta) / (float)_k; float f1 = 0.5 * (1.0f + _beta) / (float)_k; autotest_psd_s regions[] = { {.fmin=-0.5, .fmax=-f1, .pmin= 0-0, .pmax=-80.0, .test_lo=0, .test_hi=1}, {.fmin=-f0, .fmax= f0, .pmin= -1.0, .pmax= 1.0, .test_lo=1, .test_hi=1}, {.fmin= f1, .fmax= 0.5, .pmin= 0.0, .pmax=-80.0, .test_lo=0, .test_hi=1}, }; char filename[256]; sprintf(filename,"autotest/logs/symstreamcf_psd_k%u_m%u_b%.3u_autotest.m", _k, _m, (int)(_beta*100)); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, liquid_autotest_verbose ? filename : NULL); } void autotest_symstreamcf_psd_k2_m12_b030() { testbench_symstreamcf_psd(2, 12, 0.30f); } void autotest_symstreamcf_psd_k4_m12_b030() { testbench_symstreamcf_psd(4, 12, 0.30f); } void autotest_symstreamcf_psd_k4_m25_b020() { testbench_symstreamcf_psd(4, 25, 0.20f); } void autotest_symstreamcf_psd_k7_m11_b035() { testbench_symstreamcf_psd(7, 11, 0.35f); } // test copying from one object to another void autotest_symstreamcf_copy() { // create objects symstreamcf gen_orig = symstreamcf_create_linear( LIQUID_FIRFILT_ARKAISER,5,17,0.27f,LIQUID_MODEM_DPSK4); // allocate memory for buffers unsigned int buf_len = 1337; float complex buf_orig[buf_len]; float complex buf_copy[buf_len]; // generate some samples symstreamcf_write_samples(gen_orig, buf_orig, buf_len); // copy object symstreamcf gen_copy = symstreamcf_copy(gen_orig); // generate samples from each object symstreamcf_write_samples(gen_orig, buf_orig, buf_len); symstreamcf_write_samples(gen_copy, buf_copy, buf_len); // compare result // NOTE: this will fail as they have different symbol generators //CONTEND_SAME_DATA(buf_orig, buf_copy, buf_len*sizeof(float complex)); AUTOTEST_WARN("symstreamcf_copy results ignored until common PRNG is used"); // destroy objects symstreamcf_destroy(gen_orig); symstreamcf_destroy(gen_copy); } liquid-dsp-1.7.0/src/framing/tests/symstreamcf_delay_autotest.c000066400000000000000000000074051474751757600250120ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper functions void testbench_symstreamcf_delay(unsigned int _k, unsigned int _m) { // create object and get expected delay int ftype = LIQUID_FIRFILT_ARKAISER; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; symstreamcf gen = symstreamcf_create_linear(ftype,_k,_m,beta,ms); unsigned int delay = symstreamcf_get_delay(gen); float tol = 2.0f + _k; // error tolerance (fairly wide due to random signal) unsigned int i; for (i=0; i<1000 + delay; i++) { // generate a single sample float complex sample; symstreamcf_write_samples(gen, &sample, 1); // check to see if value exceeds 1 if (cabsf(sample) > 0.9f) break; } if (liquid_autotest_verbose) printf("expected delay: %u, approximate delay: %u, tol: %.0f\n", delay, i, tol); // verify delay is relatively close to expected CONTEND_DELTA((float)delay, (float)i, tol); // destroy objects symstreamcf_destroy(gen); } void autotest_symstreamcf_delay_00() { testbench_symstreamcf_delay( 2, 4); } void autotest_symstreamcf_delay_01() { testbench_symstreamcf_delay( 2, 5); } void autotest_symstreamcf_delay_02() { testbench_symstreamcf_delay( 2, 6); } void autotest_symstreamcf_delay_03() { testbench_symstreamcf_delay( 2, 7); } void autotest_symstreamcf_delay_04() { testbench_symstreamcf_delay( 2, 8); } void autotest_symstreamcf_delay_05() { testbench_symstreamcf_delay( 2, 9); } void autotest_symstreamcf_delay_06() { testbench_symstreamcf_delay( 2,10); } void autotest_symstreamcf_delay_07() { testbench_symstreamcf_delay( 2,14); } void autotest_symstreamcf_delay_08() { testbench_symstreamcf_delay( 2,20); } void autotest_symstreamcf_delay_09() { testbench_symstreamcf_delay( 2,31); } void autotest_symstreamcf_delay_10() { testbench_symstreamcf_delay( 3,12); } void autotest_symstreamcf_delay_11() { testbench_symstreamcf_delay( 4,12); } void autotest_symstreamcf_delay_12() { testbench_symstreamcf_delay( 5,12); } void autotest_symstreamcf_delay_13() { testbench_symstreamcf_delay( 6,12); } void autotest_symstreamcf_delay_14() { testbench_symstreamcf_delay( 7,12); } void autotest_symstreamcf_delay_15() { testbench_symstreamcf_delay( 8,12); } void autotest_symstreamcf_delay_16() { testbench_symstreamcf_delay( 9,12); } void autotest_symstreamcf_delay_17() { testbench_symstreamcf_delay(10,12); } void autotest_symstreamcf_delay_18() { testbench_symstreamcf_delay(11,12); } void autotest_symstreamcf_delay_19() { testbench_symstreamcf_delay(12,12); } liquid-dsp-1.7.0/src/framing/tests/symstreamrcf_autotest.c000066400000000000000000000110101474751757600240010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper functions void testbench_symstreamrcf_psd(float _bw, unsigned int _m, float _beta) { // create object int ftype = LIQUID_FIRFILT_ARKAISER; int ms = LIQUID_MODEM_QPSK; symstreamrcf gen = symstreamrcf_create_linear(ftype,_bw,_m,_beta,ms); symstreamrcf_set_gain(gen, sqrtf(_bw)); // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_samples = 192000/_bw; // number of samples // create spectral periodogram spgramcf periodogram = spgramcf_create_default(nfft); unsigned int buf_len = 1337; float complex buf[buf_len]; unsigned int n = 0; while (n < num_samples) { // fill buffer symstreamrcf_write_samples(gen, buf, buf_len); n += buf_len; // run through spectral estimation object spgramcf_write(periodogram, buf, buf_len); } // compute power spectral density output float psd[nfft]; spgramcf_get_psd(periodogram, psd); // destroy objects symstreamrcf_destroy(gen); spgramcf_destroy(periodogram); // verify spectrum // TODO: sidelobe suppression based on internal msresamp object; should be more like -80 dB float f0 = 0.5 * (1.0f - _beta) * _bw; float f1 = 0.5 * (1.0f + _beta) * _bw; autotest_psd_s regions[] = { {.fmin=-0.5, .fmax=-f1, .pmin= 0-0, .pmax=-55.0, .test_lo=0, .test_hi=1}, {.fmin=-f0, .fmax= f0, .pmin= -2.0, .pmax= 2.0, .test_lo=1, .test_hi=1}, {.fmin= f1, .fmax= 0.5, .pmin= 0.0, .pmax=-55.0, .test_lo=0, .test_hi=1}, }; char filename[256]; sprintf(filename,"autotest/logs/symstreamrcf_psd_bw%u_m%u_b%.3u_autotest.m", (int)(_bw*1000), _m, (int)(_beta*100)); liquid_autotest_validate_spectrum(psd, nfft, regions, 3, liquid_autotest_verbose ? filename : NULL); } void autotest_symstreamrcf_psd_bw200_m12_b030() { testbench_symstreamrcf_psd(0.2f, 12, 0.30f); } void autotest_symstreamrcf_psd_bw400_m12_b030() { testbench_symstreamrcf_psd(0.4f, 12, 0.30f); } void autotest_symstreamrcf_psd_bw400_m25_b020() { testbench_symstreamrcf_psd(0.4f, 25, 0.20f); } void autotest_symstreamrcf_psd_bw700_m11_b035() { testbench_symstreamrcf_psd(0.7f, 11, 0.35f); } // test copying from one object to another void autotest_symstreamrcf_copy() { // create objects symstreamrcf gen_orig = symstreamrcf_create_linear( LIQUID_FIRFILT_ARKAISER,0.2f,17,0.27f,LIQUID_MODEM_DPSK4); // allocate memory for buffers unsigned int buf_len = 1337; float complex buf_orig[buf_len]; float complex buf_copy[buf_len]; // generate some samples symstreamrcf_write_samples(gen_orig, buf_orig, buf_len); // copy object symstreamrcf gen_copy = symstreamrcf_copy(gen_orig); // generate samples from each object symstreamrcf_write_samples(gen_orig, buf_orig, buf_len); symstreamrcf_write_samples(gen_copy, buf_copy, buf_len); // compare result // NOTE: this will fail as they have different symbol generators //CONTEND_SAME_DATA(buf_orig, buf_copy, buf_len*sizeof(float complex)); AUTOTEST_WARN("symstreamrcf_copy results ignored until common PRNG is used"); // destroy objects symstreamrcf_destroy(gen_orig); symstreamrcf_destroy(gen_copy); } liquid-dsp-1.7.0/src/framing/tests/symstreamrcf_delay_autotest.c000066400000000000000000000112131474751757600251640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper function: measure delay assuming impulse // - set gain to 1 for a single sample // - set gain to 0 for remaining samples // -> this generates one symbol for the modulation scheme // - take fft of resulting pulse // - observe phase slope across pass-band void testbench_symstreamrcf_delay(float _bw, unsigned int _m) { // create object and get expected delay int ftype = LIQUID_FIRFILT_ARKAISER; float beta = 0.30f; int ms = LIQUID_MODEM_QPSK; symstreamrcf gen = symstreamrcf_create_linear(ftype,_bw,_m,beta,ms); float delay = symstreamrcf_get_delay(gen); float tol = 0.05; // error tolerance // compute buffer length based on delay unsigned int nfft = 2*(120 + (unsigned int)(delay/sqrtf(_bw))); float complex buf_time[nfft]; float complex buf_freq[nfft]; // write samples to buffer symstreamrcf_write_samples(gen, buf_time, 1); symstreamrcf_set_gain(gen, 0.0f); symstreamrcf_write_samples(gen, buf_time+1, nfft-1); // destroy objects symstreamrcf_destroy(gen); // take forward transform fft_run(nfft, buf_time, buf_freq, LIQUID_FFT_FORWARD, 0); // measure phase slope across pass-band unsigned int m = 0.4 * _bw * nfft; // use 0.4 to account for filter roll-off float complex p = 0.0f; int i; for (i=-(int)m; i<(int)m; i++) p += buf_freq[(nfft+i)%nfft] * conjf(buf_freq[(nfft+i+1)%nfft]); float delay_meas = cargf(p) * nfft / (2*M_PI); // print results if (liquid_autotest_verbose) { printf("expected delay: %.6f, measured: %.6f, err: %.6f (tol= %.3f)\n", delay, delay_meas, delay-delay_meas,tol); } // verify delay is relatively close to expected CONTEND_DELTA(delay, delay_meas, tol); } void autotest_symstreamrcf_delay_00() { testbench_symstreamrcf_delay(0.500f, 4); } void autotest_symstreamrcf_delay_01() { testbench_symstreamrcf_delay(0.500f, 5); } void autotest_symstreamrcf_delay_02() { testbench_symstreamrcf_delay(0.500f, 6); } void autotest_symstreamrcf_delay_03() { testbench_symstreamrcf_delay(0.500f, 7); } void autotest_symstreamrcf_delay_04() { testbench_symstreamrcf_delay(0.500f, 8); } void autotest_symstreamrcf_delay_05() { testbench_symstreamrcf_delay(0.500f, 9); } void autotest_symstreamrcf_delay_06() { testbench_symstreamrcf_delay(0.500f,10); } void autotest_symstreamrcf_delay_07() { testbench_symstreamrcf_delay(0.500f,14); } void autotest_symstreamrcf_delay_08() { testbench_symstreamrcf_delay(0.500f,20); } void autotest_symstreamrcf_delay_09() { testbench_symstreamrcf_delay(0.500f,31); } void autotest_symstreamrcf_delay_10() { testbench_symstreamrcf_delay(0.800f,12); } void autotest_symstreamrcf_delay_11() { testbench_symstreamrcf_delay(0.700f,12); } void autotest_symstreamrcf_delay_12() { testbench_symstreamrcf_delay(0.600f,12); } void autotest_symstreamrcf_delay_13() { testbench_symstreamrcf_delay(0.500f,12); } void autotest_symstreamrcf_delay_14() { testbench_symstreamrcf_delay(0.400f,12); } void autotest_symstreamrcf_delay_15() { testbench_symstreamrcf_delay(0.300f,12); } void autotest_symstreamrcf_delay_16() { testbench_symstreamrcf_delay(0.200f,12); } void autotest_symstreamrcf_delay_17() { testbench_symstreamrcf_delay(0.100f,12); } void autotest_symstreamrcf_delay_18() { testbench_symstreamrcf_delay(0.050f,12); } void autotest_symstreamrcf_delay_19() { testbench_symstreamrcf_delay(0.025f,12); } liquid-dsp-1.7.0/src/framing/tests/symtrack_cccf_autotest.c000066400000000000000000000164041474751757600241110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.internal.h" // autotest helper functions void testbench_symtrack_cccf(unsigned int _k, unsigned int _m, float _beta, int _ms) { int ftype = LIQUID_FIRFILT_ARKAISER; unsigned int num_symbols = 6000; // number of data symbols float noise_floor = -30.0f; // noise floor [dB] float SNRdB = 30.0f; // signal-to-noise ratio [dB] float bandwidth = 0.15f; // loop filter bandwidth float dphi = 0.02f; // carrier frequency offset [radians/sample] float phi = 2.1f; // carrier phase offset [radians] // buffers unsigned int buf_len = 800; // buffer size float complex buf_0[buf_len]; // sample buffer float complex buf_1[buf_len]; // recovered symbols buffer // create stream generator symstreamcf gen = symstreamcf_create_linear(ftype,_k,2*_m,_beta,_ms); // create channel emulator and add impairments channel_cccf channel = channel_cccf_create(); channel_cccf_add_awgn (channel, noise_floor, SNRdB); channel_cccf_add_carrier_offset(channel, dphi, phi); //float complex h[4] = {1.0f, 0, 0, 0.2f*cexpf(_Complex_I*1.4f)}; //channel_cccf_add_multipath (channel, h, 4); // create symbol tracking synchronizer symtrack_cccf symtrack = symtrack_cccf_create(ftype,_k,_m,_beta,_ms); symtrack_cccf_set_bandwidth(symtrack,bandwidth); //symtrack_cccf_set_eq_off(symtrack); // disable equalization if (liquid_autotest_verbose) symtrack_cccf_print(symtrack); unsigned int total_samples = 0; //unsigned int total_symbols = 0; unsigned int num_symbols_evm = 0; float evm = 0.0f; modemcf demod = modemcf_create(_ms); // for checking output EVM //FILE * fid = fopen("symtrack_test.dat","w"); //fprintf(fid,"#v=load('symtrack_test.dat'); v=v(:,1)+j*v(:,2); plot(v,'x');\n"); //fprintf(fid,"#axis([-1 1 -1 1]*1.5); axis square; grid on;\n"); while (total_samples < num_symbols * _k) { // write samples to buffer symstreamcf_write_samples(gen, buf_0, buf_len); // apply channel channel_cccf_execute_block(channel, buf_0, buf_len, buf_0); // run resulting stream through synchronizer unsigned int num_symbols_sync; symtrack_cccf_execute_block(symtrack, buf_0, buf_len, buf_1, &num_symbols_sync); //total_symbols += num_symbols_sync; total_samples += buf_len; // check output EVM if (total_samples > 0.80 * num_symbols * _k) { unsigned int i, sym; for (i=0; i #include #include "liquid.internal.h" const char liquid_version[] = LIQUID_VERSION; const char * liquid_libversion(void) { return LIQUID_VERSION; } int liquid_libversion_number(void) { return LIQUID_VERSION_NUMBER; } // report error int liquid_error_fl(int _code, const char * _file, int _line, const char * _format, ...) { #if !LIQUID_SUPPRESS_ERROR_OUTPUT va_list argptr; va_start(argptr, _format); fprintf(stderr,"error [%d]: %s\n", _code, liquid_error_info(_code)); fprintf(stderr," %s:%u: ", _file, _line); vfprintf(stderr, _format, argptr); fprintf(stderr,"\n"); va_end(argptr); #endif #if LIQUID_STRICT_EXIT exit(_code); #endif return _code; } // report error void * liquid_error_config_fl(const char * _file, int _line, const char * _format, ...) { int code = LIQUID_EICONFIG; #if !LIQUID_SUPPRESS_ERROR_OUTPUT va_list argptr; va_start(argptr, _format); fprintf(stderr,"error [%d]: %s\n", code, liquid_error_info(code)); fprintf(stderr," %s:%u: ", _file, _line); vfprintf(stderr, _format, argptr); fprintf(stderr,"\n"); va_end(argptr); #endif #if LIQUID_STRICT_EXIT exit(code); #endif return NULL; } const char * liquid_error_str[LIQUID_NUM_ERRORS] = { "ok", // LIQUID_OK "internal logic error", // LIQUID_EINT "invalid object", // LIQUID_EIOBJ, "invalid parameter or configuration", // LIQUID_EICONFIG "input out of range", // LIQUID_EIVAL "invalid vector length or dimension", // LIQUID_EIRANGE "invalid mode", // LIQUID_EIMODE "unsupported mode", // LIQUID_EUMODE "object has not been created or properly initialized", // LIQUID_ENOINIT "not enough memory allocated for operation", // LIQUID_EIMEM "file input/output", // LIQUID_EIO "algorithm could not converge", // LIQUID_ENOCONV "function or method not yet implemented", // LIQUID_ENOIMP }; // get error string given code const char * liquid_error_info(liquid_error_code _code) { if (_code < 0 || _code >= LIQUID_NUM_ERRORS) { liquid_error(LIQUID_EIMODE,"error code %d is out of range", _code); return NULL; } return liquid_error_str[_code]; } liquid-dsp-1.7.0/src/math/000077500000000000000000000000001474751757600153415ustar00rootroot00000000000000liquid-dsp-1.7.0/src/math/bench/000077500000000000000000000000001474751757600164205ustar00rootroot00000000000000liquid-dsp-1.7.0/src/math/bench/polyfit_benchmark.c000066400000000000000000000051451474751757600222710ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void polyf_fit_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _Q, unsigned int _N) { // normalize number of iterations // time ~ 0.2953 + 0.03381 * _N *_num_iterations /= 0.2953 + 0.03381 * _N * 40; if (*_num_iterations < 1) *_num_iterations = 1; float p[_Q+1]; float x[_N]; float y[_N]; unsigned int i; for (i=0; i<_N; i++) { x[i] = randnf(); y[i] = randnf(); } // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { polyf_fit(x,y,_N, p,_Q+1); polyf_fit(x,y,_N, p,_Q+1); polyf_fit(x,y,_N, p,_Q+1); polyf_fit(x,y,_N, p,_Q+1); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define POLYF_FIT_BENCHMARK_API(Q,N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { polyf_fit_bench(_start, _finish, _num_iterations, Q, N); } void benchmark_polyf_fit_q3_n8 POLYF_FIT_BENCHMARK_API(3, 8) void benchmark_polyf_fit_q3_n16 POLYF_FIT_BENCHMARK_API(3, 16) void benchmark_polyf_fit_q3_n32 POLYF_FIT_BENCHMARK_API(3, 32) void benchmark_polyf_fit_q3_n64 POLYF_FIT_BENCHMARK_API(3, 64) void benchmark_polyf_fit_q3_n128 POLYF_FIT_BENCHMARK_API(3, 128) liquid-dsp-1.7.0/src/math/src/000077500000000000000000000000001474751757600161305ustar00rootroot00000000000000liquid-dsp-1.7.0/src/math/src/math.bessel.c000066400000000000000000000130121474751757600204760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Bessel Functions // // liquid_lnbesselif : log modified Bessel function of the first kind // liquid_besselif : modified Bessel function of the first kind // liquid_besseli0f : modified Bessel function of the first kind (order 0) // liquid_besseljf : Bessel function of the first kind // liquid_besselj0f : Bessel function of the first kind (order 0) // #include #include #include #include #include "liquid.internal.h" // log(I_v(z)) : log Modified Bessel function of the first kind #define NUM_BESSELI_ITERATIONS 64 float liquid_lnbesselif(float _nu, float _z) { // TODO : validate input // special case: check for zeros; besseli_nu(0) = (nu = 0 ? 1 : 0) if (_z == 0) { return _nu == 0.0f ? 0.0f : -FLT_MAX; } // special case: _nu = 1/2, besseli(z) = sqrt(2/pi*z)*sinh(z) if (_nu == 0.5f) { return 0.5f*logf(2.0f/(M_PI*_z)) + logf(sinhf(_z)); } // low signal approximation if (_z < 1e-3f*sqrtf(_nu + 1.0f)) { return -liquid_lngammaf(_nu + 1.0f) + _nu*logf(0.5f*_z); } #if 0 // high-signal approximation: _z >> _nu // I_v(z) ~ exp(z) / sqrt(2*pi*z) // ln I_v(z) ~ z - 0.5*ln(2*pi*z) if ( _nu > 0.0f && logf(_z/_nu) > 8.0f ) return _z - 0.5f*logf(2*M_PI*_z); #endif float t0 = _nu*logf(0.5f*_z); float t1 = 0.0f; float t2 = 0.0f; float t3 = 0.0f; float y = 0.0f; unsigned int k; for (k=0; k 10.0f) return sqrtf(2/(M_PI*fabsf(_z)))*cosf(fabsf(_z)-M_PI/4); unsigned int k; float t, y=0.0f; for (k=0; k #include #include #include "liquid.internal.h" // infty // Q(z) = 1/sqrt(2 pi) int { exp(-u^2/2) du } // z // // Q(z) = (1/2)*(1 - erf(z/sqrt(2))) float liquid_Qf(float _z) { return 0.5f * (1.0f - erff(_z*M_SQRT1_2)); } // Marcum Q-function // TODO : check this computation // [Helstrom:1960], [Proakis:2001], [Helstrom:1992] #define NUM_MARCUMQ_ITERATIONS 16 float liquid_MarcumQf(int _M, float _alpha, float _beta) { #if 0 // expand as: // infty // Q_M(a,b) = exp(-(a^2+b^2)/2) * sum { (a/b)^k I_k(a*b) } // k=1-M return 0.0f #else // use approximation [Helstrom:1992] (Eq. 25) // Q_M(a,b) ~ erfc(x), // x = (b-a-M)/sigma^2, // sigma = M + 2a // compute sigma float sigma = (float)(_M) + 2.0f*_alpha; // compute x float x = (_beta - _alpha - (float)_M) / (sigma*sigma); // return erfc(x) return erfcf(x); #endif } // Marcum Q-function (M=1) // TODO : check this computation // [Helstrom:1960], [Proakis:2001] #define NUM_MARCUMQ1_ITERATIONS 64 float liquid_MarcumQ1f(float _alpha, float _beta) { #if 1 // expand as: infty // Q_1(a,b) = exp(-(a^2+b^2)/2) * sum { (a/b)^k I_k(a*b) } // k=0 float t0 = expf( -0.5f*(_alpha*_alpha + _beta*_beta) ); float t1 = 1.0f; float a_div_b = _alpha / _beta; float a_mul_b = _alpha * _beta; float y = 0.0f; unsigned int k; for (k=0; k 0) { _x >>= 1; n++; } return n; } // (n choose k) = n! / ( k! (n-k)! ) float liquid_nchoosek(unsigned int _n, unsigned int _k) { // if (_k > _n) { liquid_error(LIQUID_EICONFIG,"liquid_nchoosek(), _k cannot exceed _n"); return 0.0f; } else if (_k == 0 || _k == _n) { return 1.0f; } // take advantage of symmetry and take larger value if (_k < _n/2) _k = _n - _k; // use lngamma() function when _n is large if (_n > 12) { double t0 = lgamma((double)_n + 1.0f); double t1 = lgamma((double)_n - (double)_k + 1.0f); double t2 = lgamma((double)_k + 1.0f); return round(exp( t0 - t1 - t2 )); } // old method float rnum=1, rden=1; unsigned int i; for (i=_n; i>_k; i--) rnum *= i; for (i=1; i<=_n-_k; i++) rden *= i; return rnum / rden; } liquid-dsp-1.7.0/src/math/src/math.complex.c000066400000000000000000000064261474751757600207030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex math functions (trig, log, exp, etc.) // #include #include #include #include "liquid.internal.h" // complex square root float complex liquid_csqrtf(float complex _z) { float r = cabsf(_z); // magnitude of _z float a = crealf(_z); // real component of _z float re = sqrtf(0.5f*(r+a)); // real component of return value float im = sqrtf(0.5f*(r-a)); // imag component of return value // return value, retaining sign of imaginary component return cimagf(_z) > 0 ? re + _Complex_I*im : re - _Complex_I*im; } // complex exponent float complex liquid_cexpf(float complex _z) { float r = expf( crealf(_z) ); float re = cosf( cimagf(_z) ); float im = sinf( cimagf(_z) ); return r * ( re + _Complex_I*im ); } // complex logarithm float complex liquid_clogf(float complex _z) { return logf(cabsf(_z)) + _Complex_I*cargf(_z); } // complex arcsin float complex liquid_casinf(float complex _z) { return 0.5f*M_PI - liquid_cacosf(_z); } // complex arccos float complex liquid_cacosf(float complex _z) { // return based on quadrant int sign_i = crealf(_z) > 0; int sign_q = cimagf(_z) > 0; if (sign_i == sign_q) { return -_Complex_I*liquid_clogf(_z + liquid_csqrtf(_z*_z - 1.0f)); } else { return -_Complex_I*liquid_clogf(_z - liquid_csqrtf(_z*_z - 1.0f)); } // should never get to this state return 0.0f; } // complex arctan float complex liquid_catanf(float complex _z) { float complex t0 = 1.0f - _Complex_I*_z; float complex t1 = 1.0f + _Complex_I*_z; return 0.5f*_Complex_I*liquid_clogf( t0 / t1 ); } #if 0 // approximation to cargf() but faster(?) // NOTE: this is not actually very accurate float liquid_cargf_approx(float complex _x) { float theta; float xi = crealf(_x); float xq = cimagf(_x); if (xi == 0.0f) { if (xq == 0.0f) return 0.0f; return xq > 0.0f ? M_PI_2 : -M_PI_2; } else { theta = xq / fabsf(xi); } if (theta > M_PI_2) theta = M_PI_2; else if (theta < -M_PI_2) theta = -M_PI_2; return theta; } #endif liquid-dsp-1.7.0/src/math/src/math.gamma.c000066400000000000000000000116021474751757600203060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // gamma functions // // liquid_lngammaf() : log( Gamma(z) ) // liquid_gammaf() : Gamma(z) // liquid_lnlowergammaf() : log( gamma(z,a) ), lower incomplete // liquid_lnuppergammaf() : log( Gamma(z,a) ), upper incomplete // liquid_lowergammaf() : gamma(z,a), lower incomplete // liquid_uppergammaf() : Gamma(z,a), upper incomplete // liquid_factorialf() : z! // #include #include #include #include "liquid.internal.h" #define NUM_LNGAMMA_ITERATIONS (256) #define EULER_GAMMA (0.57721566490153286) float liquid_lngammaf(float _z) { float g; if (_z < 0) { liquid_error(LIQUID_EICONFIG,"liquid_lngammaf(), undefined for z <= 0"); return 0.0f; } else if (_z < 10.0f) { #if 0 g = -EULER_GAMMA*_z - logf(_z); unsigned int k; for (k=1; k tmax) tmax = t; // conditions: // 1. minimum number of iterations met // 2. surpassed inflection point: k*log(alpha) - log(Gamma(z+k+1)) // has an inverted parabolic shape // 3. sufficiently beyond peak if ( k > LOWERGAMMA_MIN_ITERATIONS && tprime > t && (tmax-t) > 20.0f) break; } return t0 + t1 + t2 + logf(t3); } // ln( Gamma(z,alpha) ) : upper incomplete gamma function float liquid_lnuppergammaf(float _z, float _alpha) { return logf( liquid_gammaf(_z) - liquid_lowergammaf(_z,_alpha) ); } // gamma(z,alpha) : lower incomplete gamma function float liquid_lowergammaf(float _z, float _alpha) { return expf( liquid_lnlowergammaf(_z,_alpha) ); } // Gamma(z,alpha) : upper incomplete gamma function float liquid_uppergammaf(float _z, float _alpha) { return expf( liquid_lnuppergammaf(_z,_alpha) ); } // compute _n! float liquid_factorialf(unsigned int _n) { return fabsf(liquid_gammaf((float)(_n+1))); } liquid-dsp-1.7.0/src/math/src/math.trig.c000066400000000000000000000037171474751757600202010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Useful mathematical formulae (trig) // #include #include #include #include "liquid.internal.h" #if 0 #define LIQUID_SINF_POLYORD (4) static float liquid_sinf_poly[LIQUID_SINF_POLYORD] = { -0.113791698328739f, -0.069825754521815f, 1.026821728423492f, 0.000000000000000f }; #endif void liquid_sincosf(float _x, float * _sinf, float * _cosf) { * _sinf = sinf(_x); * _cosf = cosf(_x); } float liquid_sinf(float _x) { float s, c; liquid_sincosf(_x,&s,&c); return s; } float liquid_cosf(float _x) { float s, c; liquid_sincosf(_x,&s,&c); return c; } float liquid_tanf(float _x) { float s, c; liquid_sincosf(_x,&s,&c); return s/c; } float liquid_expf(float _x) { return expf(_x); } float liquid_logf(float _x) { return logf(_x); } liquid-dsp-1.7.0/src/math/src/modular_arithmetic.c000066400000000000000000000164731474751757600221630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Modular arithmetic and related integer mathematics // #include #include #include "liquid.internal.h" // determine if number is prime (slow, simple method) // https://en.ikipedia.org/wiki/Primality_test#Pseudocode // (thanks to K. Rosenberg for the tip) int liquid_is_prime(unsigned int _n) { // check base cases (0, 1, 2, 3, divisible by 2, divisible by 3) if ( _n <= 1) return 0; else if ( _n <= 3) return 1; else if (!(_n & 1)) return 0; // divisible by 2 else if (!(_n % 3)) return 0; // divisible by 3 unsigned int r=5; while ( r*r <= _n ) { if ( (_n % r) == 0 || (_n % (r+2)) == 0 ) return 0; r += 6; } return 1; } // compute number's prime factors // _n : number to factor // _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] // _num_factors: number of factors found, sorted ascending int liquid_factor(unsigned int _n, unsigned int * _factors, unsigned int * _num_factors) { unsigned int k; unsigned int n = _n; unsigned int num_factors = 0; do { for (k=2; k<=n; k++) { if ( (n % k) == 0) { // k factors _n; append to list _factors[num_factors++] = k; n /= k; break; } } } while (n > 1 && num_factors < LIQUID_MAX_FACTORS); if (n > 1 && num_factors == LIQUID_MAX_FACTORS) return liquid_error(LIQUID_EICONFIG,"liquid_factor(), could not factor %u in %u numbers", _n, LIQUID_MAX_FACTORS); *_num_factors = num_factors; return LIQUID_OK; } // compute number's unique prime factors // _n : number to factor // _factors : pre-allocated array of factors [size: LIQUID_MAX_FACTORS x 1] // _num_factors: number of unique factors found, sorted ascending int liquid_unique_factor(unsigned int _n, unsigned int * _factors, unsigned int * _num_factors) { unsigned int k; unsigned int n = _n; unsigned int num_factors = 0; do { for (k=2; k<=n; k++) { if ( (n % k) == 0) { // k factors _n; append to list _factors[num_factors] = k; n /= k; if (num_factors == 0) num_factors++; else if (_factors[num_factors-1] != k) num_factors++; break; } } } while (n > 1 && num_factors < LIQUID_MAX_FACTORS); if (n > 1 && num_factors == LIQUID_MAX_FACTORS) return liquid_error(LIQUID_EICONFIG,"liquid_unqiue_factor(), could not factor %u in %u numbers", _n, LIQUID_MAX_FACTORS); *_num_factors = num_factors; return LIQUID_OK; } // compute greatest common divisor between to integers \(p\) and \(q\) unsigned int liquid_gcd(unsigned int _p, unsigned int _q) { // check base cases if (_p == 0 || _q == 0) { liquid_error(LIQUID_EICONFIG,"liquid_gcd(%u,%u), input cannot be zero", _p, _q); return 0; } else if (_p == 1 || _q == 1) { return 1; } else if (_p == _q) { return _p; } else if (_p < _q) { return liquid_gcd(_q, _p); } // dumb, slow method unsigned int gcd = 1; unsigned int r = 2; // root while ( r <= _q ) { while ((_p % r)==0 && (_q % r) == 0) { _p /= r; _q /= r; gcd *= r; } r += (r == 2) ? 1 : 2; } return gcd; } // compute c = base^exp (mod n) unsigned int liquid_modpow(unsigned int _base, unsigned int _exp, unsigned int _n) { unsigned int c = 1; unsigned int i; for (i=0; i<_exp; i++) c = (c * _base) % _n; return c; } // find smallest primitive root of _n unsigned int liquid_primitive_root(unsigned int _n) { // TODO : flesh out this function return 1; } // find smallest primitive root of _n (assuming _n is prime) unsigned int liquid_primitive_root_prime(unsigned int _n) { // find unique factors of _n-1 unsigned int unique_factors[LIQUID_MAX_FACTORS]; unsigned int num_unique_factors = 0; unsigned int n = _n-1; unsigned int k; do { for (k=2; k<=n; k++) { if ( (n%k)==0 ) { // k is a factor of (_n-1) n /= k; // add element to end of table unique_factors[num_unique_factors] = k; // increment counter only if element is unique if (num_unique_factors == 0) num_unique_factors++; else if (unique_factors[num_unique_factors-1] != k) num_unique_factors++; break; } } } while (n > 1 && num_unique_factors < LIQUID_MAX_FACTORS); #if 0 // print unique factors printf("found %u unique factors of n-1 = %u\n", num_unique_factors, _n-1); for (k=0; k 1); return t; } liquid-dsp-1.7.0/src/math/src/poly.c000066400000000000000000000044421474751757600172630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point polynomials (double precision) // #include "liquid.internal.h" #define MATRIX(name) LIQUID_CONCAT(matrix, name) #define POLY(name) LIQUID_CONCAT(poly, name) #define POLY_NAME "poly" #define EXTENSION "" #define T double #define TC double complex #define T_COMPLEX 0 #define TI_COMPLEX 1 #define T_ABS(X) fabs(X) #define TC_ABS(X) cabs(X) // prototypes #include "poly.common.proto.c" #include "poly.expand.proto.c" #include "poly.lagrange.proto.c" // finds the complex roots of the polynomial // _p : polynomial array, ascending powers [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots [size: _k-1 x 1] int poly_findroots(double * _p, unsigned int _k, double complex * _roots) { // find roots of polynomial using Bairstow's method (more // accurate and reliable than Durand-Kerner) liquid_poly_findroots_bairstow(_p,_k,_roots); // sort roots for consistent ordering qsort(_roots, _k-1, sizeof(double complex), &liquid_poly_sort_roots_compare); return LIQUID_OK; } liquid-dsp-1.7.0/src/math/src/poly.common.proto.c000066400000000000000000000046141474751757600217150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // common polynomial routines // polyval // polyfit // #include #include #include #include T POLY(_val)(T * _p, unsigned int _k, T _x) { unsigned int i; T xk = 1; T y = 0.0f; for (i=0; i<_k; i++) { y += _p[i]*xk; xk *= _x; } return y; } int POLY(_fit)(T * _x, T * _y, unsigned int _n, T * _p, unsigned int _k) { // ... T X[_n*_k]; unsigned int r,c; T v; for (r=0; r<_n; r++) { v = 1; for (c=0; c<_k; c++) { matrix_access(X,_n,_k,r,c) = v; v *= _x[r]; } } // compute transpose of X T Xt[_k*_n]; memmove(Xt,X,_k*_n*sizeof(T)); MATRIX(_trans)(Xt,_n,_k); // compute [X']*y T Xty[_k]; MATRIX(_mul)(Xt, _k, _n, _y, _n, 1, Xty,_k, 1); // compute [X']*X T X2[_k*_k]; MATRIX(_mul)(Xt, _k, _n, X, _n, _k, X2, _k, _k); // compute inv([X']*X) T G[_k*_k]; memmove(G,X2,_k*_k*sizeof(T)); MATRIX(_inv)(G,_k,_k); // compute coefficients MATRIX(_mul)(G, _k, _k, Xty,_k, 1, _p, _k, 1); return LIQUID_OK; } liquid-dsp-1.7.0/src/math/src/poly.expand.proto.c000066400000000000000000000152131474751757600217010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // polynomial expansion methods // #include #include #include #include "liquid.internal.h" // expands the polynomial: // P_n(x) = (1+x)^n // as // P_n(x) = p[0] + p[1]*x + p[2]*x^2 + ... + p[n]x^n // NOTE: _p has order n=m+k (array is length n+1) int POLY(_expandbinomial)(unsigned int _n, T * _c) { // no roots; return zero if (_n == 0) { _c[0] = 0.; return LIQUID_OK; } int i, j; // initialize coefficients array to [1,0,0,....0] for (i=0; i<=_n; i++) _c[i] = (i==0) ? 1 : 0; // iterative polynomial multiplication for (i=0; i<_n; i++) { for (j=i+1; j>0; j--) _c[j] = _c[j] + _c[j-1]; } // assert(_c[0]==1.0f); return LIQUID_OK; } // expands the polynomial: // P_n(x) = (1+x)^m * (1-x)^k // as // P_n(x) = p[0] + p[1]*x + p[2]*x^2 + ... + p[n]x^n // NOTE: _p has order n=m+k (array is length n+1) int POLY(_expandbinomial_pm)(unsigned int _m, unsigned int _k, T * _c) { unsigned int n = _m + _k; // no roots; return zero if (n == 0) { _c[0] = 0.; return LIQUID_OK; } int i, j; // initialize coefficients array to [1,0,0,....0] for (i=0; i<=n; i++) _c[i] = (i==0) ? 1 : 0; // iterative polynomial multiplication (1+x) for (i=0; i<_m; i++) { for (j=i+1; j>0; j--) _c[j] = _c[j] + _c[j-1]; } // iterative polynomial multiplication (1-x) for (i=_m; i0; j--) _c[j] = _c[j] - _c[j-1]; } // assert(_c[0]==1.0f); return LIQUID_OK; } #if 0 // expands the polynomial: // (1+x*a[0])*(1+x*a[1]) * ... * (1+x*a[n-1]) // as // c[0] + c[1]*x + c[2]*x^2 + ... + c[n]*x^n int POLY(_expandbinomial)(T * _a, unsigned int _n, T * _c) { // no roots; return zero if (_n == 0) { _c[0] = 0.; return LIQUID_OK; } int i, j; // initialize coefficients array to [1,0,0,....0] for (i=0; i<=_n; i++) _c[i] = (i==0) ? 1 : 0; // iterative polynomial multiplication for (i=0; i<_n; i++) { for (j=i+1; j>0; j--) _c[j] = _a[i]*_c[j] + _c[j-1]; _c[j] *= _a[i]; } // flip values unsigned int r = (_n+1) % 2; unsigned int L = (_n+1-r)/2; T tmp; for (i=0; i0; j--) _p[j] = -_r[i]*_p[j] + _p[j-1]; _p[j] *= -_r[i]; } // assert(c[_n]==1.0f) return LIQUID_OK; } // Perform root expansion on the polynomial // "P_n(x) = (x*b[0]-a[0]) * (x*b[1]-a[1]) * ... * (x*b[n-1]-a[n-1])" // as // "P_n(x) = p[0] + p[1]*x + ... + p[n]*x^n" // NOTE: _p has order _n (array is length _n+1) // _a : subtractant of polynomial rotos [size: _n x 1] // _b : multiplicant of polynomial roots [size: _n x 1] // _n : number of roots in polynomial // _p : polynomial coefficients [size: _n+1 x 1] int POLY(_expandroots2)(T * _a, T * _b, unsigned int _n, T * _p) { unsigned int i; // factor _b[i] from each root : (x*b - a) = (x - a/b)*b T g = 1.0; T r[_n]; for (i=0; i<_n; i++) { g *= -_b[i]; r[i] = _a[i] / _b[i]; } // expand new root set POLY(_expandroots)(r, _n, _p); // multiply by gain for (i=0; i<_n+1; i++) _p[i] *= g; return LIQUID_OK; } // expands the multiplication of two polynomials // // (a[0] + a[1]*x + a[2]*x^2 + ...) * (b[0] + b[1]*x + b[]*x^2 + ...) // as // c[0] + c[1]*x + c[2]*x^2 + ... + c[n]*x^n // // where order(c) = order(a) + order(b) + 1 // :: length(c) = length(a) + length(b) - 1 // // _a : 1st polynomial coefficients (length is _order_a+1) // _order_a : 1st polynomial order // _b : 2nd polynomial coefficients (length is _order_b+1) // _order_b : 2nd polynomial order // _c : output polynomial coefficients (length is _order_a + _order_b + 1) int POLY(_mul)(T * _a, unsigned int _order_a, T * _b, unsigned int _order_b, T * _c) { unsigned int na = _order_a + 1; unsigned int nb = _order_b + 1; unsigned int nc = na + nb - 1; unsigned int i; for (i=0; i #include #include #include #include #include "liquid.internal.h" // debug polynomial root-finding methods? #define LIQUID_POLY_FINDROOTS_DEBUG 0 // finds the complex roots of the polynomial using the Durand-Kerner method // _p : polynomial array, ascending powers [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots [size: _k-1 x 1] int liquid_poly_findroots_durandkerner(double * _p, unsigned int _k, double complex * _roots) { if (_k < 2) return liquid_error(LIQUID_EICONFIG,"liquid_poly_findroots_durandkerner(), order must be greater than 0"); if (_p[_k-1] != 1) return liquid_error(LIQUID_EICONFIG,"liquid_poly_findroots_durandkerner(), _p[_k-1] must be equal to 1"); unsigned int i; unsigned int num_roots = _k-1; double r0[num_roots]; double r1[num_roots]; // find initial magnitude float g = 0.0f; float gmax = 0.0f; for (i=0; i<_k; i++) { g = fabs(_p[i]); if (i==0 || g > gmax) gmax = g; } // initialize roots double t0 = 0.9f * (1 + gmax) * cexpf(_Complex_I*1.1526f); double t = 1.0f; for (i=0; i 3) liquid_poly_findroots_bairstow_persistent(p,n,pr,&u,&v); // compute complex roots of x^2 + u*x + v double complex r0 = 0.5f*(-u + csqrtf(u*u - 4.0*v)); double complex r1 = 0.5f*(-u - csqrtf(u*u - 4.0*v)); //printf("roots: r0=%12.8f + j*%12.8f, r1=%12.8f + j*%12.8f\n\n", // creal(r0), cimag(r0), creal(r1), cimag(r1)); // append result to output _roots[k++] = r0; _roots[k++] = r1; #if LIQUID_POLY_FINDROOTS_DEBUG // print debugging info unsigned int j; printf("initial polynomial:\n"); for (j=0; j=0; i--) { b[i] = _p[i+2] - u*b[i+1] - v*b[i+2]; f[i] = b[i+2] - u*f[i+1] - v*f[i+2]; } c = _p[1] - u*b[0] - v*b[1]; g = b[1] - u*f[0] - v*f[1]; d = _p[0] - v*b[0]; h = b[0] - v*f[0]; // compute scaling factor q0 = v*g*g; q1 = h*(h-u*g); double metric = fabs(q0+q1); if ( metric < tol ) { q = 0; u *= 0.5; v *= 0.5; continue; } else { q = 1/(v*g*g + h*(h-u*g)); } // compute u, v steps du = - q*(-h*c + g*d); dv = - q*(-g*v*c + (g*u-h)*d); double step = fabs(du)+fabs(dv); #if 0 printf(" %3u : q0=%12.4e, q1=%12.4e, q=%12.4e, metric=%12.4e, u=%8.3f, v=%8.3f, step=%12.4e\n", num_iterations, fabs(q0), fabs(q1), fabs(q), metric, creal(u), creal(v), step); #endif #if LIQUID_POLY_FINDROOTS_DEBUG // print debugging info printf("bairstow [%u] :\n", num_iterations); printf(" u : %12.4e + j*%12.4e\n", creal(u), cimag(u)); printf(" v : %12.4e + j*%12.4e\n", creal(v), cimag(v)); printf(" b : \n"); for (i=0; i bi ? -1 : 1) : (ar > br ? 1 : -1); } liquid-dsp-1.7.0/src/math/src/poly.lagrange.proto.c000066400000000000000000000106141474751757600222020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Lagrange polynomial methods // #include #include // Lagrange polynomial exact fit (order _n-1) int POLY(_fit_lagrange)(T * _x, T * _y, unsigned int _n, T * _p) { unsigned int k=_n-1; // polynomial order // clear polynomial coefficients array unsigned int i; for (i=0; i<_n; i++) _p[i] = 0.; // compute roots, gain T roots[k]; // polynomial roots T c[_n]; // expanded polynomial T g; // gain unsigned int j; unsigned int n; for (i=0; i<_n; i++) { n=0; g=1.0f; for (j=0; j<_n; j++) { if (j!=i) { roots[n++] = _x[j]; g *= (_x[i] - _x[j]); } } g = _y[i] / g; // expand roots POLY(_expandroots)(roots, k, c); for (j=0; j<_n; j++) { _p[j] += g * c[j]; } #if 0 // debug/print printf("****** %3u : **********************\n", i); printf(" g : %12.8f\n", crealf(g)); printf(" roots:\n"); for (j=0; j %16.6f\n", j, crealf(c[j]), crealf(g*c[j])); #endif } return LIQUID_OK; } // Lagrange polynomial interpolation T POLY(_interp_lagrange)(T * _x, T * _y, unsigned int _n, T _x0) { T y0 = 0.0; // set output to zero T g; // accumulator unsigned int i, j; for (i=0; i<_n; i++) { g=1.0f; for (j=0; j<_n; j++) { if (j!=i) { g *= (_x0 - _x[j])/(_x[i] - _x[j]); } } y0 += _y[i] * g; } return y0; } // Lagrange polynomial fit (barycentric form) int POLY(_fit_lagrange_barycentric)(T * _x, unsigned int _n, T * _w) { // compute barycentric weights (slow method) unsigned int j, k; for (j=0; j<_n; j++) { _w[j] = 1.; for (k=0; k<_n; k++) { if (j==k) continue; else _w[j] *= (_x[j] - _x[k]); } if (_w[j] == 0.0f) _w[j] += 1.0e-9f; _w[j] = 1. / _w[j]; } // normalize by _w[0], add minuscule margin to avoid division by zero T w0 = _w[0] + 1.0e-9f; for (j=0; j<_n; j++) _w[j] /= w0; return LIQUID_OK; } // Lagrange polynomial interpolation (barycentric form) T POLY(_val_lagrange_barycentric)(T * _x, T * _y, T * _w, T _x0, unsigned int _n) { T t0 = 0.; // numerator sum T t1 = 0.; // denominator sum T g; // _x0 - _x[j] // exact fit tolerance float tol = 1e-6f; unsigned int j; for (j=0; j<_n; j++) { g = _x0 - _x[j]; // test for "exact" fit if (T_ABS(g) < tol) return _y[j]; t0 += _w[j] * _y[j] / g; t1 += _w[j] / g; } return t0 / t1; } liquid-dsp-1.7.0/src/math/src/polyc.c000066400000000000000000000041511474751757600174230ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point polynomials (double precision) // #include "liquid.internal.h" #define MATRIX(name) LIQUID_CONCAT(matrixc, name) #define POLY(name) LIQUID_CONCAT(polyc, name) #define POLY_NAME "polyc" #define EXTENSION "c" #define T double complex #define TC double complex #define T_COMPLEX 1 #define TI_COMPLEX 1 #define T_ABS(X) cabs(X) #define TC_ABS(X) cabs(X) // prototypes #include "poly.common.proto.c" #include "poly.expand.proto.c" #include "poly.lagrange.proto.c" // finds the complex roots of the polynomial // _p : polynomial array, ascending powers [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots [size: _k-1 x 1] int polyc_findroots(double complex * _p, unsigned int _k, double complex * _roots) { return liquid_error(LIQUID_ENOIMP,"polyc_findroots(), complex root-finding not yet supported"); } liquid-dsp-1.7.0/src/math/src/polycf.c000066400000000000000000000041561474751757600175760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Complex floating-point polynomials (single precision) // #include "liquid.internal.h" #define MATRIX(name) LIQUID_CONCAT(matrixcf, name) #define POLY(name) LIQUID_CONCAT(polycf, name) #define POLY_NAME "polycf" #define EXTENSION "cf" #define T float complex #define TC float complex #define T_COMPLEX 1 #define TI_COMPLEX 1 #define T_ABS(X) cabsf(X) #define TC_ABS(X) cabsf(X) // prototypes #include "poly.common.proto.c" #include "poly.expand.proto.c" #include "poly.lagrange.proto.c" // finds the complex roots of the polynomial // _p : polynomial array, ascending powers [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots [size: _k-1 x 1] int polycf_findroots(float complex * _p, unsigned int _k, float complex * _roots) { return liquid_error(LIQUID_ENOIMP,"polycf_findroots(), complex root-finding not yet supported"); } liquid-dsp-1.7.0/src/math/src/polyf.c000066400000000000000000000053221474751757600174270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point polynomials (single precision) // #include "liquid.internal.h" #define MATRIX(name) LIQUID_CONCAT(matrixf, name) #define POLY(name) LIQUID_CONCAT(polyf, name) #define POLY_NAME "polyf" #define EXTENSION "f" #define T float #define TC float complex #define T_COMPLEX 0 #define TI_COMPLEX 1 #define T_ABS(X) fabsf(X) #define TC_ABS(X) cabsf(X) // prototypes #include "poly.common.proto.c" #include "poly.expand.proto.c" #include "poly.lagrange.proto.c" // finds the complex roots of the polynomial // _p : polynomial array, ascending powers [size: _k x 1] // _k : polynomials length (poly order = _k - 1) // _roots : resulting complex roots [size: _k-1 x 1] int polyf_findroots(float * _p, unsigned int _k, float complex * _roots) { unsigned int i; // copy to temporary double-precision array double * p = (double*) malloc(_k * sizeof(double)); for (i=0; i<_k; i++) p[i] = (double)_p[i]; // find roots of polynomial using Bairstow's method (more // accurate and reliable than Durand-Kerner) double complex * roots = (double complex*)malloc((_k-1)*sizeof(double complex)); int rc = liquid_poly_findroots_bairstow(p,_k,roots); // sort roots for consistent ordering qsort(roots, _k-1, sizeof(double complex), &liquid_poly_sort_roots_compare); // copy back to original for (i=0; i<_k-1; i++) _roots[i] = (float complex)roots[i]; // free memory and return free(p); free(roots); return rc; } liquid-dsp-1.7.0/src/math/src/windows.c000066400000000000000000000321471474751757600177750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Windowing functions // // References: // [Kaiser:1980] James F. Kaiser and Ronald W. Schafer, "On // the Use of I0-Sinh Window for Spectrum Analysis," // IEEE Transactions on Acoustics, Speech, and Signal // Processing, vol. ASSP-28, no. 1, pp. 105--107, // February, 1980. // [harris:1978] frederic j. harris, "On the Use of Windows for Harmonic // Analysis with the Discrete Fourier Transform," Proceedings of the // IEEE, vol. 66, no. 1, January, 1978. // [Nuttall:1981] Albert H. Nuttall, "Some Windows with Very Good Sidelobe // Behavior," IEEE Transactions on Acoustics, Speech, and Signal // Processing, vol. ASSP-29, no. 1, pp. 84-91, February, 1981. #include #include #include #include #include "liquid.internal.h" const char * liquid_window_str[LIQUID_WINDOW_NUM_FUNCTIONS][2] = { // short name, long name {"unknown", "unknown" }, {"hamming", "Hamming" }, {"hann", "Hann" }, {"blackmanharris", "Blackman-harris (4-term)" }, {"blackmanharris7", "Blackman-harris (7-term)" }, {"kaiser", "Kaiser-Bessel" }, {"flattop", "flat top" }, {"triangular", "triangular" }, {"rcostaper", "raised-cosine taper" }, {"kbd", "Kaiser-Bessel derived" }, }; // Print compact list of existing and available windowing functions int liquid_print_windows() { unsigned int i; unsigned int len = 10; // print all available window functions printf(" "); for (i=0; i 48 && i != LIQUID_WINDOW_NUM_FUNCTIONS-1) { len = 10; printf("\n "); } } printf("\n"); return LIQUID_OK; } // returns modulation_scheme based on input string liquid_window_type liquid_getopt_str2window(const char * _str) { // compare each string to short name unsigned int i; for (i=0; i= _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_kbd(), index exceeds maximum"); return 0.0f; } else if (_wlen == 0) { liquid_error(LIQUID_EICONFIG,"liquid_kbd(), window length must be greater than zero"); return 0.0f; } else if ( _wlen % 2 ) { liquid_error(LIQUID_EICONFIG,"liquid_kbd(), window length must be odd"); return 0.0f; } unsigned int M = _wlen / 2; if (_i >= M) return liquid_kbd(_wlen-_i-1,_wlen,_beta); float w0 = 0.0f; float w1 = 0.0f; float w; unsigned int i; for (i=0; i<=M; i++) { // compute Kaiser window w = liquid_kaiser(i,M+1,_beta); // accumulate window sums w1 += w; if (i <= _i) w0 += w; } //printf("%12.8f / %12.8f = %12.8f\n", w0, w1, w0/w1); return sqrtf(w0 / w1); } // Kaiser-Bessel derived window (full window function) // TODO add reference int liquid_kbd_window(unsigned int _i, float _beta, float * _w) { // validate input if (_i == 0) return liquid_error(LIQUID_EICONFIG,"liquid_kbd_window(), window length must be greater than zero"); if ( _i % 2 ) return liquid_error(LIQUID_EICONFIG,"liquid_kbd_window(), window length must be odd"); if ( _beta < 0.0f ) return liquid_error(LIQUID_EICONFIG,"liquid_kbd_window(), _beta must be positive"); // compute half length unsigned int M = _i / 2; // generate regular Kaiser window, length M+1 unsigned int i; float w_kaiser[M+1]; for (i=0; i<=M; i++) w_kaiser[i] = liquid_kaiser(i,M+1,_beta); // compute sum(wk[]) float w_sum = 0.0f; for (i=0; i<=M; i++) w_sum += w_kaiser[i]; // accumulate window float w_acc = 0.0f; for (i=0; i= _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_kaiser(), sample index must not exceed window length"); return 0.0f; } else if (_beta < 0) { liquid_error(LIQUID_EICONFIG,"liquid_kaiser(), beta must be greater than or equal to zero"); return 0.0f; } float t = (float)_i - (float)(_wlen-1)/2; float r = 2.0f*t/(float)(_wlen-1); float a = liquid_besseli0f(_beta*sqrtf(1-r*r)); float b = liquid_besseli0f(_beta); //printf("kaiser(%3u,%u3,%6.3f) t:%8.3f, r:%8.3f, a:%8.3f, b:%8.3f\n", _i,_wlen,_beta,t,r,a,b); return a / b; } // Hamming window [Nuttall:1981] float liquid_hamming(unsigned int _i, unsigned int _wlen) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_hamming(), sample index must not exceed window length"); return 0.0f; } return 0.53836 - 0.46164*cosf( (2*M_PI*(float)_i) / ((float)(_wlen-1)) ); } // Hann window float liquid_hann(unsigned int _i, unsigned int _wlen) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_hann(), sample index must not exceed window length"); return 0.0f; } // TODO test this function // TODO add reference return 0.5f - 0.5f*cosf( (2*M_PI*(float)_i) / ((float)(_wlen-1)) ); } // Blackman-harris window [harris:1978] float liquid_blackmanharris(unsigned int _i, unsigned int _wlen) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_blackmanharris(), sample index must not exceed window length"); return 0.0f; } // TODO test this function // TODO add reference float a0 = 0.35875f; float a1 = 0.48829f; float a2 = 0.14128f; float a3 = 0.01168f; float t = 2*M_PI*(float)_i / ((float)(_wlen-1)); return a0 - a1*cosf(t) + a2*cosf(2*t) - a3*cosf(3*t); } // 7th-order Blackman-harris window float liquid_blackmanharris7(unsigned int _i, unsigned int _wlen) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_blackmanharris7(), sample index must not exceed window length"); return 0.0f; } float a0 = 0.27105f; float a1 = 0.43329f; float a2 = 0.21812f; float a3 = 0.06592f; float a4 = 0.01081f; float a5 = 0.00077f; float a6 = 0.00001f; float t = 2*M_PI*(float)_i / ((float)(_wlen-1)); return a0 - a1*cosf( t) + a2*cosf(2*t) - a3*cosf(3*t) + a4*cosf(4*t) - a5*cosf(5*t) + a6*cosf(6*t); } // Flat-top window float liquid_flattop(unsigned int _i, unsigned int _wlen) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_flattop(), sample index must not exceed window length"); return 0.0f; } float a0 = 1.000f; float a1 = 1.930f; float a2 = 1.290f; float a3 = 0.388f; float a4 = 0.028f; float t = 2*M_PI*(float)_i / ((float)(_wlen-1)); return a0 - a1*cosf(t) + a2*cosf(2*t) - a3*cosf(3*t) + a4*cosf(4*t); } // Triangular window float liquid_triangular(unsigned int _i, unsigned int _wlen, unsigned int _n) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_triangular(), sample index must not exceed window length"); return 0.0f; } else if (_n != _wlen-1 && _n != _wlen && _n != _wlen+1) { liquid_error(LIQUID_EICONFIG,"liquid_triangular(), sub-length must be in _wlen+{-1,0,1}"); return 0.0f; } else if (_n == 0) { liquid_error(LIQUID_EICONFIG,"liquid_triangular(), sub-length must be greater than zero"); return 0.0f; } float v0 = (float)_i - (float)((_wlen-1)/2.0f); float v1 = ((float)_n)/2.0f; return 1.0 - fabsf(v0 / v1); } // raised-cosine tapering window // _i : window index // _wlen : full window length // _t : taper length float liquid_rcostaper_window(unsigned int _i, unsigned int _wlen, unsigned int _t) { // validate input if (_i > _wlen) { liquid_error(LIQUID_EICONFIG,"liquid_rcostaper_window(), sample index must not exceed window length"); return 0.0f; } else if (_t > _wlen/2) { liquid_error(LIQUID_EICONFIG,"liquid_rcostaper_window(), taper length cannot exceed half window length"); return 0.0f; } // reverse time for ramp-down section if (_i > _wlen - _t - 1) _i = _wlen - _i - 1; // return ramp or flat component return (_i < _t) ? 0.5f - 0.5f*cosf(M_PI*((float)_i + 0.5f) / (float)_t) : 1.0f; } // shim to support legacy APIs (backwards compatible with 1.3.2) float kaiser(unsigned int _i,unsigned int _wlen, float _beta, float _dt) { return liquid_kaiser(_i,_wlen,_beta); } float hamming(unsigned int _i,unsigned int _wlen) { return liquid_hamming(_i,_wlen); } float hann(unsigned int _i,unsigned int _wlen) { return liquid_hann(_i,_wlen); } float blackmanharris(unsigned int _i,unsigned int _wlen) { return liquid_blackmanharris(_i,_wlen); } float blackmanharris7(unsigned int _i,unsigned int _wlen) { return liquid_blackmanharris7(_i,_wlen); } float flattop(unsigned int _i,unsigned int _wlen) { return liquid_flattop(_i,_wlen); } float triangular(unsigned int _i,unsigned int _wlen,unsigned int _n) { return liquid_triangular(_i,_wlen,_n); } float liquid_rcostaper_windowf(unsigned int _i,unsigned int _wlen,unsigned int _t) { return liquid_rcostaper_window(_i,_wlen,_t); } float kbd(unsigned int _i,unsigned int _wlen,float _beta) { return liquid_kbd(_i,_wlen,_beta); } int kbd_window(unsigned int _wlen,float _beta,float * _w) { return liquid_kbd_window(_wlen,_beta,_w); } liquid-dsp-1.7.0/src/math/tests/000077500000000000000000000000001474751757600165035ustar00rootroot00000000000000liquid-dsp-1.7.0/src/math/tests/gcd_autotest.c000066400000000000000000000046001474751757600213340ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" void testbench_gcd(unsigned int _gcd, unsigned int _p, unsigned int _q) { unsigned int P = _p * _gcd; unsigned int Q = _q * _gcd; unsigned int gcd_test = liquid_gcd(P,Q); if (liquid_autotest_verbose) printf(" gcd(%12u,%12u) = %12u (expected %u)\n", P, Q, gcd_test, _gcd); CONTEND_EQUALITY(gcd_test, _gcd); } // no common roots; gcd = 1 void autotest_gcd_one() { testbench_gcd( 1, 2, 3); testbench_gcd( 1, 2, 5); testbench_gcd( 1, 2, 7); testbench_gcd( 1, 7, 2); testbench_gcd( 1, 17, 19); testbench_gcd( 1, 23, 31); testbench_gcd( 1, 2*2*2*2*2, 3*5*7*19); } // edge cases void autotest_gcd_edge_cases() { testbench_gcd( 1, 1, 1); testbench_gcd( 1, 1, 2); testbench_gcd( 1, 1, 2400); testbench_gcd( 12345, 1, 1); // P==Q testbench_gcd( (1<<17)-1, 1, 1); // P==Q } // set of base tests void autotest_gcd_base() { testbench_gcd( 2*2*3*5*7, 2*3, 17); testbench_gcd( 2*2*3*5*7, 2*3, 17*17); testbench_gcd( 2*2*3*5*7, 2*3, 17*17*17); testbench_gcd( 11, 3, 1); testbench_gcd( 3, 127, 131); testbench_gcd( 131, 127, 3); testbench_gcd( 127, 131, 3); } liquid-dsp-1.7.0/src/math/tests/math_autotest.c000066400000000000000000000061771474751757600215430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // Q function void autotest_Q() { float tol = 1e-6f; CONTEND_DELTA(liquid_Qf(-4.0f), 0.999968329f, tol); CONTEND_DELTA(liquid_Qf(-3.0f), 0.998650102f, tol); CONTEND_DELTA(liquid_Qf(-2.0f), 0.977249868f, tol); CONTEND_DELTA(liquid_Qf(-1.0f), 0.841344746f, tol); CONTEND_DELTA(liquid_Qf( 0.0f), 0.5f, tol); CONTEND_DELTA(liquid_Qf( 1.0f), 0.158655254f, tol); CONTEND_DELTA(liquid_Qf( 2.0f), 0.022750132f, tol); CONTEND_DELTA(liquid_Qf( 3.0f), 0.001349898f, tol); CONTEND_DELTA(liquid_Qf( 4.0f), 0.000031671f, tol); } // sincf void autotest_sincf() { float tol = 1e-3f; CONTEND_DELTA(sincf(0.0f), 1.0f, tol); } // nextpow2 void autotest_nextpow2() { CONTEND_EQUALITY(liquid_nextpow2(1), 0); CONTEND_EQUALITY(liquid_nextpow2(2), 1); CONTEND_EQUALITY(liquid_nextpow2(3), 2); CONTEND_EQUALITY(liquid_nextpow2(4), 2); CONTEND_EQUALITY(liquid_nextpow2(5), 3); CONTEND_EQUALITY(liquid_nextpow2(6), 3); CONTEND_EQUALITY(liquid_nextpow2(7), 3); CONTEND_EQUALITY(liquid_nextpow2(8), 3); CONTEND_EQUALITY(liquid_nextpow2(9), 4); CONTEND_EQUALITY(liquid_nextpow2(10), 4); CONTEND_EQUALITY(liquid_nextpow2(11), 4); CONTEND_EQUALITY(liquid_nextpow2(12), 4); CONTEND_EQUALITY(liquid_nextpow2(13), 4); CONTEND_EQUALITY(liquid_nextpow2(14), 4); CONTEND_EQUALITY(liquid_nextpow2(15), 4); CONTEND_EQUALITY(liquid_nextpow2(67), 7); CONTEND_EQUALITY(liquid_nextpow2(179), 8); CONTEND_EQUALITY(liquid_nextpow2(888), 10); } // test math configuration and error handling void autotest_math_config() { //_liquid_error_downgrade_enable(); CONTEND_EQUALITY(liquid_nextpow2(0), 0); CONTEND_EQUALITY(liquid_nchoosek(4, 5), 0.0f); CONTEND_EQUALITY(liquid_lngammaf(-1), 0.0f); CONTEND_EQUALITY(liquid_gcd(12, 0), 0); CONTEND_EQUALITY(liquid_gcd( 0,12), 0); CONTEND_EQUALITY(liquid_gcd( 0, 0), 0); //_liquid_error_downgrade_disable(); } liquid-dsp-1.7.0/src/math/tests/math_bessel_autotest.c000066400000000000000000000203221474751757600230640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: log Modified Bessel function of the first kind // void autotest_lnbesselif() { float tol = 1e-5f; // test lnbesselif(nu,z) with various values for nu and z CONTEND_DELTA( liquid_lnbesselif( 0.0f, 0.0f), 0.0, tol ); CONTEND_DELTA( liquid_lnbesselif( 0.0f, 0.1f), 0.00249843923387607,tol ); CONTEND_DELTA( liquid_lnbesselif( 0.1f, 7.1f), 5.21933724549090, tol ); CONTEND_DELTA( liquid_lnbesselif( 0.3f, 2.1f), 0.853008130814754, tol ); CONTEND_DELTA( liquid_lnbesselif( 0.9f, 9.3f), 7.23414120004177, tol ); CONTEND_DELTA( liquid_lnbesselif( 1.0f, 0.1f), -2.99448253386220, tol ); CONTEND_DELTA( liquid_lnbesselif( 1.7f, 0.01f), -9.44195081753909, tol ); CONTEND_DELTA( liquid_lnbesselif( 1.8f, 1e-3f), -14.1983271298778, tol ); CONTEND_DELTA( liquid_lnbesselif( 1.9f, 8.7f), 6.49469148684252, tol ); CONTEND_DELTA( liquid_lnbesselif( 4.9f, 0.01f), -30.5795429642925, tol ); CONTEND_DELTA( liquid_lnbesselif( 7.4f, 9.3f), 4.33486237261960, tol ); // test large values of nu CONTEND_DELTA( liquid_lnbesselif( 20.0f, 3.0f), -34.1194307343208, tol); CONTEND_DELTA( liquid_lnbesselif( 30.0f, 3.0f), -62.4217845317278, tol); #if 0 CONTEND_DELTA( liquid_lnbesselif( 35.0f, 3.0f), -77.8824494916507, tol); CONTEND_DELTA( liquid_lnbesselif( 38.0f, 3.0f), -87.5028737258841, tol); CONTEND_DELTA( liquid_lnbesselif( 39.0f, 3.0f), -90.7624095618186, tol); CONTEND_DELTA( liquid_lnbesselif( 40.0f, 3.0f), -94.0471931331690, tol); CONTEND_DELTA( liquid_lnbesselif( 80.0f, 3.0f), -241.208142562073, tol); CONTEND_DELTA( liquid_lnbesselif( 140.0f, 3.0f), -498.439222461430, tol); #endif } // // AUTOTEST: Modified Bessel function of the first kind // void autotest_besselif() { float tol = 1e-3f; // check case when nu=0 CONTEND_DELTA(liquid_besselif(0.0f,0.0f), 1.0f, tol); CONTEND_DELTA(liquid_besselif(0.0f,0.1f), 1.00250156293410f, tol); CONTEND_DELTA(liquid_besselif(0.0f,0.2f), 1.01002502779515f, tol); CONTEND_DELTA(liquid_besselif(0.0f,0.5f), 1.06348337074132f, tol); CONTEND_DELTA(liquid_besselif(0.0f,1.0f), 1.26606587775201f, tol); CONTEND_DELTA(liquid_besselif(0.0f,2.0f), 2.27958530233607f, tol); CONTEND_DELTA(liquid_besselif(0.0f,3.0f), 4.88079258586503f, tol); // check case when nu=0.5 CONTEND_DELTA(liquid_besselif(0.5f,0.0f), 0.000000000000000, tol); CONTEND_DELTA(liquid_besselif(0.5f,0.1f), 0.252733984600132, tol); CONTEND_DELTA(liquid_besselif(0.5f,0.2f), 0.359208417583362, tol); CONTEND_DELTA(liquid_besselif(0.5f,0.5f), 0.587993086790417, tol); CONTEND_DELTA(liquid_besselif(0.5f,1.0f), 0.937674888245489, tol); CONTEND_DELTA(liquid_besselif(0.5f,2.0f), 2.046236863089057, tol); CONTEND_DELTA(liquid_besselif(0.5f,3.0f), 4.614822903407577, tol); // check case when nu=1.3 CONTEND_DELTA(liquid_besselif(1.3f,0.0f), 0.000000000000000, tol); CONTEND_DELTA(liquid_besselif(1.3f,0.1f), 0.017465030873157, tol); CONTEND_DELTA(liquid_besselif(1.3f,0.2f), 0.043144293848607, tol); CONTEND_DELTA(liquid_besselif(1.3f,0.5f), 0.145248507279042, tol); CONTEND_DELTA(liquid_besselif(1.3f,1.0f), 0.387392350983796, tol); CONTEND_DELTA(liquid_besselif(1.3f,2.0f), 1.290819215135879, tol); CONTEND_DELTA(liquid_besselif(1.3f,3.0f), 3.450680420553085, tol); } // // AUTOTEST: Modified Bessel function of the first kind // void autotest_besseli0f() { float tol = 1e-3f; CONTEND_DELTA(liquid_besseli0f(0.0f), 1.0f, tol); CONTEND_DELTA(liquid_besseli0f(0.1f), 1.00250156293410f, tol); CONTEND_DELTA(liquid_besseli0f(0.2f), 1.01002502779515f, tol); CONTEND_DELTA(liquid_besseli0f(0.5f), 1.06348337074132f, tol); CONTEND_DELTA(liquid_besseli0f(1.0f), 1.26606587775201f, tol); CONTEND_DELTA(liquid_besseli0f(2.0f), 2.27958530233607f, tol); CONTEND_DELTA(liquid_besseli0f(3.0f), 4.88079258586503f, tol); } // // AUTOTEST: Bessel function of the first kind // void autotest_besseljf() { float tol = 1e-3f; // check case when nu=0 CONTEND_DELTA(liquid_besseljf(0.0f,0.0f), 1.000000000000000, tol); CONTEND_DELTA(liquid_besseljf(0.0f,0.1f), 0.997501562066040, tol); CONTEND_DELTA(liquid_besseljf(0.0f,0.2f), 0.990024972239576, tol); CONTEND_DELTA(liquid_besseljf(0.0f,0.5f), 0.938469807240813, tol); CONTEND_DELTA(liquid_besseljf(0.0f,1.0f), 0.765197686557967, tol); CONTEND_DELTA(liquid_besseljf(0.0f,2.0f), 0.223890779141236, tol); CONTEND_DELTA(liquid_besseljf(0.0f,3.0f), -0.260051954901934, tol); CONTEND_DELTA(liquid_besseljf(0.0f,4.0f), -0.397149809863847, tol); CONTEND_DELTA(liquid_besseljf(0.0f,6.0f), 0.150645257250997, tol); CONTEND_DELTA(liquid_besseljf(0.0f,8.0f), 0.171650807137554, tol); // check case when nu=0.5 CONTEND_DELTA(liquid_besseljf(0.5f,0.0f), 0.000000000000000, tol); CONTEND_DELTA(liquid_besseljf(0.5f,0.1f), 0.251892940326001, tol); CONTEND_DELTA(liquid_besseljf(0.5f,0.2f), 0.354450744211402, tol); CONTEND_DELTA(liquid_besseljf(0.5f,0.5f), 0.540973789934529, tol); CONTEND_DELTA(liquid_besseljf(0.5f,1.0f), 0.671396707141804, tol); CONTEND_DELTA(liquid_besseljf(0.5f,2.0f), 0.513016136561828, tol); CONTEND_DELTA(liquid_besseljf(0.5f,3.0f), 0.065008182877376, tol); CONTEND_DELTA(liquid_besseljf(0.5f,4.0f), -0.301920513291637, tol); CONTEND_DELTA(liquid_besseljf(0.5f,6.0f), -0.091015409523068, tol); CONTEND_DELTA(liquid_besseljf(0.5f,8.0f), 0.279092808570990, tol); // check case when nu=1.7 CONTEND_DELTA(liquid_besseljf(1.7f,0.0f), 0.000000000000000, tol); CONTEND_DELTA(liquid_besseljf(1.7f,0.1f), 0.003971976455203, tol); CONTEND_DELTA(liquid_besseljf(1.7f,0.2f), 0.012869169735073, tol); CONTEND_DELTA(liquid_besseljf(1.7f,0.5f), 0.059920175825578, tol); CONTEND_DELTA(liquid_besseljf(1.7f,1.0f), 0.181417665056645, tol); CONTEND_DELTA(liquid_besseljf(1.7f,2.0f), 0.437811462130677, tol); CONTEND_DELTA(liquid_besseljf(1.7f,3.0f), 0.494432522734784, tol); CONTEND_DELTA(liquid_besseljf(1.7f,4.0f), 0.268439400467270, tol); CONTEND_DELTA(liquid_besseljf(1.7f,6.0f), -0.308175744215833, tol); CONTEND_DELTA(liquid_besseljf(1.7f,8.0f), -0.001102600927987, tol); } // // AUTOTEST: Bessel function of the first kind // void autotest_besselj0f() { float tol = 1e-3f; CONTEND_DELTA(liquid_besselj0f(0.0f), 1.0f, tol); CONTEND_DELTA(liquid_besselj0f(0.1f), 0.997501562066040f, tol); CONTEND_DELTA(liquid_besselj0f(0.2f), 0.990024972239576f, tol); CONTEND_DELTA(liquid_besselj0f(0.5f), 0.938469807240813f, tol); CONTEND_DELTA(liquid_besselj0f(1.0f), 0.765197686557967f, tol); CONTEND_DELTA(liquid_besselj0f(2.0f), 0.223890779141236f, tol); CONTEND_DELTA(liquid_besselj0f(2.5f), -0.048383776468199f, tol); CONTEND_DELTA(liquid_besselj0f(3.0f), -0.260051954901934f, tol); CONTEND_DELTA(liquid_besselj0f(3.5f), -0.380127739987263f, tol); CONTEND_DELTA(liquid_besselj0f(4.0f), -0.397149809863848f, tol); CONTEND_DELTA(liquid_besselj0f(4.5f), -0.320542508985121f, tol); } liquid-dsp-1.7.0/src/math/tests/math_complex_autotest.c000066400000000000000000000537661474751757600233000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // cexpf void autotest_cexpf() { float tol = 1e-3f; unsigned int n = 32; float complex z[32] = { 2.721502e+00+_Complex_I* -8.449366e-01, 2.264794e+00+_Complex_I* 2.387520e+00, 3.293179e+00+_Complex_I* -2.419589e+00, -1.318218e+00+_Complex_I* 2.145837e+00, -1.777802e+00+_Complex_I* 4.317598e-01, -1.808236e-01+_Complex_I* 1.030967e+00, -1.081724e+00+_Complex_I* 1.072073e-01, 3.617838e+00+_Complex_I* 3.329561e+00, 1.085694e+00+_Complex_I* 1.738376e+00, -2.867179e+00+_Complex_I* 8.557510e-01, -3.869596e+00+_Complex_I* -2.056906e+00, -2.902147e+00+_Complex_I* 2.433414e+00, -2.746567e+00+_Complex_I* -7.924449e-01, -2.961677e+00+_Complex_I* -3.129529e+00, 3.991396e+00+_Complex_I* -2.253945e+00, 1.034594e-01+_Complex_I* 2.712898e+00, 9.011188e-01+_Complex_I* -1.631747e+00, 1.100418e+00+_Complex_I* 1.942973e-01, -5.133605e-02+_Complex_I* 3.782200e+00, -1.659866e+00+_Complex_I* 2.170862e+00, 2.139597e-01+_Complex_I* 2.159311e+00, -7.981710e-01+_Complex_I* 3.132236e+00, -1.733482e+00+_Complex_I* -1.180333e+00, 2.461796e+00+_Complex_I* 3.352212e+00, -3.441958e+00+_Complex_I* 3.594616e+00, 2.079630e-01+_Complex_I* -3.311553e+00, -2.462289e+00+_Complex_I* 1.305815e+00, 3.121861e+00+_Complex_I* -1.208857e+00, -3.486629e+00+_Complex_I* -3.839816e+00, -3.383861e-01+_Complex_I* -3.495233e+00, -2.093760e+00+_Complex_I* 3.765073e+00, 3.217665e+00+_Complex_I* 2.807358e+00 }; float complex test[32] = { 1.009152e+01+_Complex_I* -1.137087e+01, -7.018747e+00+_Complex_I* 6.592232e+00, -2.020926e+01+_Complex_I* -1.779666e+01, -1.455457e-01+_Complex_I* 2.245718e-01, 1.534993e-01+_Complex_I* 7.072523e-02, 4.289666e-01+_Complex_I* 7.159020e-01, 3.370642e-01+_Complex_I* 3.627482e-02, -3.660068e+01+_Complex_I* -6.961947e+00, -4.939656e-01+_Complex_I* 2.920008e+00, 3.727975e-02+_Complex_I* 4.293222e-02, -9.748754e-03+_Complex_I* -1.844954e-02, -4.170312e-02+_Complex_I* 3.571317e-02, 4.503850e-02+_Complex_I* -4.567777e-02, -5.172835e-02+_Complex_I* -6.240385e-04, -3.416917e+01+_Complex_I* -4.198295e+01, -1.008646e+00+_Complex_I* 4.609940e-01, -1.499894e-01+_Complex_I* -2.457784e+00, 2.948871e+00+_Complex_I* 5.802783e-01, -7.616135e-01+_Complex_I* -5.677744e-01, -1.073852e-01+_Complex_I* 1.569425e-01, -6.875640e-01+_Complex_I* 1.030203e+00, -4.501318e-01+_Complex_I* 4.212064e-03, 6.724286e-02+_Complex_I* -1.633708e-01, -1.146673e+01+_Complex_I* -2.451473e+00, -2.877386e-02+_Complex_I* -1.400682e-02, -1.213428e+00+_Complex_I* 2.082440e-01, 2.232348e-02+_Complex_I* 8.226451e-02, 8.033771e+00+_Complex_I* -2.121861e+01, -2.344211e-02+_Complex_I* 1.967391e-02, -6.688032e-01+_Complex_I* 2.468952e-01, -1.000387e-01+_Complex_I* -7.194542e-02, -2.358796e+01+_Complex_I* 8.191224e+00 }; unsigned int i; for (i=0; i 0.20f) CONTEND_LESS_THAN(20*log10f(cabsf(buf_freq[i])), -40.0f); } #if 0 // DEBUG: export to file for testing FILE * fid = fopen("window_autotest.m","w"); fprintf(fid,"clear all; close all; nfft=%u; n=%u;\n", nfft, _n); fprintf(fid,"w=zeros(n,1); W=zeros(nfft,1);\n"); for (i=0; i<_n; i++) fprintf(fid,"w(%u) = %12.8f;\n", i+1, w[i]); for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: poly_fit 3rd order polynomial, critically sampled // void autotest_polyf_fit_q3n3() { unsigned int Q=2; // polynomial order unsigned int n=3; // input vector size float x[3] = {-1.0f, 0.0f, 1.0f}; float y[3] = { 1.0f, 0.0f, 1.0f}; float p[3]; float p_test[3] = {0.0f, 0.0f, 1.0f}; float tol = 1e-3f; unsigned int k=Q+1; polyf_fit(x,y,n, p,k); if (liquid_autotest_verbose) { unsigned int i; for (i=0; i<3; i++) printf("%3u : %12.8f > %12.8f\n", i, x[i], y[i]); for (i=0; i<3; i++) printf("p[%3u] = %12.8f\n", i, p[i]); } CONTEND_DELTA(p[0], p_test[0], tol); CONTEND_DELTA(p[1], p_test[1], tol); CONTEND_DELTA(p[2], p_test[2], tol); //CONTEND_DELTA(p[3], p_test[3], tol); } void autotest_polyf_lagrange_issue165() { // Inputs taken from issue#165 //unsigned int Q=2; // polynomial order unsigned int n=3; // input vector size float x[3] = {-1.0f, 0.0f, 1.0f}; float y[3] = {7.059105f, 24.998369f, 14.365907f}; float p[3]; float tol = 1e-3f; polyf_fit_lagrange(x,y,n,p); unsigned int j; for (j=0; j %12.8f\n", j, x[j], y[j]); for (j=0; j #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: polyf_findroots // // _p : polynomial, [size: _order+1 x 1] // _r : roots (sorted), [size: _order x 1] // _ordre : polynomial order void polyf_findroots_testbench(float * _p, float complex * _r, unsigned int _order, float _tol) { float complex roots[_order]; polyf_findroots(_p,_order+1,roots); unsigned int i; if (liquid_autotest_verbose) { printf("poly:\n"); for (i=0; i<=_order; i++) printf(" p[%3u] = %12.8f\n", i, _p[i]); printf("roots:\n"); for (i=0; i<_order; i++) { float e = cabsf(roots[i] - _r[i]); printf(" r[%3u] = %12.8f + %12.8fj (%12.8f + %12.8fj) %12.4e%s\n", i, crealf(roots[i]), cimagf(roots[i]), crealf( _r[i]), cimagf( _r[i]), e, e < _tol ? "" : " *"); } } // check to see if roots match within relative tolerance for (i=0; i<_order; i++) CONTEND_DELTA(roots[i], _r[i], _tol); } void autotest_polyf_findroots_real() { // basic roots, no complex values float p[6] = {6,11,-33,-33,11,6}; float complex r[5] = {-3, -1, -1./3., 0.5, 2.}; polyf_findroots_testbench(p, r, 5, 1e-6f); } void autotest_polyf_findroots_complex() { // complex roots float p[3] = {3,2,1}; float complex r[2] = {-1 + _Complex_I*M_SQRT2, -1 - _Complex_I*M_SQRT2}; polyf_findroots_testbench(p, r, 2, 1e-6f); } void autotest_polyf_findroots_mix() { // complex roots float p[7] = {-1,6,5,4,3,2,1}; float complex r[6] = { -1.544928106217380, -0.8438580445415772 + 1.251293921227189*_Complex_I, -0.8438580445415772 - 1.251293921227189*_Complex_I, 0.1464465720078399, 0.5430988116463471 + 1.282747429218130*_Complex_I, 0.5430988116463471 - 1.282747429218130*_Complex_I}; polyf_findroots_testbench(p, r, 6, 1e-6f); } void autotest_polyf_findroots_mix2() { // complex roots, longer polynomial float p[11] = { -2.1218292415142059326171875000e-02, 1.6006522178649902343750000000e+00, -1.2054302543401718139648437500e-01, -8.4453743696212768554687500000e-01, -1.1174567937850952148437500000e+00, 8.2108253240585327148437500000e-01, 2.2316795587539672851562500000e-01, 1.4220994710922241210937500000e+00, -8.4215706586837768554687500000e-01, 1.3681684434413909912109375000e-01, 1.0689756833016872406005859375e-02,}; float complex r[10] = { -17.67808709752869, -0.7645511425850682 + 0.4932343666704793*_Complex_I, -0.7645511425850682 - 0.4932343666704793*_Complex_I, -0.2764509491715267 + 1.058805768356938 *_Complex_I, -0.2764509491715267 - 1.058805768356938 *_Complex_I, 0.01327054605125156, 0.9170364272114475 + 0.3838341863217226*_Complex_I, 0.9170364272114475 - 0.3838341863217226*_Complex_I, 2.556937242081334 + 1.448576080447611 *_Complex_I, 2.556937242081334 - 1.448576080447611 *_Complex_I}; polyf_findroots_testbench(p, r, 10, 4e-6f); } // // AUTOTEST: polycf_findroots (random roots) // void xautotest_polycf_findroots_rand() { unsigned int n=5; float tol=1e-4f; float complex p[n]; float complex roots[n-1]; float complex p_hat[n]; unsigned int i; for (i=0; i #include "liquid.h" // Helper function to keep code base small void matrixf_inv_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations // time ~ _n ^ 2 *_num_iterations /= _n * _n; if (*_num_iterations < 1) *_num_iterations = 1; float x[_n*_n]; unsigned int i; for (i=0; i<_n*_n; i++) x[i] = randnf(); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { matrixf_inv(x,_n,_n); matrixf_inv(x,_n,_n); matrixf_inv(x,_n,_n); matrixf_inv(x,_n,_n); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define MATRIXF_INV_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { matrixf_inv_bench(_start, _finish, _num_iterations, N); } void benchmark_matrixf_inv_n2 MATRIXF_INV_BENCHMARK_API(2) void benchmark_matrixf_inv_n4 MATRIXF_INV_BENCHMARK_API(4) void benchmark_matrixf_inv_n8 MATRIXF_INV_BENCHMARK_API(8) void benchmark_matrixf_inv_n16 MATRIXF_INV_BENCHMARK_API(16) void benchmark_matrixf_inv_n32 MATRIXF_INV_BENCHMARK_API(32) void benchmark_matrixf_inv_n64 MATRIXF_INV_BENCHMARK_API(64) liquid-dsp-1.7.0/src/matrix/bench/matrixf_linsolve_benchmark.c000066400000000000000000000054251474751757600245440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" // Helper function to keep code base small void matrixf_linsolve_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // normalize number of iterations // time ~ _n ^ 2 *_num_iterations /= _n * _n; if (*_num_iterations < 1) *_num_iterations = 1; unsigned long int i; float A[_n*_n]; float b[_n]; float x[_n]; for (i=0; i<_n*_n; i++) A[i] = randnf(); for (i=0; i<_n; i++) b[i] = randnf(); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { matrixf_linsolve(A,_n,b,x,NULL); matrixf_linsolve(A,_n,b,x,NULL); matrixf_linsolve(A,_n,b,x,NULL); matrixf_linsolve(A,_n,b,x,NULL); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define MATRIXF_LINSOLVE_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { matrixf_linsolve_bench(_start, _finish, _num_iterations, N); } void benchmark_matrixf_linsolve_n2 MATRIXF_LINSOLVE_BENCHMARK_API(2) void benchmark_matrixf_linsolve_n4 MATRIXF_LINSOLVE_BENCHMARK_API(4) void benchmark_matrixf_linsolve_n8 MATRIXF_LINSOLVE_BENCHMARK_API(8) void benchmark_matrixf_linsolve_n16 MATRIXF_LINSOLVE_BENCHMARK_API(16) void benchmark_matrixf_linsolve_n32 MATRIXF_LINSOLVE_BENCHMARK_API(32) void benchmark_matrixf_linsolve_n64 MATRIXF_LINSOLVE_BENCHMARK_API(64) liquid-dsp-1.7.0/src/matrix/bench/matrixf_mul_benchmark.c000066400000000000000000000052351474751757600235050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void matrixf_mul_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations // time ~ _n ^ 2 *_num_iterations /= _n * _n; if (*_num_iterations < 1) *_num_iterations = 1; float a[_n*_n]; float b[_n*_n]; float c[_n*_n]; unsigned int i; for (i=0; i<_n*_n; i++) { a[i] = randnf(); b[i] = randnf(); } // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { matrixf_mul(a,_n,_n, b,_n,_n, c,_n,_n); matrixf_mul(a,_n,_n, b,_n,_n, c,_n,_n); matrixf_mul(a,_n,_n, b,_n,_n, c,_n,_n); matrixf_mul(a,_n,_n, b,_n,_n, c,_n,_n); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } #define MATRIXF_MUL_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { matrixf_mul_bench(_start, _finish, _num_iterations, N); } void benchmark_matrixf_mul_n2 MATRIXF_MUL_BENCHMARK_API(2) void benchmark_matrixf_mul_n4 MATRIXF_MUL_BENCHMARK_API(4) void benchmark_matrixf_mul_n8 MATRIXF_MUL_BENCHMARK_API(8) void benchmark_matrixf_mul_n16 MATRIXF_MUL_BENCHMARK_API(16) void benchmark_matrixf_mul_n32 MATRIXF_MUL_BENCHMARK_API(32) void benchmark_matrixf_mul_n64 MATRIXF_MUL_BENCHMARK_API(64) liquid-dsp-1.7.0/src/matrix/bench/smatrixf_mul_benchmark.c000066400000000000000000000064041474751757600236670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" // Helper function to keep code base small void smatrixf_mul_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _n) { // normalize number of iterations // time ~ _n ^ 3 *_num_iterations = 1 + *_num_iterations * 8192 / (_n * _n * _n + 1); unsigned long int i; // generate random matrices smatrixf a = smatrixf_create(_n, _n); smatrixf b = smatrixf_create(_n, _n); smatrixf c = smatrixf_create(_n, _n); // number of random non-zero entries unsigned int nnz = _n / 20 < 4 ? 4 : _n / 20; // initialize _a for (i=0; i #include #include int MATRIX(_print)(T * _X, unsigned int _R, unsigned int _C) { printf("matrix [%u x %u] : \n", _R, _C); unsigned int r,c; for (r=0; r<_R; r++) { for (c=0; c<_C; c++) { MATRIX_PRINT_ELEMENT(_X,_R,_C,r,c); } printf("\n"); } return LIQUID_OK; } // initialize square matrix to the identity matrix int MATRIX(_eye)(T * _x, unsigned int _n) { unsigned int r,c,k=0; for (r=0; r<_n; r++) { for (c=0; c<_n; c++) { _x[k++] = r==c ? 1. : 0.; } } return LIQUID_OK; } // initialize matrix to ones int MATRIX(_ones)(T * _x, unsigned int _r, unsigned int _c) { unsigned int k; for (k=0; k<_r*_c; k++) _x[k] = 1.; return LIQUID_OK; } // initialize matrix to zeros int MATRIX(_zeros)(T * _x, unsigned int _r, unsigned int _c) { unsigned int k; for (k=0; k<_r*_c; k++) _x[k] = 0.; return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/matrix.c000066400000000000000000000036261474751757600201620ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Floating-point matrix (double precision) // #include "liquid.internal.h" #define MATRIX(name) LIQUID_CONCAT(matrix, name) #define MATRIX_NAME "matrix" #define T double // general type #define TP double // primitive type #define T_COMPLEX 0 // is type complex? #define T_ABS(X) fabs(X) #define TP_ABS(X) fabs(X) #define MATRIX_PRINT_ELEMENT(X,R,C,r,c) \ printf("%12.8f", matrix_access(X,R,C,r,c)); // prototypes #include "matrix.base.proto.c" #include "matrix.cgsolve.proto.c" #include "matrix.chol.proto.c" #include "matrix.gramschmidt.proto.c" #include "matrix.inv.proto.c" #include "matrix.linsolve.proto.c" #include "matrix.ludecomp.proto.c" #include "matrix.qrdecomp.proto.c" #include "matrix.math.proto.c" liquid-dsp-1.7.0/src/matrix/src/matrix.cgsolve.proto.c000066400000000000000000000130351474751757600227600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Solve linear system of equations using conjugate gradient method // // References: // [Schewchuk:1994] Jonathon Richard Shewchuk, "An Introduction to // the Conjugate Gradient Method Without the Agonizing Pain," // Manuscript, August, 1994. // #include #include #include "liquid.internal.h" #define DEBUG_CGSOLVE 0 // solve linear system of equations using conjugate gradient method // _A : symmetric positive definite matrix [size: _n x _n] // _n : system dimension // _b : equality [size: _n x 1] // _x : solution estimate [size: _n x 1] // _opts : options (ignored for now) int MATRIX(_cgsolve)(T * _A, unsigned int _n, T * _b, T * _x, void * _opts) { // validate input if (_n == 0) return liquid_error(LIQUID_EICONFIG,"matrix_cgsolve(), system dimension cannot be zero"); // options unsigned int max_iterations = 4*_n; // maximum number of iterations double tol = 1e-6; // error tolerance unsigned int j; // TODO : check options // 1. set initial _x0 // 2. max number of iterations // 3. residual tolerance // allocate memory for arrays T x0[_n], x1[_n]; // iterative vector x (solution estimate) T d0[_n], d1[_n]; // iterative vector d T r0[_n], r1[_n]; // iterative vector r (step direction) T q[_n]; // A * d0 T Ax1[_n]; // A * x1 // scalars T delta_init; // b^T * b0 T delta0; // r0^T * r0 T delta1; // r1^T * r1 T gamma; // d0^T * q T alpha; T beta; double res; // residual double res_opt=0.0; // residual of best solution // initialize x0 to {0, 0, ... 0} for (j=0; j<_n; j++) x0[j] = 0.0; // d0 = b - A*x0 (assume x0 = {0, 0, 0, ...0}) for (j=0; j<_n; j++) d0[j] = _b[j]; // r0 = d0 memmove(r0, d0, _n*sizeof(T)); // delta_init = b^T * b MATRIX(_transpose_mul)(_b, _n, 1, &delta_init); // delta0 = r0^T * r0 MATRIX(_transpose_mul)(r0, _n, 1, &delta0); // save best solution memmove(_x, x0, _n*sizeof(T)); unsigned int i=0; // iteration counter while ( (i < max_iterations) && (creal(delta0) > tol*tol*creal(delta_init)) ) { #if DEBUG_CGSOLVE printf("*********** %4u / %4u (max) **************\n", i, max_iterations); printf(" comparing %12.4e > %12.4e\n", creal(delta0), tol*tol*creal(delta_init)); #endif // q = A*d0 MATRIX(_mul)(_A, _n, _n, d0, _n, 1, q, _n, 1); // gamma = d0^T * q gamma = 0.0; for (j=0; j<_n; j++) { T prod = conj(d0[j]) * q[j]; gamma += prod; } // step size: alpha = (r0^T * r0) / (d0^T * A * d0) // = delta0 / gamma alpha = delta0 / gamma; #if DEBUG_CGSOLVE printf(" alpha = %12.8f\n", crealf(alpha)); printf(" delta0 = %12.8f\n", crealf(delta0)); #endif // update x for (j=0; j<_n; j++) x1[j] = x0[j] + alpha*d0[j]; #if DEBUG_CGSOLVE printf(" x:\n"); MATRIX(_print)(x1, _n, 1); #endif // update r if ( ((i+1)%50) == 0) { // peridically re-compute: r = b - A*x1 MATRIX(_mul)(_A, _n, _n, x1, _n, 1, Ax1, _n, 1); for (j=0; j<_n; j++) r1[j] = _b[j] - Ax1[j]; } else { for (j=0; j<_n; j++) r1[j] = r0[j] - alpha*q[j]; } // delta1 = r1^T * r1 MATRIX(_transpose_mul)(r1, _n, 1, &delta1); // update beta beta = delta1 / delta0; // d1 = r + beta*d0 for (j=0; j<_n; j++) d1[j] = r1[j] + beta*d0[j]; // compute residual res = sqrt( T_ABS(delta1) / T_ABS(delta_init) ); if (i==0 || res < res_opt) { // save best solution res_opt = res; memmove(_x, x1, _n*sizeof(T)); } #if DEBUG_CGSOLVE printf(" res = %12.4e\n", res); #endif // copy old x, d, r, delta memmove(x0, x1, _n*sizeof(T)); memmove(d0, d1, _n*sizeof(T)); memmove(r0, r1, _n*sizeof(T)); delta0 = delta1; // increment counter i++; } return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/matrix.chol.proto.c000066400000000000000000000064731474751757600222530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Matrix Cholesky decomposition method definitions // #include #include "liquid.internal.h" #define DEBUG_MATRIX_CHOL 0 // Compute Cholesky decomposition of a symmetric/Hermitian positive- // definite matrix as A = L * L^T // _a : input square matrix [size: _n x _n] // _n : input matrix dimension // _l : output lower-triangular matrix int MATRIX(_chol)(T * _a, unsigned int _n, T * _l) { // reset L unsigned int i; for (i=0; i<_n*_n; i++) _l[i] = 0.0; unsigned int j; unsigned int k; T a_jj; T l_jj; T l_ik; T l_jk; TP t0; T t1; for (j=0; j<_n; j++) { // assert that a_jj is real, positive a_jj = matrix_access(_a,_n,_n,j,j); if ( creal(a_jj) < 0.0 ) return liquid_error(LIQUID_EICONFIG,"matrix_chol(), matrix is not positive definite (real{A[%u,%u]} = %12.4e < 0)",j,j,creal(a_jj)); #if T_COMPLEX if ( fabs(cimag(a_jj)) > 0.0 ) return liquid_error(LIQUID_EICONFIG,"matrix_chol(), matrix is not positive definite (|imag{A[%u,%u]}| = %12.4e > 0)",j,j,fabs(cimag(a_jj))); #endif // compute l_jj and store it in output matrix t0 = 0.0; for (k=0; k t0 if ( creal(a_jj) < t0 ) return liquid_error(LIQUID_EICONFIG,"matrix_chol(), matrix is not positive definite (real{A[%u,%u]} = %12.4e < %12.4e)",j,j,creal(a_jj),t0); l_jj = sqrt( a_jj - t0 ); matrix_access(_l,_n,_n,j,j) = l_jj; for (i=j+1; i<_n; i++) { t1 = matrix_access(_a,_n,_n,i,j); for (k=0; k #include "liquid.internal.h" #define DEBUG_MATRIX_GRAMSCHMIDT 0 // compute projection of _u onto _v, store in _e int MATRIX(_proj)(T * _u, T * _v, unsigned int _n, T * _e) { // compute dot-product between _u and _v unsigned int i; T uv = 0.; T uu = 0.; for (i=0; i<_n; i++) { uv += _u[i] * _v[i]; uu += _u[i] * _u[i]; } // TODO : check magnitude of _uu T g = uv / uu; for (i=0; i<_n; i++) _e[i] = _u[i] * g; return LIQUID_OK; } // Orthnormalization using the Gram-Schmidt algorithm int MATRIX(_gramschmidt)(T * _x, unsigned int _rx, unsigned int _cx, T * _v) { // validate input if (_rx == 0 || _cx == 0) return liquid_error(LIQUID_EICONFIG,"matrix_gramschmidt(), input matrix cannot have zero-length dimensions"); unsigned int i; unsigned int j; unsigned int k; // copy _x to _u memmove(_v, _x, _rx * _cx * sizeof(T)); unsigned int n = _rx; // dimensionality of each vector T proj_ij[n]; for (j=0; j<_cx; j++) { for (i=0; i v_max || r_hat==r) { r_opt = r_hat; v_max = v; } } // if the maximum is zero, matrix is singular if (v_max == 0.0f) return liquid_error(LIQUID_EICONFIG,"matrix_gjelim(), matrix singular to machine precision"); // if row does not match column (e.g. maximum value does not // lie on the diagonal) swap the rows if (r != r_opt) { MATRIX(_swaprows)(_X,_XR,_XC,r,r_opt); } // pivot on the diagonal element MATRIX(_pivot)(_X,_XR,_XC,r,r); } // scale by diagonal T g; for (r=0; r<_XR; r++) { g = 1 / matrix_access(_X,_XR,_XC,r,r); for (c=0; c<_XC; c++) matrix_access(_X,_XR,_XC,r,c) *= g; } return LIQUID_OK; } // pivot on element _r, _c int MATRIX(_pivot)(T * _X, unsigned int _XR, unsigned int _XC, unsigned int _r, unsigned int _c) { T v = matrix_access(_X,_XR,_XC,_r,_c); if (v==0) return liquid_error(LIQUID_EICONFIG,"matrix_pivot(), pivoting on zero"); unsigned int r,c; // pivot using back-substitution T g; // multiplier for (r=0; r<_XR; r++) { // skip over pivot row if (r == _r) continue; // compute multiplier g = matrix_access(_X,_XR,_XC,r,_c) / v; // back-substitution for (c=0; c<_XC; c++) { matrix_access(_X,_XR,_XC,r,c) = g*matrix_access(_X,_XR,_XC,_r,c) - matrix_access(_X,_XR,_XC, r,c); } } return LIQUID_OK; } int MATRIX(_swaprows)(T * _X, unsigned int _XR, unsigned int _XC, unsigned int _r1, unsigned int _r2) { if (_r1 == _r2) return LIQUID_OK; unsigned int c; T v_tmp; for (c=0; c<_XC; c++) { v_tmp = matrix_access(_X,_XR,_XC,_r1,c); matrix_access(_X,_XR,_XC,_r1,c) = matrix_access(_X,_XR,_XC,_r2,c); matrix_access(_X,_XR,_XC,_r2,c) = v_tmp; } return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/matrix.linsolve.proto.c000066400000000000000000000053001474751757600231450ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Solve linear system of equations // #include #include "liquid.internal.h" // solve linear system of n equations: Ax = b // _A : system matrix [size: _n x _n] // _n : system size // _b : equality vector [size: _n x 1] // _x : solution vector [size: _n x 1] // _opts : options (ignored for now) int MATRIX(_linsolve)(T * _A, unsigned int _n, T * _b, T * _x, void * _opts) { #if 0 T A_inv[_n*_n]; memmove(A_inv, _A, _n*_n*sizeof(T)); MATRIX(_inv)(A_inv,_n,_n); MATRIX(_mul)(A_inv, _n, _n, _b, _n, 1, _x, _n, 1); #else unsigned int r; unsigned int c; // compute augmented matrix M [size: _n x _n+1] as // T: // A11 A12 A13 ... A1n b1 // A21 A22 A23 ... A2n b2 // A31 A32 A33 ... A3n b3 // ... // An1 An2 An3 ... Ann bn T M[_n*_n + _n]; // allocate array unsigned int m=0; // output matrix index counter unsigned int a=0; // input matrix index counter for (r=0; r<_n; r++) { for (c=0; c<_n; c++) M[m++] = _A[a++]; M[m++] = _b[r]; } // run Gauss-Jordan elimination on M // T: // 1 0 0 ... 0 x1 // 0 1 0 ... 0 x2 // 0 0 1 ... 0 x3 // ... // 0 0 0 ... 1 xn MATRIX(_gjelim)(M, _n, _n+1); // copy result from right-most column of M for (r=0; r<_n; r++) _x[r] = M[(_n+1)*(r+1)-1]; #endif return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/matrix.ludecomp.proto.c000066400000000000000000000105721474751757600231310ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Matrix L/U decomposition method definitions // #include "liquid.internal.h" // L/U/P decomposition, Crout's method int MATRIX(_ludecomp_crout)(T * _x, unsigned int _rx, unsigned int _cx, T * _l, T * _u, T * _p) { // validate input if (_rx != _cx) return liquid_error(LIQUID_EICONFIG,"matrix_ludecomp_crout(), input matrix not square"); unsigned int n = _rx; // reset L, U unsigned int i; for (i=0; i #include #include // add elements of two matrices // _X : 1st input matrix [size: _R x _C] // _Y : 2nd input matrix [size: _R x _C] // _Z : output matrix [size: _R x _C] // _R : number of rows // _C : number of columns int MATRIX(_add)(T * _X, T * _Y, T * _Z, unsigned int _R, unsigned int _C) { unsigned int i; for (i=0; i<(_R*_C); i++) _Z[i] = _X[i] + _Y[i]; return LIQUID_OK; } // subtract elements of two matrices // _X : 1st input matrix [size: _R x _C] // _Y : 2nd input matrix [size: _R x _C] // _Z : output matrix [size: _R x _C] // _R : number of rows // _C : number of columns int MATRIX(_sub)(T * _X, T * _Y, T * _Z, unsigned int _R, unsigned int _C) { unsigned int i; for (i=0; i<(_R*_C); i++) _Z[i] = _X[i] - _Y[i]; return LIQUID_OK; } // point-wise multiplication // _X : 1st input matrix [size: _R x _C] // _Y : 2nd input matrix [size: _R x _C] // _Z : output matrix [size: _R x _C] // _R : number of rows // _C : number of columns int MATRIX(_pmul)(T * _X, T * _Y, T * _Z, unsigned int _R, unsigned int _C) { unsigned int i; for (i=0; i<(_R*_C); i++) _Z[i] = _X[i] * _Y[i]; return LIQUID_OK; } // point-wise division // _X : 1st input matrix [size: _R x _C] // _Y : 2nd input matrix [size: _R x _C] // _Z : output matrix [size: _R x _C] // _R : number of rows // _C : number of columns int MATRIX(_pdiv)(T * _X, T * _Y, T * _Z, unsigned int _R, unsigned int _C) { unsigned int i; for (i=0; i<(_R*_C); i++) _Z[i] = _X[i] / _Y[i]; return LIQUID_OK; } // multiply two matrices together int MATRIX(_mul)(T * _X, unsigned int _XR, unsigned int _XC, T * _Y, unsigned int _YR, unsigned int _YC, T * _Z, unsigned int _ZR, unsigned int _ZC) { // ensure lengths are valid if (_ZR != _XR || _ZC != _YC || _XC != _YR ) return liquid_error(LIQUID_EIRANGE,"matrix_mul(), invalid dimensions"); unsigned int r, c, i; for (r=0; r<_ZR; r++) { for (c=0; c<_ZC; c++) { // z(i,j) = dotprod( x(i,:), y(:,j) ) T sum=0.0f; for (i=0; i<_XC; i++) { sum += matrix_access(_X,_XR,_XC,r,i) * matrix_access(_Y,_YR,_YC,i,c); } matrix_access(_Z,_ZR,_ZC,r,c) = sum; #ifdef DEBUG printf("z(%u,%u) = ", r, c); MATRIX_PRINT_ELEMENT(_Z,_ZR,_ZC,r,c); printf("\n"); #endif } } return LIQUID_OK; } // augment matrices x and y: // z = [x | y] int MATRIX(_aug)(T * _x, unsigned int _rx, unsigned int _cx, T * _y, unsigned int _ry, unsigned int _cy, T * _z, unsigned int _rz, unsigned int _cz) { // ensure lengths are valid if (_rz != _rx || _rz != _ry || _rx != _ry || _cz != _cx + _cy) return liquid_error(LIQUID_EIRANGE,"matrix_aug(), invalid dimensions"); // TODO: improve speed with memmove unsigned int r, c, n; for (r=0; r<_rz; r++) { n=0; for (c=0; c<_cx; c++) matrix_access(_z,_rz,_cz,r,n++) = matrix_access(_x,_rx,_cx,r,c); for (c=0; c<_cy; c++) matrix_access(_z,_rz,_cz,r,n++) = matrix_access(_y,_ry,_cy,r,c); } return LIQUID_OK; } // solve set of linear equations int MATRIX(_div)(T * _X, T * _Y, T * _Z, unsigned int _n) { // compute inv(_Y) T Y_inv[_n*_n]; memmove(Y_inv, _Y, _n*_n*sizeof(T)); MATRIX(_inv)(Y_inv,_n,_n); // _Z = _X * inv(_Y) return MATRIX(_mul)(_X, _n, _n, Y_inv, _n, _n, _Z, _n, _n); } // matrix determinant (2 x 2) T MATRIX(_det2x2)(T * _X, unsigned int _r, unsigned int _c) { // validate input if (_r != 2 || _c != 2) return liquid_error(LIQUID_EIRANGE,"matrix_det2x2(), invalid dimensions"); return _X[0]*_X[3] - _X[1]*_X[2]; } // matrix determinant (n x n) T MATRIX(_det)(T * _X, unsigned int _r, unsigned int _c) { // validate input if (_r != _c) return liquid_error(LIQUID_EIRANGE,"matrix_det(), matrix must be square"); unsigned int n = _r; if (n==2) return MATRIX(_det2x2)(_X,2,2); // compute L/U decomposition (Doolittle's method) T L[n*n]; // lower T U[n*n]; // upper T P[n*n]; // permutation MATRIX(_ludecomp_doolittle)(_X,n,n,L,U,P); // evaluate along the diagonal of U T det = 1.0; unsigned int i; for (i=0; i #include "liquid.internal.h" #define DEBUG_MATRIX_QRDECOMP 1 // Q/R decomposition using the Gram-Schmidt algorithm int MATRIX(_qrdecomp_gramschmidt)(T * _x, unsigned int _m, unsigned int _n, T * _q, T * _r) { // validate input if (_m != _n) return liquid_error(LIQUID_EIRANGE,"matrix_qrdecomp_gramschmidt(), input matrix not square"); unsigned int n = _m; unsigned int i,j,k; // generate and initialize matrices T e[n*n]; // normalized... for (i=0; i _value) break; } // return i; } liquid-dsp-1.7.0/src/matrix/src/smatrix.proto.c000066400000000000000000000436131474751757600215070ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sparse matrices // // sparse matrix structure // example: the following floating-point sparse matrix is represented // with the corresponding values: // [ 0 0 0 0 0 ] // [ 0 2.3 0 0 0 ] // [ 0 0 0 0 1.2 ] // [ 0 0 0 0 0 ] // [ 0 3.4 0 4.4 0 ] // [ 0 0 0 0 0 ] // // M (rows) : 6 // N (cols) : 5 // mlist : { {}, {1}, {4}, {}, {1,3}, {} } // nlist : { {}, {1,4}, {}, {4}, {2} } // mvals : { {}, {2.3}, {1.2}, {}, {3.4,4.4}, {} } // nvals : { {}, {2.3, 3.4}, {}, {4.4}, {1.2} } // num_mlist : { 0, 1, 1, 0, 2, 0 } // num_nlist : { 0, 2, 0, 1, 1 } // max_num_mlist : 2 // max_num_nlist : 2 // // NOTE: while this particular example does not show a particular // improvement in memory use, such a case can be made for // extremely large matrices which only have a few non-zero // entries. // struct SMATRIX(_s) { unsigned int M; // number of rows unsigned int N; // number of columns unsigned short int ** mlist; // list of non-zero col indices in each row unsigned short int ** nlist; // list of non-zero row indices in each col T ** mvals; // list of non-zero values in each row T ** nvals; // list of non-zero values in each col unsigned int * num_mlist; // weight of each row, m unsigned int * num_nlist; // weight of each row, n unsigned int max_num_mlist; // maximum of num_mlist unsigned int max_num_nlist; // maximum of num_nlist }; int SMATRIX(_reset_max_mlist)(SMATRIX() _q); int SMATRIX(_reset_max_nlist)(SMATRIX() _q); // create _m x _n matrix, initialized with zeros SMATRIX() SMATRIX(_create)(unsigned int _m, unsigned int _n) { if (_m==0 || _n==0) return liquid_error_config("smatrix%s_create(), dimensions must be greater than zero",EXTENSION); // create object and allocate memory SMATRIX() q = (SMATRIX()) malloc(sizeof(struct SMATRIX(_s))); q->M = _m; q->N = _n; unsigned int i; unsigned int j; // initialize size of each pointer list q->num_mlist = (unsigned int*)malloc( q->M*sizeof(unsigned int) ); q->num_nlist = (unsigned int*)malloc( q->N*sizeof(unsigned int) ); for (i=0; iM; i++) q->num_mlist[i] = 0; for (j=0; jN; j++) q->num_nlist[j] = 0; // initialize lists q->mlist = (unsigned short int **) malloc( q->M*sizeof(unsigned short int *) ); q->nlist = (unsigned short int **) malloc( q->N*sizeof(unsigned short int *) ); for (i=0; iM; i++) q->mlist[i] = (unsigned short int *) malloc( q->num_mlist[i]*sizeof(unsigned short int) ); for (j=0; jN; j++) q->nlist[j] = (unsigned short int *) malloc( q->num_nlist[j]*sizeof(unsigned short int) ); // initialize values q->mvals = (T **) malloc( q->M*sizeof(T*) ); q->nvals = (T **) malloc( q->N*sizeof(T*) ); for (i=0; iM; i++) q->mvals[i] = (T *) malloc( q->num_mlist[i]*sizeof(T) ); for (j=0; jN; j++) q->nvals[j] = (T *) malloc( q->num_nlist[j]*sizeof(T) ); // set maximum list size q->max_num_mlist = 0; q->max_num_nlist = 0; // return main object return q; } // create _m x _n matrix, initialized on array SMATRIX() SMATRIX(_create_array)(T * _v, unsigned int _m, unsigned int _n) { // create object and allocate memory SMATRIX() q = SMATRIX(_create)(_m,_n); // initialize elements unsigned int i; unsigned int j; for (i=0; i<_m; i++) { for (j=0; j<_n; j++) { if (_v[i*_n + j] != 0) SMATRIX(_set)(q,i,j,_v[i*_n + j]); } } // return main object return q; } // destroy object int SMATRIX(_destroy)(SMATRIX() _q) { unsigned int i; unsigned int j; // free internal memory free(_q->num_mlist); free(_q->num_nlist); // free lists for (i=0; i<_q->M; i++) free(_q->mlist[i]); for (j=0; j<_q->N; j++) free(_q->nlist[j]); free(_q->mlist); free(_q->nlist); // free values for (i=0; i<_q->M; i++) free(_q->mvals[i]); for (j=0; j<_q->N; j++) free(_q->nvals[j]); free(_q->mvals); free(_q->nvals); // free main object memory free(_q); return LIQUID_OK; } // print compact form int SMATRIX(_print)(SMATRIX() _q) { printf("dims : %u %u\n", _q->M, _q->N); printf("max : %u %u\n", _q->max_num_mlist, _q->max_num_nlist); unsigned int i; unsigned int j; printf("rows :"); for (i=0; i<_q->M; i++) printf(" %u", _q->num_mlist[i]); printf("\n"); printf("cols :"); for (j=0; j<_q->N; j++) printf(" %u", _q->num_nlist[j]); printf("\n"); // print mlist printf("row indices:\n"); for (i=0; i<_q->M; i++) { if (_q->num_mlist[i] == 0) continue; printf(" %3u :", i); for (j=0; j<_q->num_mlist[i]; j++) printf(" %u", _q->mlist[i][j]); printf("\n"); } // print nlist printf("column indices:\n"); for (j=0; j<_q->N; j++) { if (_q->num_nlist[j] == 0) continue; printf(" %3u :", j); for (i=0; i<_q->num_nlist[j]; i++) printf(" %u", _q->nlist[j][i]); printf("\n"); } #if SMATRIX_FLOAT // print mvals printf("row values:\n"); for (i=0; i<_q->M; i++) { printf(" %3u :", i); for (j=0; j<_q->num_mlist[i]; j++) printf(" %6.2f", _q->mvals[i][j]); printf("\n"); } // print nvals printf("column values:\n"); for (j=0; j<_q->N; j++) { printf(" %3u :", j); for (i=0; i<_q->num_nlist[j]; i++) printf(" %6.2f", _q->nvals[j][i]); printf("\n"); } #endif return LIQUID_OK; } // print expanded form int SMATRIX(_print_expanded)(SMATRIX() _q) { unsigned int i; unsigned int j; unsigned int t; // print in expanded 'regular' form for (i=0; i<_q->M; i++) { // reset counter t = 0; for (j=0; j<_q->N; j++) { if (t == _q->num_mlist[i]) { PRINTVAL_ZERO(); } else if (_q->mlist[i][t] == j) { PRINTVAL(_q->mvals[i][t]); t++; } else { PRINTVAL_ZERO(); } } printf("\n"); } return LIQUID_OK; } // get matrix dimensions int SMATRIX(_size)(SMATRIX() _q, unsigned int * _m, unsigned int * _n) { *_m = _q->M; *_n = _q->N; return LIQUID_OK; } // zero all values, retaining memory allocation int SMATRIX(_clear)(SMATRIX() _q) { unsigned int i; unsigned int j; // clear row entries for (i=0; i<_q->M; i++) { for (j=0; j<_q->num_mlist[i]; j++) { _q->mvals[i][j] = 0; } } // clear column entries for (j=0; j<_q->N; j++) { for (i=0; i<_q->num_nlist[j]; i++) { _q->nvals[j][i] = 0; } } return LIQUID_OK; } // zero all values, clearing memory int SMATRIX(_reset)(SMATRIX() _q) { unsigned int i; unsigned int j; for (i=0; i<_q->M; i++) _q->num_mlist[i] = 0; for (j=0; j<_q->N; j++) _q->num_nlist[j] = 0; _q->max_num_mlist = 0; _q->max_num_nlist = 0; return LIQUID_OK; } // determine if element is set int SMATRIX(_isset)(SMATRIX() _q, unsigned int _m, unsigned int _n) { // validate input if (_m >= _q->M || _n >= _q->N) { liquid_error(LIQUID_EIRANGE,"SMATRIX(_isset)(%u,%u), index exceeds matrix dimension (%u,%u)",_m, _n, _q->M, _q->N); return 0; } unsigned int j; for (j=0; j<_q->num_mlist[_m]; j++) { if (_q->mlist[_m][j] == _n) return 1; } return 0; } // insert element at index int SMATRIX(_insert)(SMATRIX() _q, unsigned int _m, unsigned int _n, T _v) { // validate input if (_m >= _q->M || _n >= _q->N) return liquid_error(LIQUID_EIRANGE,"SMATRIX(_insert)(%u,%u), index exceeds matrix dimension (%u,%u)",_m, _n, _q->M, _q->N); // check to see if element is already set if (SMATRIX(_isset)(_q,_m,_n)) { // simply set the value and return printf("SMATRIX(_insert), value already set...\n"); return SMATRIX(_set)(_q, _m, _n, _v); } // increment list sizes _q->num_mlist[_m]++; _q->num_nlist[_n]++; // reallocate indices lists at this index _q->mlist[_m] = (unsigned short int*) realloc(_q->mlist[_m], _q->num_mlist[_m]*sizeof(unsigned short int)); _q->nlist[_n] = (unsigned short int*) realloc(_q->nlist[_n], _q->num_nlist[_n]*sizeof(unsigned short int)); // reallocate values lists at this index _q->mvals[_m] = (T*) realloc(_q->mvals[_m], _q->num_mlist[_m]*sizeof(T)); _q->nvals[_n] = (T*) realloc(_q->nvals[_n], _q->num_nlist[_n]*sizeof(T)); // find index within list to insert new value unsigned int mindex = smatrix_indexsearch(_q->mlist[_m], _q->num_mlist[_m]-1, _n); unsigned int nindex = smatrix_indexsearch(_q->nlist[_n], _q->num_nlist[_n]-1, _m); //printf("inserting value (n=%3u) at m=%3u, index=%3u\n", _n, _m, mindex); //printf("inserting value (m=%3u) at n=%3u, index=%3u\n", _m, _n, nindex); // insert indices to appropriate place in list memmove(&_q->mlist[_m][mindex+1], &_q->mlist[_m][mindex], (_q->num_mlist[_m]-mindex-1)*sizeof(unsigned short int)); memmove(&_q->nlist[_n][nindex+1], &_q->nlist[_n][nindex], (_q->num_nlist[_n]-nindex-1)*sizeof(unsigned short int)); _q->mlist[_m][mindex] = _n; _q->nlist[_n][nindex] = _m; // insert values to appropriate place in list memmove(&_q->mvals[_m][mindex+1], &_q->mvals[_m][mindex], (_q->num_mlist[_m]-mindex-1)*sizeof(T)); memmove(&_q->nvals[_n][nindex+1], &_q->nvals[_n][nindex], (_q->num_nlist[_n]-nindex-1)*sizeof(T)); _q->mvals[_m][mindex] = _v; _q->nvals[_n][nindex] = _v; // update maximum if (_q->num_mlist[_m] > _q->max_num_mlist) _q->max_num_mlist = _q->num_mlist[_m]; if (_q->num_nlist[_n] > _q->max_num_nlist) _q->max_num_nlist = _q->num_nlist[_n]; return LIQUID_OK; } // delete element at index int SMATRIX(_delete)(SMATRIX() _q, unsigned int _m, unsigned int _n) { // validate input if (_m > _q->M || _n > _q->N) return liquid_error(LIQUID_EIRANGE,"SMATRIX(_delete)(%u,%u), index exceeds matrix dimension (%u,%u)",_m, _n, _q->M, _q->N); // check to see if element is already not set if (!SMATRIX(_isset)(_q,_m,_n)) return LIQUID_OK; // remove value from mlist (shift left) unsigned int i; unsigned int j; unsigned int t=0; for (j=0; j<_q->num_mlist[_m]; j++) { if (_q->mlist[_m][j] == _n) t = j; } for (j=t; j<_q->num_mlist[_m]-1; j++) _q->mlist[_m][j] = _q->mlist[_m][j+1]; // remove value from nlist (shift left) t = 0; for (i=0; i<_q->num_nlist[_n]; i++) { if (_q->nlist[_n][i] == _m) t = i; } for (i=t; i<_q->num_nlist[_n]-1; i++) _q->nlist[_n][i] = _q->nlist[_n][i+1]; // reduce sizes _q->num_mlist[_m]--; _q->num_nlist[_n]--; // reallocate _q->mlist[_m] = (unsigned short int*) realloc(_q->mlist[_m], _q->num_mlist[_m]*sizeof(unsigned short int)); _q->nlist[_n] = (unsigned short int*) realloc(_q->nlist[_n], _q->num_nlist[_n]*sizeof(unsigned short int)); // reset maxima if (_q->max_num_mlist == _q->num_mlist[_m]+1) SMATRIX(_reset_max_mlist)(_q); if (_q->max_num_nlist == _q->num_nlist[_n]+1) SMATRIX(_reset_max_nlist)(_q); return LIQUID_OK; } // set element value at index int SMATRIX(_set)(SMATRIX() _q, unsigned int _m, unsigned int _n, T _v) { // validate input if (_m >= _q->M || _n >= _q->N) return liquid_error(LIQUID_EIRANGE,"SMATRIX(_set)(%u,%u), index exceeds matrix dimension (%u,%u)",_m, _n, _q->M, _q->N); // insert new element if not already allocated if (!SMATRIX(_isset)(_q,_m,_n)) return SMATRIX(_insert)(_q,_m,_n,_v); // set value unsigned int i; unsigned int j; for (j=0; j<_q->num_mlist[_m]; j++) { if (_q->mlist[_m][j] == _n) _q->mvals[_m][j] = _v; } for (i=0; i<_q->num_nlist[_n]; i++) { if (_q->nlist[_n][i] == _m) _q->nvals[_n][i] = _v; } return LIQUID_OK; } // get element value at index (return zero if not set) T SMATRIX(_get)(SMATRIX() _q, unsigned int _m, unsigned int _n) { // validate input if (_m >= _q->M || _n >= _q->N) { liquid_error(LIQUID_EIRANGE,"SMATRIX(_get)(%u,%u), index exceeds matrix dimension (%u,%u)",_m, _n, _q->M, _q->N); return 0; } unsigned int j; for (j=0; j<_q->num_mlist[_m]; j++) { if (_q->mlist[_m][j] == _n) return _q->mvals[_m][j]; } return 0; } // initialize to identity matrix int SMATRIX(_eye)(SMATRIX() _q) { // reset all elements SMATRIX(_reset)(_q); // set values along diagonal unsigned int i; unsigned int dmin = _q->M < _q->N ? _q->M : _q->N; for (i=0; iM != _a->M || _c->N != _b->N || _a->N != _b->M) return liquid_error(LIQUID_EIRANGE,"SMATRIX(_mul)(), invalid dimensions"); // clear output matrix (retain memory allocation) SMATRIX(_clear)(_c); unsigned int r; // output row unsigned int c; // output column unsigned int i; unsigned int j; for (r=0; r<_c->M; r++) { // find number of non-zero entries in row 'r' of matrix '_a' unsigned int nnz_a_row = _a->num_mlist[r]; // if this number is zero, there will not be any non-zero // entries in the corresponding row of the output matrix '_c' if (nnz_a_row == 0) continue; for (c=0; c<_c->N; c++) { // find number of non-zero entries in column 'c' of matrix '_b' unsigned int nnz_b_col = _b->num_nlist[c]; T p = 0; int set_value = 0; // find common elements between non-zero elements in // row 'r' of matrix '_a' and col 'c' of matrix '_b' i=0; // reset array index for rows of '_a' j=0; // reset array index for cols of '_b' while (i < nnz_a_row && j < nnz_b_col) { // unsigned int ca = _a->mlist[r][i]; unsigned int rb = _b->nlist[c][j]; if (ca == rb) { // match found between _a[r,ca] and _b[rb,c] p += _a->mvals[r][i] * _b->nvals[c][j]; set_value = 1; i++; j++; } else if (ca < rb) i++; // increment index for '_a' else j++; // increment index for '_b' } // set value if any multiplications have been made if (set_value) { #if SMATRIX_BOOL // set result modulo 2 SMATRIX(_set)(_c, r, c, p % 2); #else SMATRIX(_set)(_c, r, c, p); #endif } } } return LIQUID_OK; } // multiply by vector // _q : sparse matrix // _x : input vector [size: _n x 1] // _y : output vector [size: _m x 1] int SMATRIX(_vmul)(SMATRIX() _q, T * _x, T * _y) { unsigned int i; unsigned int j; // initialize to zero for (i=0; i<_q->M; i++) _y[i] = 0; for (i=0; i<_q->M; i++) { // running total T p = 0; // only compute multiplications on non-zero entries for (j=0; j<_q->num_mlist[i]; j++) p += _q->mvals[i][j] * _x[ _q->mlist[i][j] ]; // set output value appropriately #if SMATRIX_BOOL _y[i] = p % 2; #else _y[i] = p; #endif } return LIQUID_OK; } // // internal methods // // find maximum mlist length int SMATRIX(_reset_max_mlist)(SMATRIX() _q) { unsigned int i; _q->max_num_mlist = 0; for (i=0; i<_q->M; i++) { if (_q->num_mlist[i] > _q->max_num_mlist) _q->max_num_mlist = _q->num_mlist[i]; } return LIQUID_OK; } // find maximum nlist length int SMATRIX(_reset_max_nlist)(SMATRIX() _q) { unsigned int j; _q->max_num_nlist = 0; for (j=0; j<_q->N; j++) { if (_q->num_nlist[j] > _q->max_num_nlist) _q->max_num_nlist = _q->num_nlist[j]; } return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/smatrixb.c000066400000000000000000000064721474751757600205110ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sparse matrix API: boolean // #include #include #include #include "liquid.internal.h" // name-mangling macro #define SMATRIX(name) LIQUID_CONCAT(smatrixb,name) #define EXTENSION "b" // primitive type #define T unsigned char // category (float/int/bool) #define SMATRIX_FLOAT 0 #define SMATRIX_INT 0 #define SMATRIX_BOOL 1 // print macros #define PRINTVAL_ZERO() printf(" ."); #define PRINTVAL(V) printf(" %1u", V); // prototypes #include "smatrix.proto.c" // // smatrix cross methods // // multiply sparse binary matrix by floating-point matrix // _q : sparse matrix [size: A->M x A->N] // _x : input vector [size: mx x nx ] // _y : output vector [size: my x ny ] int smatrixb_mulf(smatrixb _A, float * _x, unsigned int _mx, unsigned int _nx, float * _y, unsigned int _my, unsigned int _ny) { // ensure lengths are valid if (_my != _A->M || _ny != _nx || _A->N != _mx ) return liquid_error(LIQUID_EIRANGE,"matrix_mul(), invalid dimensions"); unsigned int i; unsigned int j; // clear output matrix for (i=0; i<_my*_ny; i++) _y[i] = 0.0f; // for (i=0; i<_A->M; i++) { // find non-zero column entries in this row unsigned int p; for (p=0; p<_A->num_mlist[i]; p++) { for (j=0; j<_ny; j++) { //_y(i,j) += _x( _A->mlist[i][p], j); _y[i*_ny + j] += _x[ _A->mlist[i][p]*_nx + j]; } } } return LIQUID_OK; } // multiply sparse binary matrix by floating-point vector // _q : sparse matrix // _x : input vector [size: _N x 1] // _y : output vector [size: _M x 1] int smatrixb_vmulf(smatrixb _q, float * _x, float * _y) { unsigned int i; unsigned int j; for (i=0; i<_q->M; i++) { // reset total _y[i] = 0.0f; // only accumulate values on non-zero entries for (j=0; j<_q->num_mlist[i]; j++) _y[i] += _x[ _q->mlist[i][j] ]; } return LIQUID_OK; } liquid-dsp-1.7.0/src/matrix/src/smatrixf.c000066400000000000000000000032201474751757600205010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sparse matrix API: float // #include #include #include #include "liquid.internal.h" // macro #define SMATRIX(name) LIQUID_CONCAT(smatrixf,name) #define EXTENSION "f" // primitive type #define T float // category (float/int/bool) #define SMATRIX_FLOAT 1 #define SMATRIX_INT 0 #define SMATRIX_BOOL 0 // print macros #define PRINTVAL_ZERO() printf(" %6s", "."); #define PRINTVAL(V) printf(" %6.2f", V); // prototypes #include "smatrix.proto.c" liquid-dsp-1.7.0/src/matrix/src/smatrixi.c000066400000000000000000000032511474751757600205100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // sparse matrix API: short signed integer // #include #include #include #include "liquid.internal.h" // name-mangling macro #define SMATRIX(name) LIQUID_CONCAT(smatrixi,name) #define EXTENSION "i" // primitive type #define T short int // category (float/int/bool) #define SMATRIX_FLOAT 0 #define SMATRIX_INT 1 #define SMATRIX_BOOL 0 // print macros #define PRINTVAL_ZERO() printf(" ."); #define PRINTVAL(V) printf(" %3d", V); // prototypes #include "smatrix.proto.c" liquid-dsp-1.7.0/src/matrix/tests/000077500000000000000000000000001474751757600170565ustar00rootroot00000000000000liquid-dsp-1.7.0/src/matrix/tests/data/000077500000000000000000000000001474751757600177675ustar00rootroot00000000000000liquid-dsp-1.7.0/src/matrix/tests/data/README.md000066400000000000000000000002051474751757600212430ustar00rootroot00000000000000 matrix test data ================ This directory contains all of the data files for testing matrix operations within liquid-dsp. liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_add.c000066400000000000000000000122261474751757600235540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix addition // #include // matrixcf_data_add_x [size: 5 x 4] float complex matrixcf_data_add_x[] = { 1.366575479507 + -1.463535666466*_Complex_I /* ( 0, 0) */, 1.982354640961 + 0.090445250273*_Complex_I /* ( 0, 1) */, 0.913504719734 + -0.689249753952*_Complex_I /* ( 0, 2) */, 0.671039104462 + -0.184951126575*_Complex_I /* ( 0, 3) */, 0.264611721039 + 0.204716682434*_Complex_I /* ( 1, 0) */, 0.995791137218 + -0.192152589560*_Complex_I /* ( 1, 1) */, -1.983934879303 + -0.306251227856*_Complex_I /* ( 1, 2) */, -0.375840932131 + -0.751154422760*_Complex_I /* ( 1, 3) */, 0.245937779546 + -0.470900952816*_Complex_I /* ( 2, 0) */, -0.343152791262 + 1.205224752426*_Complex_I /* ( 2, 1) */, -0.143777698278 + -0.457689523697*_Complex_I /* ( 2, 2) */, -1.387172579765 + 0.225333094597*_Complex_I /* ( 2, 3) */, 0.781192481518 + -1.102205991745*_Complex_I /* ( 3, 0) */, 1.444583415985 + 0.660028517246*_Complex_I /* ( 3, 1) */, 0.043851174414 + 0.049496211112*_Complex_I /* ( 3, 2) */, 0.399744838476 + -1.435891628265*_Complex_I /* ( 3, 3) */, -0.488068610430 + -0.211131110787*_Complex_I /* ( 4, 0) */, 0.573721885681 + 0.016210200265*_Complex_I /* ( 4, 1) */, -1.381630182266 + -0.026558181271*_Complex_I /* ( 4, 2) */, -0.176615595818 + -0.414863616228*_Complex_I /* ( 4, 3) */}; // matrixcf_data_add_y [size: 5 x 4] float complex matrixcf_data_add_y[] = { -0.345586329699 + 0.240964725614*_Complex_I /* ( 0, 0) */, -0.025732314214 + 1.212726473808*_Complex_I /* ( 0, 1) */, 0.907316803932 + 1.614625453949*_Complex_I /* ( 0, 2) */, -1.277831077576 + -0.193561494350*_Complex_I /* ( 0, 3) */, -0.566267848015 + -0.477513909340*_Complex_I /* ( 1, 0) */, -0.220387980342 + 0.152425482869*_Complex_I /* ( 1, 1) */, 1.062286615372 + -1.132043361664*_Complex_I /* ( 1, 2) */, 0.560977220535 + -0.981467425823*_Complex_I /* ( 1, 3) */, 0.025816366076 + -0.697246491909*_Complex_I /* ( 2, 0) */, 0.658244788647 + -1.403432965279*_Complex_I /* ( 2, 1) */, -1.326129436493 + -0.529069602489*_Complex_I /* ( 2, 2) */, -1.535833358765 + -1.406206607819*_Complex_I /* ( 2, 3) */, 0.101660177112 + -1.552777647972*_Complex_I /* ( 3, 0) */, 1.834807038307 + 0.647780478001*_Complex_I /* ( 3, 1) */, -0.620168924332 + -0.103246472776*_Complex_I /* ( 3, 2) */, -0.063054643571 + -0.756766498089*_Complex_I /* ( 3, 3) */, 0.280569136143 + 0.560459613800*_Complex_I /* ( 4, 0) */, -0.069713011384 + -0.971132814884*_Complex_I /* ( 4, 1) */, 0.225165605545 + -1.117488980293*_Complex_I /* ( 4, 2) */, -0.290932357311 + 0.302335798740*_Complex_I /* ( 4, 3) */}; // matrixcf_data_add_z [size: 5 x 4] float complex matrixcf_data_add_z[] = { 1.020989149809 + -1.222570940852*_Complex_I /* ( 0, 0) */, 1.956622326747 + 1.303171724081*_Complex_I /* ( 0, 1) */, 1.820821523666 + 0.925375699997*_Complex_I /* ( 0, 2) */, -0.606791973114 + -0.378512620926*_Complex_I /* ( 0, 3) */, -0.301656126976 + -0.272797226906*_Complex_I /* ( 1, 0) */, 0.775403156877 + -0.039727106690*_Complex_I /* ( 1, 1) */, -0.921648263931 + -1.438294589520*_Complex_I /* ( 1, 2) */, 0.185136288404 + -1.732621848583*_Complex_I /* ( 1, 3) */, 0.271754145622 + -1.168147444725*_Complex_I /* ( 2, 0) */, 0.315091997385 + -0.198208212852*_Complex_I /* ( 2, 1) */, -1.469907134771 + -0.986759126186*_Complex_I /* ( 2, 2) */, -2.923005938530 + -1.180873513222*_Complex_I /* ( 2, 3) */, 0.882852658629 + -2.654983639717*_Complex_I /* ( 3, 0) */, 3.279390454292 + 1.307808995247*_Complex_I /* ( 3, 1) */, -0.576317749918 + -0.053750261664*_Complex_I /* ( 3, 2) */, 0.336690194905 + -2.192658126354*_Complex_I /* ( 3, 3) */, -0.207499474287 + 0.349328503013*_Complex_I /* ( 4, 0) */, 0.504008874297 + -0.954922614619*_Complex_I /* ( 4, 1) */, -1.156464576721 + -1.144047161564*_Complex_I /* ( 4, 2) */, -0.467547953129 + -0.112527817488*_Complex_I /* ( 4, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_aug.c000066400000000000000000000134321474751757600236000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix augmentation // #include // matrixcf_data_aug_x [size: 5 x 4] float complex matrixcf_data_aug_x[] = { -1.383545994759 + 0.803655147552*_Complex_I /* ( 0, 0) */, -0.918114125729 + -1.194809913635*_Complex_I /* ( 0, 1) */, 0.090901032090 + 0.484884619713*_Complex_I /* ( 0, 2) */, 0.109402157366 + 1.450437188148*_Complex_I /* ( 0, 3) */, -2.269510746002 + -0.606436431408*_Complex_I /* ( 1, 0) */, -0.195189133286 + 0.416639328003*_Complex_I /* ( 1, 1) */, 1.940145850182 + 0.895506143570*_Complex_I /* ( 1, 2) */, -0.784153759480 + -0.345893263817*_Complex_I /* ( 1, 3) */, 0.652509629726 + 0.994532823563*_Complex_I /* ( 2, 0) */, -2.253150939941 + 0.327611356974*_Complex_I /* ( 2, 1) */, 1.012208938599 + -0.677044689655*_Complex_I /* ( 2, 2) */, -0.700399398804 + -0.330108255148*_Complex_I /* ( 2, 3) */, -1.175772666931 + 0.248428389430*_Complex_I /* ( 3, 0) */, 0.412228941917 + -2.519471645355*_Complex_I /* ( 3, 1) */, -1.667356371880 + -1.187105178833*_Complex_I /* ( 3, 2) */, 1.243350982666 + -0.736937880516*_Complex_I /* ( 3, 3) */, 0.033468723297 + 0.131351217628*_Complex_I /* ( 4, 0) */, -0.617851972580 + 1.434038400650*_Complex_I /* ( 4, 1) */, -1.009798288345 + 0.758803665638*_Complex_I /* ( 4, 2) */, 1.450994849205 + -0.595933079720*_Complex_I /* ( 4, 3) */}; // matrixcf_data_aug_y [size: 5 x 3] float complex matrixcf_data_aug_y[] = { 0.301848381758 + 0.353115469217*_Complex_I /* ( 0, 0) */, 0.703616917133 + 0.044240720570*_Complex_I /* ( 0, 1) */, 0.268176555634 + 1.071476221085*_Complex_I /* ( 0, 2) */, -0.717849135399 + -0.764326214790*_Complex_I /* ( 1, 0) */, -0.108926303685 + -0.315297245979*_Complex_I /* ( 1, 1) */, 0.357895255089 + -1.419853448868*_Complex_I /* ( 1, 2) */, -0.831380963326 + 1.003911018372*_Complex_I /* ( 2, 0) */, -0.361211270094 + -0.926369905472*_Complex_I /* ( 2, 1) */, 2.307183980942 + -0.432167291641*_Complex_I /* ( 2, 2) */, -0.694230437279 + -1.021739125252*_Complex_I /* ( 3, 0) */, 0.412434548140 + -1.840429663658*_Complex_I /* ( 3, 1) */, 0.342358648777 + -1.084336757660*_Complex_I /* ( 3, 2) */, -0.314995974302 + -0.811702668667*_Complex_I /* ( 4, 0) */, 0.912520587444 + -2.686280250549*_Complex_I /* ( 4, 1) */, 0.204153224826 + -0.616621196270*_Complex_I /* ( 4, 2) */}; // matrixcf_data_aug_z [size: 5 x 7] float complex matrixcf_data_aug_z[] = { -1.383545994759 + 0.803655147552*_Complex_I /* ( 0, 0) */, -0.918114125729 + -1.194809913635*_Complex_I /* ( 0, 1) */, 0.090901032090 + 0.484884619713*_Complex_I /* ( 0, 2) */, 0.109402157366 + 1.450437188148*_Complex_I /* ( 0, 3) */, 0.301848381758 + 0.353115469217*_Complex_I /* ( 0, 4) */, 0.703616917133 + 0.044240720570*_Complex_I /* ( 0, 5) */, 0.268176555634 + 1.071476221085*_Complex_I /* ( 0, 6) */, -2.269510746002 + -0.606436431408*_Complex_I /* ( 1, 0) */, -0.195189133286 + 0.416639328003*_Complex_I /* ( 1, 1) */, 1.940145850182 + 0.895506143570*_Complex_I /* ( 1, 2) */, -0.784153759480 + -0.345893263817*_Complex_I /* ( 1, 3) */, -0.717849135399 + -0.764326214790*_Complex_I /* ( 1, 4) */, -0.108926303685 + -0.315297245979*_Complex_I /* ( 1, 5) */, 0.357895255089 + -1.419853448868*_Complex_I /* ( 1, 6) */, 0.652509629726 + 0.994532823563*_Complex_I /* ( 2, 0) */, -2.253150939941 + 0.327611356974*_Complex_I /* ( 2, 1) */, 1.012208938599 + -0.677044689655*_Complex_I /* ( 2, 2) */, -0.700399398804 + -0.330108255148*_Complex_I /* ( 2, 3) */, -0.831380963326 + 1.003911018372*_Complex_I /* ( 2, 4) */, -0.361211270094 + -0.926369905472*_Complex_I /* ( 2, 5) */, 2.307183980942 + -0.432167291641*_Complex_I /* ( 2, 6) */, -1.175772666931 + 0.248428389430*_Complex_I /* ( 3, 0) */, 0.412228941917 + -2.519471645355*_Complex_I /* ( 3, 1) */, -1.667356371880 + -1.187105178833*_Complex_I /* ( 3, 2) */, 1.243350982666 + -0.736937880516*_Complex_I /* ( 3, 3) */, -0.694230437279 + -1.021739125252*_Complex_I /* ( 3, 4) */, 0.412434548140 + -1.840429663658*_Complex_I /* ( 3, 5) */, 0.342358648777 + -1.084336757660*_Complex_I /* ( 3, 6) */, 0.033468723297 + 0.131351217628*_Complex_I /* ( 4, 0) */, -0.617851972580 + 1.434038400650*_Complex_I /* ( 4, 1) */, -1.009798288345 + 0.758803665638*_Complex_I /* ( 4, 2) */, 1.450994849205 + -0.595933079720*_Complex_I /* ( 4, 3) */, -0.314995974302 + -0.811702668667*_Complex_I /* ( 4, 4) */, 0.912520587444 + -2.686280250549*_Complex_I /* ( 4, 5) */, 0.204153224826 + -0.616621196270*_Complex_I /* ( 4, 6) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_chol.c000066400000000000000000000065221474751757600237530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing Cholesky decomposition // #include // matrixcf_data_chol_L [size: 4 x 4] float complex matrixcf_data_chol_L[] = { 1.010000000000 + 0.000000000000*_Complex_I /* ( 0, 0) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 0, 1) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 0, 2) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 0, 3) */, -1.420000000000 + 0.250000000000*_Complex_I /* ( 1, 0) */, 0.500000000000 + 0.000000000000*_Complex_I /* ( 1, 1) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 1, 2) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 1, 3) */, 0.320000000000 + -1.230000000000*_Complex_I /* ( 2, 0) */, 2.010000000000 + 0.780000000000*_Complex_I /* ( 2, 1) */, 0.300000000000 + 0.000000000000*_Complex_I /* ( 2, 2) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 2, 3) */, -1.020000000000 + 1.020000000000*_Complex_I /* ( 3, 0) */, -0.320000000000 + -0.030000000000*_Complex_I /* ( 3, 1) */, -1.650000000000 + 2.010000000000*_Complex_I /* ( 3, 2) */, 1.070000000000 + 0.000000000000*_Complex_I /* ( 3, 3) */}; // matrixcf_data_chol_A [size: 4 x 4] float complex matrixcf_data_chol_A[] = { 1.020100000000 + 0.000000000000*_Complex_I /* ( 0, 0) */, -1.434200000000 + -0.252500000000*_Complex_I /* ( 0, 1) */, 0.323200000000 + 1.242300000000*_Complex_I /* ( 0, 2) */, -1.030200000000 + -1.030200000000*_Complex_I /* ( 0, 3) */, -1.434200000000 + 0.252500000000*_Complex_I /* ( 1, 0) */, 2.328900000000 + 0.000000000000*_Complex_I /* ( 1, 1) */, 0.243100000000 + -2.056600000000*_Complex_I /* ( 1, 2) */, 1.543400000000 + 1.208400000000*_Complex_I /* ( 1, 3) */, 0.323200000000 + -1.242300000000*_Complex_I /* ( 2, 0) */, 0.243100000000 + 2.056600000000*_Complex_I /* ( 2, 1) */, 6.353800000000 + 0.000000000000*_Complex_I /* ( 2, 2) */, -2.742600000000 + 0.135900000000*_Complex_I /* ( 2, 3) */, -1.030200000000 + 1.030200000000*_Complex_I /* ( 3, 0) */, 1.543400000000 + -1.208400000000*_Complex_I /* ( 3, 1) */, -2.742600000000 + -0.135900000000*_Complex_I /* ( 3, 2) */, 10.091600000000 + 0.000000000000*_Complex_I /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_inv.c000066400000000000000000000107101474751757600236140ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix inversion // #include // matrixcf_data_inv_x [size: 5 x 5] float complex matrixcf_data_inv_x[] = { -0.911099433899 + -0.436777323484*_Complex_I /* ( 0, 0) */, 0.598295390606 + -0.283340752125*_Complex_I /* ( 0, 1) */, -0.264758616686 + -0.421906232834*_Complex_I /* ( 0, 2) */, -0.066837862134 + -0.934806823730*_Complex_I /* ( 0, 3) */, 0.393610686064 + -1.011345505714*_Complex_I /* ( 0, 4) */, -0.543692529202 + -1.426580429077*_Complex_I /* ( 1, 0) */, -1.006833553314 + 0.448534607887*_Complex_I /* ( 1, 1) */, 0.048818156123 + -0.540948212147*_Complex_I /* ( 1, 2) */, 0.180871278048 + 0.331172674894*_Complex_I /* ( 1, 3) */, -1.100448012352 + 1.841731786728*_Complex_I /* ( 1, 4) */, 2.341797351837 + -1.200128436089*_Complex_I /* ( 2, 0) */, 0.239693909883 + 0.206349417567*_Complex_I /* ( 2, 1) */, -0.815828502178 + -0.349400132895*_Complex_I /* ( 2, 2) */, 1.213637232780 + 0.298941820860*_Complex_I /* ( 2, 3) */, -1.522765398026 + 1.651986479759*_Complex_I /* ( 2, 4) */, 1.481738448143 + 0.055169839412*_Complex_I /* ( 3, 0) */, -1.241538286209 + -0.077680915594*_Complex_I /* ( 3, 1) */, 1.046607017517 + -0.843883395195*_Complex_I /* ( 3, 2) */, -1.564810752869 + 1.346152186394*_Complex_I /* ( 3, 3) */, 0.786287426949 + -1.010108113289*_Complex_I /* ( 3, 4) */, 1.234361886978 + -1.305809140205*_Complex_I /* ( 4, 0) */, 0.053748749197 + 0.403882414103*_Complex_I /* ( 4, 1) */, -0.081336200237 + -0.462558329105*_Complex_I /* ( 4, 2) */, -1.370563983917 + -0.284755766392*_Complex_I /* ( 4, 3) */, 0.200873896480 + -0.036809749901*_Complex_I /* ( 4, 4) */}; // matrixcf_data_inv_y [size: 5 x 5] float complex matrixcf_data_inv_y[] = { -0.127852678827 + -0.009178191835*_Complex_I /* ( 0, 0) */, -0.199905444866 + 0.033789259175*_Complex_I /* ( 0, 1) */, 0.168465876479 + -0.059607902071*_Complex_I /* ( 0, 2) */, 0.087700609092 + -0.030597427908*_Complex_I /* ( 0, 3) */, 0.084793376582 + 0.131223765916*_Complex_I /* ( 0, 4) */, 0.209779356201 + 0.642123753363*_Complex_I /* ( 1, 0) */, -0.045651767577 + -0.019599459364*_Complex_I /* ( 1, 1) */, 0.137284052424 + 0.504637287094*_Complex_I /* ( 1, 2) */, -0.333643348460 + 0.455368743084*_Complex_I /* ( 1, 3) */, 0.244939020151 + -0.609710193351*_Complex_I /* ( 1, 4) */, -0.114524820581 + 0.963012925652*_Complex_I /* ( 2, 0) */, 0.303499486096 + 0.348121666797*_Complex_I /* ( 2, 1) */, -0.327372880299 + 0.397314645420*_Complex_I /* ( 2, 2) */, -0.231096370464 + 0.372958732742*_Complex_I /* ( 2, 3) */, 0.089363987094 + -0.240520272187*_Complex_I /* ( 2, 4) */, 0.072169240922 + 0.159456098576*_Complex_I /* ( 3, 0) */, -0.064066539188 + 0.069570707500*_Complex_I /* ( 3, 1) */, 0.090335627717 + -0.121329478735*_Complex_I /* ( 3, 2) */, 0.053196220990 + -0.158230982223*_Complex_I /* ( 3, 3) */, -0.413653285108 + 0.167815066469*_Complex_I /* ( 3, 4) */, 0.089194647874 + -0.035492413461*_Complex_I /* ( 4, 0) */, -0.192303472410 + -0.221655891788*_Complex_I /* ( 4, 1) */, 0.111730542618 + -0.221903756183*_Complex_I /* ( 4, 2) */, 0.303835472120 + -0.022543572811*_Complex_I /* ( 4, 3) */, -0.167008031325 + 0.051911194273*_Complex_I /* ( 4, 4) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_linsolve.c000066400000000000000000000071621474751757600246620ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing linear solver // #include // matrixcf_data_linsolve_A [size: 5 x 5] float complex matrixcf_data_linsolve_A[] = { -0.482884645462 + -0.221723198891*_Complex_I /* ( 0, 0) */, -0.387645065784 + 0.086682170630*_Complex_I /* ( 0, 1) */, 1.580931067467 + 0.883717715740*_Complex_I /* ( 0, 2) */, 1.570333838463 + 1.783135294914*_Complex_I /* ( 0, 3) */, -1.081483244896 + -0.691094517708*_Complex_I /* ( 0, 4) */, 0.248138338327 + -0.250954031944*_Complex_I /* ( 1, 0) */, 0.790891706944 + -0.313775628805*_Complex_I /* ( 1, 1) */, -0.146090522408 + -1.320674061775*_Complex_I /* ( 1, 2) */, 0.672296106815 + 1.346951484680*_Complex_I /* ( 1, 3) */, -0.352442741394 + 0.056975554675*_Complex_I /* ( 1, 4) */, 0.707973957062 + -0.069402769208*_Complex_I /* ( 2, 0) */, -0.894841134548 + -1.854133605957*_Complex_I /* ( 2, 1) */, 0.397095054388 + -0.924011290073*_Complex_I /* ( 2, 2) */, 0.054669041187 + 0.017023870721*_Complex_I /* ( 2, 3) */, 0.515784740448 + -0.455956429243*_Complex_I /* ( 2, 4) */, 0.570774257183 + 0.538610219955*_Complex_I /* ( 3, 0) */, -0.389531791210 + 0.200702637434*_Complex_I /* ( 3, 1) */, 0.159817531705 + 1.283960223198*_Complex_I /* ( 3, 2) */, 1.571215510368 + 0.574963092804*_Complex_I /* ( 3, 3) */, -2.452192783356 + -0.583715677261*_Complex_I /* ( 3, 4) */, -0.603657603264 + 0.617622077465*_Complex_I /* ( 4, 0) */, 0.935181498528 + 0.949800848961*_Complex_I /* ( 4, 1) */, 0.043205004185 + 1.351160168648*_Complex_I /* ( 4, 2) */, 0.674502849579 + 0.340750336647*_Complex_I /* ( 4, 3) */, -0.241452947259 + 1.540177464485*_Complex_I /* ( 4, 4) */}; // matrixcf_data_linsolve_x [size: 5 x 1] float complex matrixcf_data_linsolve_x[] = { -0.686784207821 + 0.516409814358*_Complex_I /* ( 0, 0) */, 0.725918948650 + -0.725804686546*_Complex_I /* ( 1, 0) */, 0.048043362796 + 1.415739893913*_Complex_I /* ( 2, 0) */, 1.184294700623 + -1.108955144882*_Complex_I /* ( 3, 0) */, 1.000079274178 + 0.117630988359*_Complex_I /* ( 4, 0) */}; // matrixcf_data_linsolve_b [size: 5 x 1] float complex matrixcf_data_linsolve_b[] = { 1.889372086452 + 2.079795053851*_Complex_I /* ( 0, 0) */, 4.099006087145 + 0.093571115573*_Complex_I /* ( 1, 0) */, -0.465385431770 + -0.201195243205*_Complex_I /* ( 2, 0) */, -2.502649126311 + -1.292489487343*_Complex_I /* ( 3, 0) */, 0.307098947642 + 0.568345470088*_Complex_I /* ( 4, 0) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_ludecomp.c000066400000000000000000000124041474751757600246320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing L/U decomposition // #include // matrixcf_data_ludecomp_A [size: 8 x 8] float complex matrixcf_data_ludecomp_A[] = { 0.455808967352 + 0.239869371057*_Complex_I /* ( 0, 0) */, 1.076113820076 + 0.303303003311*_Complex_I /* ( 0, 1) */, -1.174549579620 + -1.593330740929*_Complex_I /* ( 0, 2) */, 1.428434848785 + -2.108702898026*_Complex_I /* ( 0, 3) */, 1.944794058800 + 1.039716124535*_Complex_I /* ( 0, 4) */, -0.003220892511 + -1.070197224617*_Complex_I /* ( 0, 5) */, 2.282850980759 + 0.567153334618*_Complex_I /* ( 0, 6) */, 0.677789986134 + -0.110934779048*_Complex_I /* ( 0, 7) */, -0.541479706764 + 0.508462309837*_Complex_I /* ( 1, 0) */, 0.659551382065 + 0.341979026794*_Complex_I /* ( 1, 1) */, 0.422295093536 + -0.748002707958*_Complex_I /* ( 1, 2) */, 0.991572380066 + -1.739566326141*_Complex_I /* ( 1, 3) */, -0.973251938820 + -0.314995020628*_Complex_I /* ( 1, 4) */, -0.348222613335 + 1.216362476349*_Complex_I /* ( 1, 5) */, -0.444941103458 + -0.435953140259*_Complex_I /* ( 1, 6) */, 0.664277911186 + 0.398205667734*_Complex_I /* ( 1, 7) */, 1.578197240829 + -0.245545297861*_Complex_I /* ( 2, 0) */, -0.734657287598 + -0.314642846584*_Complex_I /* ( 2, 1) */, -0.185400843620 + 0.411517560482*_Complex_I /* ( 2, 2) */, -0.141458645463 + 2.540255069733*_Complex_I /* ( 2, 3) */, -1.887707233429 + 1.261052608490*_Complex_I /* ( 2, 4) */, 1.356706976891 + -0.073478087783*_Complex_I /* ( 2, 5) */, 0.382849365473 + 1.176013708115*_Complex_I /* ( 2, 6) */, 0.088731415570 + -0.000313452416*_Complex_I /* ( 2, 7) */, 0.694614350796 + 0.107012517750*_Complex_I /* ( 3, 0) */, -0.541421890259 + -1.525843501091*_Complex_I /* ( 3, 1) */, 1.210077285767 + -0.249905958772*_Complex_I /* ( 3, 2) */, 0.051122765988 + 0.576834678650*_Complex_I /* ( 3, 3) */, 2.360952138901 + -0.439353585243*_Complex_I /* ( 3, 4) */, 0.927220702171 + 0.293185442686*_Complex_I /* ( 3, 5) */, -0.235832184553 + -0.484229415655*_Complex_I /* ( 3, 6) */, -1.589996099472 + 0.180045768619*_Complex_I /* ( 3, 7) */, 1.345695137978 + -0.080361045897*_Complex_I /* ( 4, 0) */, -0.245824366808 + -1.841626405716*_Complex_I /* ( 4, 1) */, 0.978698849678 + 1.369340777397*_Complex_I /* ( 4, 2) */, -1.106017351151 + -1.615537166595*_Complex_I /* ( 4, 3) */, 0.627505123615 + 1.024900913239*_Complex_I /* ( 4, 4) */, 1.808397769928 + -0.614134788513*_Complex_I /* ( 4, 5) */, -0.322292149067 + -0.765307128429*_Complex_I /* ( 4, 6) */, -0.674273192883 + 0.044275555760*_Complex_I /* ( 4, 7) */, -2.861634492874 + 2.582857608795*_Complex_I /* ( 5, 0) */, -1.920535564423 + -0.081001155078*_Complex_I /* ( 5, 1) */, -1.339942932129 + -0.246527969837*_Complex_I /* ( 5, 2) */, 0.540911912918 + 0.283990591764*_Complex_I /* ( 5, 3) */, -0.800716042519 + 0.764756917953*_Complex_I /* ( 5, 4) */, 1.206449866295 + 0.518103539944*_Complex_I /* ( 5, 5) */, -0.377558648586 + 0.065486297011*_Complex_I /* ( 5, 6) */, -1.090067625046 + 0.741791069508*_Complex_I /* ( 5, 7) */, -1.424072742462 + 0.091005645692*_Complex_I /* ( 6, 0) */, 0.340615779161 + 1.995890378952*_Complex_I /* ( 6, 1) */, -0.395366579294 + 0.685165762901*_Complex_I /* ( 6, 2) */, 0.367168039083 + -1.265154719353*_Complex_I /* ( 6, 3) */, 0.716018438339 + 1.003421306610*_Complex_I /* ( 6, 4) */, -0.648339152336 + 2.441966056824*_Complex_I /* ( 6, 5) */, 0.788251757622 + 1.254729628563*_Complex_I /* ( 6, 6) */, -0.776828289032 + -0.615517139435*_Complex_I /* ( 6, 7) */, 1.112848401070 + -0.297139286995*_Complex_I /* ( 7, 0) */, 0.366721868515 + 0.650049626827*_Complex_I /* ( 7, 1) */, 0.072020366788 + -0.518339037895*_Complex_I /* ( 7, 2) */, 1.033115744591 + -0.196805760264*_Complex_I /* ( 7, 3) */, -1.083071947098 + -1.565491795540*_Complex_I /* ( 7, 4) */, 1.409144878387 + 0.992799341679*_Complex_I /* ( 7, 5) */, 0.387732833624 + -1.445696353912*_Complex_I /* ( 7, 6) */, -0.528750956059 + -1.205648779869*_Complex_I /* ( 7, 7) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_mul.c000066400000000000000000000105341474751757600236210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix multiplication // #include // matrixcf_data_mul_x [size: 5 x 4] float complex matrixcf_data_mul_x[] = { 1.131277322769 + -2.908640623093*_Complex_I /* ( 0, 0) */, 0.847201466560 + -1.637244105339*_Complex_I /* ( 0, 1) */, -2.173580169678 + 0.096817605197*_Complex_I /* ( 0, 2) */, 0.792498826981 + -0.358158409595*_Complex_I /* ( 0, 3) */, -0.243082717061 + 0.824095964432*_Complex_I /* ( 1, 0) */, -1.889652967453 + 0.283876717091*_Complex_I /* ( 1, 1) */, 0.044418141246 + -0.882465064526*_Complex_I /* ( 1, 2) */, 0.515216410160 + -0.366532146931*_Complex_I /* ( 1, 3) */, 0.579283773899 + 1.173513293266*_Complex_I /* ( 2, 0) */, 0.059265002608 + -0.497733235359*_Complex_I /* ( 2, 1) */, -0.877321839333 + 0.404732406139*_Complex_I /* ( 2, 2) */, -0.794282734394 + 0.456011295319*_Complex_I /* ( 2, 3) */, -1.174414634705 + -1.358565688133*_Complex_I /* ( 3, 0) */, -0.418152034283 + 1.380919337273*_Complex_I /* ( 3, 1) */, -0.747197151184 + 1.584241986275*_Complex_I /* ( 3, 2) */, -0.522293865681 + -0.573823392391*_Complex_I /* ( 3, 3) */, -1.866284489632 + -0.199214607477*_Complex_I /* ( 4, 0) */, -0.453905433416 + 0.452787637711*_Complex_I /* ( 4, 1) */, 1.989426016808 + -1.771166682243*_Complex_I /* ( 4, 2) */, 2.234328985214 + 0.855401337147*_Complex_I /* ( 4, 3) */}; // matrixcf_data_mul_y [size: 4 x 3] float complex matrixcf_data_mul_y[] = { 0.122429788113 + -1.041572093964*_Complex_I /* ( 0, 0) */, -1.123313307762 + -1.396123170853*_Complex_I /* ( 0, 1) */, -0.318034142256 + -0.537796914577*_Complex_I /* ( 0, 2) */, 0.096901215613 + -0.035752061754*_Complex_I /* ( 1, 0) */, 0.423960685730 + -0.379842221737*_Complex_I /* ( 1, 1) */, -0.184147700667 + 0.022100308910*_Complex_I /* ( 1, 2) */, 0.189968794584 + 0.919595599174*_Complex_I /* ( 2, 0) */, 0.621766507626 + -0.634516119957*_Complex_I /* ( 2, 1) */, 0.605251312256 + 1.410223841667*_Complex_I /* ( 2, 2) */, 0.427330523729 + 0.042397715151*_Complex_I /* ( 3, 0) */, 0.204851210117 + 0.611065924168*_Complex_I /* ( 3, 1) */, 0.562124013901 + 0.047597970814*_Complex_I /* ( 3, 2) */}; // matrixcf_data_mul_z [size: 5 x 3] float complex matrixcf_data_mul_z[] = { -3.015598273252 + -3.823225604286*_Complex_I /* ( 0, 0) */, -6.503138041472 + 2.522251659946*_Complex_I /* ( 0, 1) */, -3.033435877267 + -2.533375977709*_Complex_I /* ( 0, 2) */, 1.711291176504 + 0.187568584413*_Complex_I /* ( 1, 0) */, 0.527484730969 + -0.085346610822*_Complex_I /* ( 1, 1) */, 2.440625470928 + -0.878385559540*_Complex_I /* ( 1, 2) */, 0.383559143593 + -1.078745633782*_Complex_I /* ( 2, 0) */, 0.093675017974 + -1.944126015771*_Complex_I /* ( 2, 1) */, -1.122987739839 + -1.365514815630*_Complex_I /* ( 2, 2) */, -3.347645581625 + 0.552152171890*_Complex_I /* ( 3, 0) */, 0.554058303745 + 4.932442551750*_Complex_I /* ( 3, 1) */, -3.263304464031 + 0.357861697730*_Complex_I /* ( 3, 2) */, 2.461434774758 + 3.932854324787*_Complex_I /* ( 4, 0) */, 1.845966920717 + 2.370697350446*_Complex_I /* ( 4, 1) */, 5.477082880684 + 3.294354034834*_Complex_I /* ( 4, 2) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_qrdecomp.c000066400000000000000000000106661474751757600246440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing Q/R decomposition // #include // matrixcf_data_qrdecomp_A [size: 4 x 4] float complex matrixcf_data_qrdecomp_A[] = { 2.114020000000 + -0.576040000000*_Complex_I /* ( 0, 0) */, 0.417500000000 + 1.008330000000*_Complex_I /* ( 0, 1) */, -0.962640000000 + -3.621960000000*_Complex_I /* ( 0, 2) */, -0.206790000000 + -1.026680000000*_Complex_I /* ( 0, 3) */, 0.008540000000 + 1.616260000000*_Complex_I /* ( 1, 0) */, 0.846950000000 + -0.327360000000*_Complex_I /* ( 1, 1) */, -1.018620000000 + -1.107860000000*_Complex_I /* ( 1, 2) */, -1.788770000000 + 1.844560000000*_Complex_I /* ( 1, 3) */, -2.979010000000 + -1.303840000000*_Complex_I /* ( 2, 0) */, 0.522890000000 + 1.891100000000*_Complex_I /* ( 2, 1) */, 1.325760000000 + -0.367370000000*_Complex_I /* ( 2, 2) */, 0.047170000000 + 0.206280000000*_Complex_I /* ( 2, 3) */, 0.289700000000 + 0.642470000000*_Complex_I /* ( 3, 0) */, -0.559160000000 + 0.683020000000*_Complex_I /* ( 3, 1) */, 1.406150000000 + 0.623980000000*_Complex_I /* ( 3, 2) */, -0.127670000000 + -0.539970000000*_Complex_I /* ( 3, 3) */}; // matrixcf_data_qrdecomp_Q [size: 4 x 4] float complex matrixcf_data_qrdecomp_Q[] = { 0.491706158979 + -0.133982845866*_Complex_I /* ( 0, 0) */, 0.429660711419 + 0.559833033911*_Complex_I /* ( 0, 1) */, -0.309333641162 + -0.278321211351*_Complex_I /* ( 0, 2) */, 0.215207397547 + -0.150957196713*_Complex_I /* ( 0, 3) */, 0.001986343837 + 0.375930689639*_Complex_I /* ( 1, 0) */, 0.242768204454 + 0.009257007128*_Complex_I /* ( 1, 1) */, -0.422306122793 + -0.032511505165*_Complex_I /* ( 1, 2) */, -0.503566009661 + 0.605534385769*_Complex_I /* ( 1, 3) */, -0.692896739226 + -0.303263998601*_Complex_I /* ( 2, 0) */, 0.054111560749 + 0.468071856237*_Complex_I /* ( 2, 1) */, -0.082147488614 + 0.069653107384*_Complex_I /* ( 2, 2) */, 0.279669645547 + 0.340721083028*_Complex_I /* ( 2, 3) */, 0.067382179098 + 0.149433995875*_Complex_I /* ( 3, 0) */, -0.270466351267 + 0.384428384950*_Complex_I /* ( 3, 1) */, -0.285071449427 + 0.744704670261*_Complex_I /* ( 3, 2) */, -0.173581995183 + -0.293616086507*_Complex_I /* ( 3, 3) */}; // matrixcf_data_qrdecomp_R [size: 4 x 4] float complex matrixcf_data_qrdecomp_R[] = { 4.299356356224 + 0.000000000000*_Complex_I /* ( 0, 0) */, -0.922616273377 + -0.789487259898*_Complex_I /* ( 0, 1) */, -1.025768821795 + -1.040664085433*_Complex_I /* ( 0, 2) */, 0.541217397816 + -0.002345615451*_Complex_I /* ( 0, 3) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 1, 0) */, 2.273733268802 + 0.000000000000*_Complex_I /* ( 1, 1) */, -2.939502710322 + -2.626579524510*_Complex_I /* ( 1, 2) */, -1.154743344912 + 0.323209860623*_Complex_I /* ( 1, 3) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 2, 0) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 2, 1) */, 1.701364174878 + 0.000000000000*_Complex_I /* ( 2, 2) */, 0.689923063328 + -0.348316412767*_Complex_I /* ( 2, 3) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 3, 0) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 3, 1) */, 0.000000000000 + 0.000000000000*_Complex_I /* ( 3, 2) */, 2.392371328442 + 0.000000000000*_Complex_I /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixcf_data_transmul.c000066400000000000000000000177711474751757600247030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing multiply/transpose // #include // matrixcf_data_transmul_x [size: 5 x 4] float complex matrixcf_data_transmul_x[] = { 0.897770464420 + -1.137341141701*_Complex_I /* ( 0, 0) */, 0.816529691219 + -0.575469911098*_Complex_I /* ( 0, 1) */, 2.407611131668 + 0.901603281498*_Complex_I /* ( 0, 2) */, -1.024818181992 + -1.785745739937*_Complex_I /* ( 0, 3) */, 1.494256496429 + -0.826167643070*_Complex_I /* ( 1, 0) */, -0.908512234688 + 0.119766108692*_Complex_I /* ( 1, 1) */, -0.215938329697 + -2.537411689758*_Complex_I /* ( 1, 2) */, -1.348789930344 + -0.935531198978*_Complex_I /* ( 1, 3) */, -0.398543357849 + 0.101190350950*_Complex_I /* ( 2, 0) */, -0.083604514599 + 1.493514776230*_Complex_I /* ( 2, 1) */, 0.477280050516 + -0.074863225222*_Complex_I /* ( 2, 2) */, -0.283995777369 + 0.336168438196*_Complex_I /* ( 2, 3) */, -0.030109925196 + -1.602186083794*_Complex_I /* ( 3, 0) */, 2.220442056656 + -0.208865001798*_Complex_I /* ( 3, 1) */, 1.889614224434 + -0.896111547947*_Complex_I /* ( 3, 2) */, -0.317830920219 + 0.215485602617*_Complex_I /* ( 3, 3) */, -0.945744097233 + -0.822628259659*_Complex_I /* ( 4, 0) */, -0.238264903426 + 0.054408840835*_Complex_I /* ( 4, 1) */, 0.532425582409 + 0.438958346844*_Complex_I /* ( 4, 2) */, 0.089408367872 + -1.864659070969*_Complex_I /* ( 4, 3) */}; // matrixcf_data_transmul_xxT [size: 5 x 5] float complex matrixcf_data_transmul_xxT[] = { 13.946043026996 + 0.000000000000*_Complex_I /* ( 0, 0) */, 1.715635857916 + 6.831514803023*_Complex_I /* ( 0, 1) */, -0.628286275869 + 0.653261344190*_Complex_I /* ( 0, 2) */, 7.410888277177 + 5.014956782605*_Complex_I /* ( 0, 3) */, 4.776506544166 + -0.740548606324*_Complex_I /* ( 0, 4) */, 1.715635857916 + -6.831514803023*_Complex_I /* ( 1, 0) */, 12.934634198959 + 0.000000000000*_Complex_I /* ( 1, 1) */, -0.268847669275 + 1.016808442009*_Complex_I /* ( 1, 2) */, 1.329226044140 + -1.905118394989*_Complex_I /* ( 1, 3) */, -0.115507997317 + -1.823416830395*_Complex_I /* ( 1, 4) */, -0.628286275869 + -0.653261344190*_Complex_I /* ( 2, 0) */, -0.268847669275 + -1.016808442009*_Complex_I /* ( 2, 1) */, 2.833715966403 + 0.000000000000*_Complex_I /* ( 2, 2) */, 0.483955462699 + 2.897799335427*_Complex_I /* ( 2, 3) */, -0.036118440085 + -1.523720724413*_Complex_I /* ( 2, 4) */, 7.410888277177 + -5.014956782605*_Complex_I /* ( 3, 0) */, 1.329226044140 + 1.905118394989*_Complex_I /* ( 3, 1) */, 0.483955462699 + -2.897799335427*_Complex_I /* ( 3, 2) */, 12.063002732969 + 0.000000000000*_Complex_I /* ( 3, 3) */, 0.988561701830 + -0.460512464248*_Complex_I /* ( 3, 4) */, 4.776506544166 + 0.740548606324*_Complex_I /* ( 4, 0) */, -0.115507997317 + 1.823416830395*_Complex_I /* ( 4, 1) */, -0.036118440085 + 1.523720724413*_Complex_I /* ( 4, 2) */, 0.988561701830 + 0.460512464248*_Complex_I /* ( 4, 3) */, 5.591988375464 + 0.000000000000*_Complex_I /* ( 4, 4) */}; // matrixcf_data_transmul_xxH [size: 5 x 5] float complex matrixcf_data_transmul_xxH[] = { 2.693069394806 + 5.019630491560*_Complex_I /* ( 0, 0) */, 1.208446246635 + -4.757020341403*_Complex_I /* ( 0, 1) */, 2.656451825557 + 2.224444954914*_Complex_I /* ( 0, 2) */, 5.911512147844 + -2.959566260460*_Complex_I /* ( 0, 3) */, -4.483236639053 + 3.806796594938*_Complex_I /* ( 0, 4) */, 1.208446246635 + -4.757020341403*_Complex_I /* ( 1, 0) */, -3.086513006704 + 0.932888319797*_Complex_I /* ( 1, 1) */, -0.210317709361 + -2.269045302266*_Complex_I /* ( 1, 2) */, -5.412513485879 + -6.508039464439*_Complex_I /* ( 1, 3) */, -2.749055759920 + 0.459776624619*_Complex_I /* ( 1, 4) */, 2.656451825557 + 2.224444954914*_Complex_I /* ( 2, 0) */, -0.210317709361 + -2.269045302266*_Complex_I /* ( 2, 1) */, -1.885163224141 + -0.592788922020*_Complex_I /* ( 2, 2) */, 1.153042421508 + 3.232018360881*_Complex_I /* ( 2, 3) */, 1.287247559495 + 0.601010412549*_Complex_I /* ( 2, 4) */, 5.911512147844 + -2.959566260460*_Complex_I /* ( 3, 0) */, -5.412513485879 + -6.508039464439*_Complex_I /* ( 3, 1) */, 1.153042421508 + 3.232018360881*_Complex_I /* ( 3, 2) */, 5.142853158215 + -4.354648092153*_Complex_I /* ( 3, 3) */, -0.034391537899 + 2.674865932467*_Complex_I /* ( 3, 4) */, -4.483236639053 + 3.806796594938*_Complex_I /* ( 4, 0) */, -2.749055759920 + 0.459776624619*_Complex_I /* ( 4, 1) */, 1.287247559495 + 0.601010412549*_Complex_I /* ( 4, 2) */, -0.034391537899 + 2.674865932467*_Complex_I /* ( 4, 3) */, -3.106642538055 + 1.664057265760*_Complex_I /* ( 4, 4) */}; // matrixcf_data_transmul_xTx [size: 4 x 4] float complex matrixcf_data_transmul_xTx[] = { 9.323024431917 + 0.000000000000*_Complex_I /* ( 0, 0) */, 0.563876592623 + 2.570030362211*_Complex_I /* ( 0, 1) */, 3.226123027525 + 2.636644463529*_Complex_I /* ( 0, 2) */, 1.129305368076 + -4.064920271606*_Complex_I /* ( 0, 3) */, 0.563876592623 + -2.570030362211*_Complex_I /* ( 1, 0) */, 9.108918860377 + 0.000000000000*_Complex_I /* ( 1, 1) */, 5.467585123601 + 2.017612849734*_Complex_I /* ( 1, 2) */, 0.956522192172 + 0.211168853425*_Complex_I /* ( 1, 3) */, 3.226123027525 + -2.636644463529*_Complex_I /* ( 2, 0) */, 5.467585123601 + -2.017612849734*_Complex_I /* ( 2, 1) */, 18.177787287820 + 0.000000000000*_Complex_I /* ( 2, 2) */, -3.137608134941 + -7.366300567700*_Complex_I /* ( 2, 3) */, 1.129305368076 + 4.064920271606*_Complex_I /* ( 3, 0) */, 0.956522192172 + -0.211168853425*_Complex_I /* ( 3, 1) */, -3.137608134941 + 7.366300567700*_Complex_I /* ( 3, 2) */, 10.759653720678 + 0.000000000000*_Complex_I /* ( 3, 3) */}; // matrixcf_data_transmul_xHx [size: 4 x 4] float complex matrixcf_data_transmul_xHx[] = { -1.137085237839 + -2.939337742229*_Complex_I /* ( 0, 0) */, -1.429264118470 + -4.526184217761*_Complex_I /* ( 0, 1) */, -1.049795781222 + -9.317515018345*_Complex_I /* ( 0, 2) */, -6.923890470327 + 1.308742276041*_Complex_I /* ( 0, 3) */, -1.429264118470 + -4.526184217761*_Complex_I /* ( 1, 0) */, 3.863557186128 + -2.360596346275*_Complex_I /* ( 1, 1) */, 6.914587648894 + -0.110888488534*_Complex_I /* ( 1, 2) */, -1.585896210450 + 0.361787209777*_Complex_I /* ( 1, 3) */, -1.049795781222 + -9.317515018345*_Complex_I /* ( 2, 0) */, 6.914587648894 + -0.110888488534*_Complex_I /* ( 2, 1) */, 1.672484488523 + 2.446622681596*_Complex_I /* ( 2, 2) */, -2.591648390404 + -1.678750072577*_Complex_I /* ( 2, 3) */, -6.923890470327 + 1.308742276041*_Complex_I /* ( 3, 0) */, -1.585896210450 + 0.361787209777*_Complex_I /* ( 3, 1) */, -2.591648390404 + -1.678750072577*_Complex_I /* ( 3, 2) */, -4.641352652692 + 5.522450469852*_Complex_I /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_add.c000066400000000000000000000065601474751757600234150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix addition // #include // matrixf_data_add_x [size: 5 x 4] float matrixf_data_add_x[] = { -2.153858900070 /* ( 0, 0) */, 0.374406367540 /* ( 0, 1) */, -0.356648415327 /* ( 0, 2) */, 0.673922061920 /* ( 0, 3) */, -1.686753273010 /* ( 1, 0) */, -0.382442235947 /* ( 1, 1) */, 0.287308961153 /* ( 1, 2) */, -0.479356884956 /* ( 1, 3) */, -0.336519986391 /* ( 2, 0) */, 0.173820436001 /* ( 2, 1) */, -1.243059277534 /* ( 2, 2) */, -1.508571028709 /* ( 2, 3) */, 0.903724849224 /* ( 3, 0) */, 0.490690946579 /* ( 3, 1) */, 0.242906242609 /* ( 3, 2) */, 0.192125678062 /* ( 3, 3) */, 0.053418140858 /* ( 4, 0) */, 0.389735013247 /* ( 4, 1) */, 0.781731247902 /* ( 4, 2) */, -1.207890510559 /* ( 4, 3) */}; // matrixf_data_add_y [size: 5 x 4] float matrixf_data_add_y[] = { -1.569433808327 /* ( 0, 0) */, 0.182892739773 /* ( 0, 1) */, 2.420134067535 /* ( 0, 2) */, -0.114732131362 /* ( 0, 3) */, -1.274159908295 /* ( 1, 0) */, -1.230959534645 /* ( 1, 1) */, 0.574799835682 /* ( 1, 2) */, -0.756966531277 /* ( 1, 3) */, 1.426752924919 /* ( 2, 0) */, 1.018160581589 /* ( 2, 1) */, -0.099268406630 /* ( 2, 2) */, 0.683501064777 /* ( 2, 3) */, 0.145665585995 /* ( 3, 0) */, 0.337123543024 /* ( 3, 1) */, 0.754367768764 /* ( 3, 2) */, 0.908503055573 /* ( 3, 3) */, -1.320610523224 /* ( 4, 0) */, -1.090982913971 /* ( 4, 1) */, 0.494600951672 /* ( 4, 2) */, 0.713486075401 /* ( 4, 3) */}; // matrixf_data_add_z [size: 5 x 4] float matrixf_data_add_z[] = { -3.723292708397 /* ( 0, 0) */, 0.557299107313 /* ( 0, 1) */, 2.063485652208 /* ( 0, 2) */, 0.559189930558 /* ( 0, 3) */, -2.960913181305 /* ( 1, 0) */, -1.613401770592 /* ( 1, 1) */, 0.862108796835 /* ( 1, 2) */, -1.236323416233 /* ( 1, 3) */, 1.090232938528 /* ( 2, 0) */, 1.191981017590 /* ( 2, 1) */, -1.342327684164 /* ( 2, 2) */, -0.825069963932 /* ( 2, 3) */, 1.049390435219 /* ( 3, 0) */, 0.827814489603 /* ( 3, 1) */, 0.997274011374 /* ( 3, 2) */, 1.100628733635 /* ( 3, 3) */, -1.267192382365 /* ( 4, 0) */, -0.701247900724 /* ( 4, 1) */, 1.276332199574 /* ( 4, 2) */, -0.494404435158 /* ( 4, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_aug.c000066400000000000000000000073101474751757600234330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix augmentation // #include // matrixf_data_aug_x [size: 5 x 4] float matrixf_data_aug_x[] = { -0.747572302818 /* ( 0, 0) */, 1.023007512093 /* ( 0, 1) */, -0.806419134140 /* ( 0, 2) */, 1.476346969604 /* ( 0, 3) */, -0.456311076880 /* ( 1, 0) */, 1.049571633339 /* ( 1, 1) */, 0.041211493313 /* ( 1, 2) */, 0.870350718498 /* ( 1, 3) */, -0.585918903351 /* ( 2, 0) */, -2.498867988586 /* ( 2, 1) */, 1.247432827950 /* ( 2, 2) */, -1.840264678001 /* ( 2, 3) */, 0.618996977806 /* ( 3, 0) */, -1.083691835403 /* ( 3, 1) */, -1.827050209045 /* ( 3, 2) */, -0.579039454460 /* ( 3, 3) */, 1.507880568504 /* ( 4, 0) */, 1.633087396622 /* ( 4, 1) */, -0.439950227737 /* ( 4, 2) */, -0.058893665671 /* ( 4, 3) */}; // matrixf_data_aug_y [size: 5 x 3] float matrixf_data_aug_y[] = { 0.376702636480 /* ( 0, 0) */, 0.790158689022 /* ( 0, 1) */, 2.111151933670 /* ( 0, 2) */, -0.690664231777 /* ( 1, 0) */, -0.598035037518 /* ( 1, 1) */, -0.137144193053 /* ( 1, 2) */, 1.078616261482 /* ( 2, 0) */, 0.907722294331 /* ( 2, 1) */, -0.432205766439 /* ( 2, 2) */, -1.615019798279 /* ( 3, 0) */, 0.122782632709 /* ( 3, 1) */, 1.174023866653 /* ( 3, 2) */, 0.233828529716 /* ( 4, 0) */, 0.032883912325 /* ( 4, 1) */, -0.896481394768 /* ( 4, 2) */}; // matrixf_data_aug_z [size: 5 x 7] float matrixf_data_aug_z[] = { -0.747572302818 /* ( 0, 0) */, 1.023007512093 /* ( 0, 1) */, -0.806419134140 /* ( 0, 2) */, 1.476346969604 /* ( 0, 3) */, 0.376702636480 /* ( 0, 4) */, 0.790158689022 /* ( 0, 5) */, 2.111151933670 /* ( 0, 6) */, -0.456311076880 /* ( 1, 0) */, 1.049571633339 /* ( 1, 1) */, 0.041211493313 /* ( 1, 2) */, 0.870350718498 /* ( 1, 3) */, -0.690664231777 /* ( 1, 4) */, -0.598035037518 /* ( 1, 5) */, -0.137144193053 /* ( 1, 6) */, -0.585918903351 /* ( 2, 0) */, -2.498867988586 /* ( 2, 1) */, 1.247432827950 /* ( 2, 2) */, -1.840264678001 /* ( 2, 3) */, 1.078616261482 /* ( 2, 4) */, 0.907722294331 /* ( 2, 5) */, -0.432205766439 /* ( 2, 6) */, 0.618996977806 /* ( 3, 0) */, -1.083691835403 /* ( 3, 1) */, -1.827050209045 /* ( 3, 2) */, -0.579039454460 /* ( 3, 3) */, -1.615019798279 /* ( 3, 4) */, 0.122782632709 /* ( 3, 5) */, 1.174023866653 /* ( 3, 6) */, 1.507880568504 /* ( 4, 0) */, 1.633087396622 /* ( 4, 1) */, -0.439950227737 /* ( 4, 2) */, -0.058893665671 /* ( 4, 3) */, 0.233828529716 /* ( 4, 4) */, 0.032883912325 /* ( 4, 5) */, -0.896481394768 /* ( 4, 6) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_cgsolve.c000066400000000000000000000100721474751757600243200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing conjugate gradient solver // #include // matrixf_data_cgsolve_A [size: 8 x 8] float matrixf_data_cgsolve_A[] = { 12.722920400000 /* ( 0, 0) */, 0.000000000000 /* ( 0, 1) */, -7.952912300000 /* ( 0, 2) */, 0.000000000000 /* ( 0, 3) */, 4.111499800000 /* ( 0, 4) */, 0.000000000000 /* ( 0, 5) */, 0.000000000000 /* ( 0, 6) */, 0.000000000000 /* ( 0, 7) */, 0.000000000000 /* ( 1, 0) */, 0.065151200000 /* ( 1, 1) */, 0.000000000000 /* ( 1, 2) */, -0.218259800000 /* ( 1, 3) */, 0.000000000000 /* ( 1, 4) */, 0.000000000000 /* ( 1, 5) */, 0.000000000000 /* ( 1, 6) */, 0.000000000000 /* ( 1, 7) */, -7.952912300000 /* ( 2, 0) */, 0.000000000000 /* ( 2, 1) */, 5.031585200000 /* ( 2, 2) */, 0.000000000000 /* ( 2, 3) */, -2.570038800000 /* ( 2, 4) */, -0.110545700000 /* ( 2, 5) */, 0.000000000000 /* ( 2, 6) */, 0.000000000000 /* ( 2, 7) */, 0.000000000000 /* ( 3, 0) */, -0.218259800000 /* ( 3, 1) */, 0.000000000000 /* ( 3, 2) */, 0.733045600000 /* ( 3, 3) */, 0.000000000000 /* ( 3, 4) */, 0.000000000000 /* ( 3, 5) */, 0.000000000000 /* ( 3, 6) */, 0.000000000000 /* ( 3, 7) */, 4.111499800000 /* ( 4, 0) */, 0.000000000000 /* ( 4, 1) */, -2.570038800000 /* ( 4, 2) */, 0.000000000000 /* ( 4, 3) */, 1.338132900000 /* ( 4, 4) */, 0.239381000000 /* ( 4, 5) */, 0.078430200000 /* ( 4, 6) */, 0.000000000000 /* ( 4, 7) */, 0.000000000000 /* ( 5, 0) */, 0.000000000000 /* ( 5, 1) */, -0.110545700000 /* ( 5, 2) */, 0.000000000000 /* ( 5, 3) */, 0.239381000000 /* ( 5, 4) */, 7.472388300000 /* ( 5, 5) */, 1.981894700000 /* ( 5, 6) */, -1.373365000000 /* ( 5, 7) */, 0.000000000000 /* ( 6, 0) */, 0.000000000000 /* ( 6, 1) */, 0.000000000000 /* ( 6, 2) */, 0.000000000000 /* ( 6, 3) */, 0.078430200000 /* ( 6, 4) */, 1.981894700000 /* ( 6, 5) */, 3.489272600000 /* ( 6, 6) */, 0.000000000000 /* ( 6, 7) */, 0.000000000000 /* ( 7, 0) */, 0.000000000000 /* ( 7, 1) */, 0.000000000000 /* ( 7, 2) */, 0.000000000000 /* ( 7, 3) */, 0.000000000000 /* ( 7, 4) */, -1.373365000000 /* ( 7, 5) */, 0.000000000000 /* ( 7, 6) */, 2.063114900000 /* ( 7, 7) */}; // matrixf_data_cgsolve_x [size: 8 x 1] float matrixf_data_cgsolve_x[] = { 0.162052200000 /* ( 0, 0) */, -0.012720300000 /* ( 1, 0) */, 1.043375100000 /* ( 2, 0) */, 0.006205200000 /* ( 3, 0) */, 0.878157000000 /* ( 4, 0) */, 0.146412900000 /* ( 5, 0) */, 0.782585200000 /* ( 6, 0) */, -0.825784600000 /* ( 7, 0) */}; // matrixf_data_cgsolve_b [size: 8 x 1] float matrixf_data_cgsolve_b[] = { -2.625551095190 /* ( 0, 0) */, -0.002183088520 /* ( 1, 0) */, 1.687960897575 /* ( 2, 0) */, 0.007325024691 /* ( 3, 0) */, -0.743719348831 /* ( 4, 0) */, 3.874032638311 /* ( 5, 0) */, 3.089702075189 /* ( 6, 0) */, -1.904766864859 /* ( 7, 0) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_chol.c000066400000000000000000000045761474751757600236170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing Cholesky decomposition // #include // matrixf_data_chol_L [size: 4 x 4] float matrixf_data_chol_L[] = { 1.010000000000 /* ( 0, 0) */, 0.000000000000 /* ( 0, 1) */, 0.000000000000 /* ( 0, 2) */, 0.000000000000 /* ( 0, 3) */, -1.420000000000 /* ( 1, 0) */, 0.500000000000 /* ( 1, 1) */, 0.000000000000 /* ( 1, 2) */, 0.000000000000 /* ( 1, 3) */, 0.320000000000 /* ( 2, 0) */, 2.010000000000 /* ( 2, 1) */, 0.300000000000 /* ( 2, 2) */, 0.000000000000 /* ( 2, 3) */, -1.020000000000 /* ( 3, 0) */, -0.320000000000 /* ( 3, 1) */, -1.650000000000 /* ( 3, 2) */, 1.070000000000 /* ( 3, 3) */}; // matrixf_data_chol_A [size: 4 x 4] float matrixf_data_chol_A[] = { 1.020100000000 /* ( 0, 0) */, -1.434200000000 /* ( 0, 1) */, 0.323200000000 /* ( 0, 2) */, -1.030200000000 /* ( 0, 3) */, -1.434200000000 /* ( 1, 0) */, 2.266400000000 /* ( 1, 1) */, 0.550600000000 /* ( 1, 2) */, 1.288400000000 /* ( 1, 3) */, 0.323200000000 /* ( 2, 0) */, 0.550600000000 /* ( 2, 1) */, 4.232500000000 /* ( 2, 2) */, -1.464600000000 /* ( 2, 3) */, -1.030200000000 /* ( 3, 0) */, 1.288400000000 /* ( 3, 1) */, -1.464600000000 /* ( 3, 2) */, 5.010200000000 /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_gramschmidt.c000066400000000000000000000042231474751757600251610ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing Gram-Schmidt orthonormalization // #include // matrixf_data_gramschmidt_A [size: 4 x 3] float matrixf_data_gramschmidt_A[] = { 1.000000000000 /* ( 0, 0) */, 2.000000000000 /* ( 0, 1) */, 1.000000000000 /* ( 0, 2) */, 0.000000000000 /* ( 1, 0) */, 2.000000000000 /* ( 1, 1) */, 0.000000000000 /* ( 1, 2) */, 2.000000000000 /* ( 2, 0) */, 3.000000000000 /* ( 2, 1) */, 1.000000000000 /* ( 2, 2) */, 1.000000000000 /* ( 3, 0) */, 1.000000000000 /* ( 3, 1) */, 0.000000000000 /* ( 3, 2) */}; // matrixf_data_gramschmidt_V [size: 4 x 3] float matrixf_data_gramschmidt_V[] = { 0.408248290464 /* ( 0, 0) */, 0.235702260396 /* ( 0, 1) */, 0.666666666667 /* ( 0, 2) */, 0.000000000000 /* ( 1, 0) */, 0.942809041582 /* ( 1, 1) */, -0.333333333333 /* ( 1, 2) */, 0.816496580928 /* ( 2, 0) */, 0.000000000000 /* ( 2, 1) */, 0.000000000000 /* ( 2, 2) */, 0.408248290464 /* ( 3, 0) */, -0.235702260396 /* ( 3, 1) */, -0.666666666667 /* ( 3, 2) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_inv.c000066400000000000000000000057301474751757600234570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix inversion // #include // matrixf_data_inv_x [size: 5 x 5] float matrixf_data_inv_x[] = { 0.145655393600 /* ( 0, 0) */, -2.292126655579 /* ( 0, 1) */, 0.928358852863 /* ( 0, 2) */, 0.995244622231 /* ( 0, 3) */, -0.719965457916 /* ( 0, 4) */, 1.625229239464 /* ( 1, 0) */, 1.179069876671 /* ( 1, 1) */, 0.023814691231 /* ( 1, 2) */, -0.458529949188 /* ( 1, 3) */, 0.870123147964 /* ( 1, 4) */, 1.599076509476 /* ( 2, 0) */, 1.012132167816 /* ( 2, 1) */, 0.240342438221 /* ( 2, 2) */, -0.663878023624 /* ( 2, 3) */, 1.523158550262 /* ( 2, 4) */, 1.400263786316 /* ( 3, 0) */, -0.016515849158 /* ( 3, 1) */, 0.525676131248 /* ( 3, 2) */, -0.526886940002 /* ( 3, 3) */, -0.605886101723 /* ( 3, 4) */, -0.291201651096 /* ( 4, 0) */, 0.635409533978 /* ( 4, 1) */, 0.016531571746 /* ( 4, 2) */, 0.113017730415 /* ( 4, 3) */, -0.886025428772 /* ( 4, 4) */}; // matrixf_data_inv_y [size: 5 x 5] float matrixf_data_inv_y[] = { 0.123047731616 /* ( 0, 0) */, 1.264793339850 /* ( 0, 1) */, -0.888020214878 /* ( 0, 2) */, 0.146648698334 /* ( 0, 3) */, -0.484762774689 /* ( 0, 4) */, 0.031615676756 /* ( 1, 0) */, -0.041217620573 /* ( 1, 1) */, 0.486809371567 /* ( 1, 2) */, -0.307386761818 /* ( 1, 3) */, 0.980900315396 /* ( 1, 4) */, 0.456515830075 /* ( 2, 0) */, -2.168499777786 /* ( 2, 1) */, 2.469455722213 /* ( 2, 2) */, 0.010642598564 /* ( 2, 3) */, 1.737407148356 /* ( 2, 4) */, 0.690799395919 /* ( 3, 0) */, 1.532809684521 /* ( 3, 1) */, -0.611813824735 /* ( 3, 2) */, -1.028413056396 /* ( 3, 3) */, 0.595460566672 /* ( 3, 4) */, 0.078865348162 /* ( 4, 0) */, -0.290188077617 /* ( 4, 1) */, 0.609005594780 /* ( 4, 2) */, -0.399620351004 /* ( 4, 3) */, -0.157493442155 /* ( 4, 4) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_linsolve.c000066400000000000000000000050721474751757600245150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing linear solver // #include // matrixf_data_linsolve_A [size: 5 x 5] float matrixf_data_linsolve_A[] = { 0.359868824482 /* ( 0, 0) */, -0.821193814278 /* ( 0, 1) */, -0.267460018396 /* ( 0, 2) */, 0.886115014553 /* ( 0, 3) */, 0.153591111302 /* ( 0, 4) */, 0.298885852098 /* ( 1, 0) */, -1.239024162292 /* ( 1, 1) */, -0.948822617531 /* ( 1, 2) */, -0.779868483543 /* ( 1, 3) */, -0.334943383932 /* ( 1, 4) */, -0.071195065975 /* ( 2, 0) */, 0.763968944550 /* ( 2, 1) */, 0.294695496559 /* ( 2, 2) */, 0.060610540211 /* ( 2, 3) */, 0.016189640388 /* ( 2, 4) */, 1.150504231453 /* ( 3, 0) */, -0.605459213257 /* ( 3, 1) */, 0.055004067719 /* ( 3, 2) */, 1.185544967651 /* ( 3, 3) */, 0.555612862110 /* ( 3, 4) */, 1.054118633270 /* ( 4, 0) */, -0.494105964899 /* ( 4, 1) */, -0.824876368046 /* ( 4, 2) */, 0.667240202427 /* ( 4, 3) */, 1.367745161057 /* ( 4, 4) */}; // matrixf_data_linsolve_x [size: 5 x 1] float matrixf_data_linsolve_x[] = { -0.848446607590 /* ( 0, 0) */, 1.041861057281 /* ( 1, 0) */, 0.453321367502 /* ( 2, 0) */, -0.949143886566 /* ( 3, 0) */, 1.200846910477 /* ( 4, 0) */}; // matrixf_data_linsolve_b [size: 5 x 1] float matrixf_data_linsolve_b[] = { -1.938755917550 /* ( 0, 0) */, -1.636609601788 /* ( 1, 0) */, 0.951859625938 /* ( 2, 0) */, -2.040058038471 /* ( 3, 0) */, -0.773941632607 /* ( 4, 0) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_ludecomp.c000066400000000000000000000065721474751757600245000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing L/U decomposition // #include // matrixf_data_ludecomp_A [size: 8 x 8] float matrixf_data_ludecomp_A[] = { 0.936903119087 /* ( 0, 0) */, 1.048182249069 /* ( 0, 1) */, 0.464600890875 /* ( 0, 2) */, 1.122355699539 /* ( 0, 3) */, -0.661124527454 /* ( 0, 4) */, -0.953127145767 /* ( 0, 5) */, -0.759313285351 /* ( 0, 6) */, 1.418183445930 /* ( 0, 7) */, -0.272643178701 /* ( 1, 0) */, -1.166662335396 /* ( 1, 1) */, 1.556591391563 /* ( 1, 2) */, -0.323065608740 /* ( 1, 3) */, -0.267991930246 /* ( 1, 4) */, 0.396302074194 /* ( 1, 5) */, 0.238355115056 /* ( 1, 6) */, -0.437593698502 /* ( 1, 7) */, 0.431114047766 /* ( 2, 0) */, -0.916567981243 /* ( 2, 1) */, 0.108782351017 /* ( 2, 2) */, -0.714223206043 /* ( 2, 3) */, 0.197309300303 /* ( 2, 4) */, 1.105972766876 /* ( 2, 5) */, -0.014590717852 /* ( 2, 6) */, 0.288964867592 /* ( 2, 7) */, 1.536642432213 /* ( 3, 0) */, 1.810190558434 /* ( 3, 1) */, 0.722570478916 /* ( 3, 2) */, 0.184841006994 /* ( 3, 3) */, -0.239855647087 /* ( 3, 4) */, 0.494688391685 /* ( 3, 5) */, -0.372100114822 /* ( 3, 6) */, -0.754012823105 /* ( 3, 7) */, 0.139140784740 /* ( 4, 0) */, -0.755531311035 /* ( 4, 1) */, 1.567769289017 /* ( 4, 2) */, -0.774845600128 /* ( 4, 3) */, 1.536481976509 /* ( 4, 4) */, -1.498587012291 /* ( 4, 5) */, 0.262655615807 /* ( 4, 6) */, -1.045227766037 /* ( 4, 7) */, 0.445236086845 /* ( 5, 0) */, -0.573900520802 /* ( 5, 1) */, 0.550646543503 /* ( 5, 2) */, 0.073093712330 /* ( 5, 3) */, 0.700358152390 /* ( 5, 4) */, 0.659417688847 /* ( 5, 5) */, 0.990632474422 /* ( 5, 6) */, -0.596979260445 /* ( 5, 7) */, -1.469601035118 /* ( 6, 0) */, -1.366319775581 /* ( 6, 1) */, -1.536668300629 /* ( 6, 2) */, 0.301474511623 /* ( 6, 3) */, 0.205486327410 /* ( 6, 4) */, 1.184612751007 /* ( 6, 5) */, 1.984294533730 /* ( 6, 6) */, 0.846946001053 /* ( 6, 7) */, -0.780786097050 /* ( 7, 0) */, -1.778358221054 /* ( 7, 1) */, -0.621561229229 /* ( 7, 2) */, 0.809134125710 /* ( 7, 3) */, -0.395780056715 /* ( 7, 4) */, 0.095775716007 /* ( 7, 5) */, 1.116999864578 /* ( 7, 6) */, -0.937837302685 /* ( 7, 7) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_mul.c000066400000000000000000000056741474751757600234670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing matrix multiplication // #include // matrixf_data_mul_x [size: 5 x 4] float matrixf_data_mul_x[] = { -0.348304957151 /* ( 0, 0) */, 1.638695955276 /* ( 0, 1) */, 0.618153512478 /* ( 0, 2) */, 0.580581486225 /* ( 0, 3) */, 1.125966548920 /* ( 1, 0) */, 0.590879321098 /* ( 1, 1) */, -0.499333083630 /* ( 1, 2) */, -0.144607886672 /* ( 1, 3) */, -0.169909551740 /* ( 2, 0) */, 1.626509308815 /* ( 2, 1) */, -0.776567280293 /* ( 2, 2) */, -1.341656446457 /* ( 2, 3) */, 0.492572665215 /* ( 3, 0) */, -0.075633287430 /* ( 3, 1) */, 1.035362601280 /* ( 3, 2) */, 0.842321217060 /* ( 3, 3) */, -0.209287241101 /* ( 4, 0) */, -0.789002001286 /* ( 4, 1) */, -0.397730469704 /* ( 4, 2) */, 0.034179374576 /* ( 4, 3) */}; // matrixf_data_mul_y [size: 4 x 3] float matrixf_data_mul_y[] = { 0.445414155722 /* ( 0, 0) */, 0.233421698213 /* ( 0, 1) */, -0.682938814163 /* ( 0, 2) */, -0.934787094593 /* ( 1, 0) */, 0.500407993793 /* ( 1, 1) */, -0.053248234093 /* ( 1, 2) */, -0.784089267254 /* ( 2, 0) */, 0.127269089222 /* ( 2, 1) */, -0.477077603340 /* ( 2, 2) */, -0.105383664370 /* ( 3, 0) */, -1.556528329849 /* ( 3, 1) */, -0.184585332870 /* ( 3, 2) */}; // matrixf_data_mul_z [size: 5 x 3] float matrixf_data_mul_z[] = { -2.232843128510 /* ( 0, 0) */, -0.086305075740 /* ( 0, 1) */, -0.251460714553 /* ( 0, 2) */, 0.355936096586 /* ( 1, 0) */, 0.720042365177 /* ( 1, 1) */, -0.535516414414 /* ( 1, 2) */, -0.845833288222 /* ( 2, 0) */, 2.763750941354 /* ( 2, 1) */, 0.647562038031 /* ( 2, 2) */, -0.610483740991 /* ( 3, 0) */, -1.102197535527 /* ( 3, 1) */, -0.981798103518 /* ( 3, 2) */, 0.952583633427 /* ( 4, 0) */, -0.547495051253 /* ( 4, 1) */, 0.368382631550 /* ( 4, 2) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_qrdecomp.c000066400000000000000000000057701474751757600245010ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing Q/R decomposition // #include // matrixf_data_qrdecomp_A [size: 4 x 4] float matrixf_data_qrdecomp_A[] = { 1.000000000000 /* ( 0, 0) */, 2.000000000000 /* ( 0, 1) */, 3.000000000000 /* ( 0, 2) */, 4.000000000000 /* ( 0, 3) */, 5.000000000000 /* ( 1, 0) */, 5.000000000000 /* ( 1, 1) */, 7.000000000000 /* ( 1, 2) */, 8.000000000000 /* ( 1, 3) */, 6.000000000000 /* ( 2, 0) */, 4.000000000000 /* ( 2, 1) */, 8.000000000000 /* ( 2, 2) */, 7.000000000000 /* ( 2, 3) */, 1.000000000000 /* ( 3, 0) */, 0.000000000000 /* ( 3, 1) */, 3.000000000000 /* ( 3, 2) */, 1.000000000000 /* ( 3, 3) */}; // matrixf_data_qrdecomp_Q [size: 4 x 4] float matrixf_data_qrdecomp_Q[] = { 0.125988157670 /* ( 0, 0) */, 0.617707763884 /* ( 0, 1) */, 0.571886263590 /* ( 0, 2) */, 0.524890659168 /* ( 0, 3) */, 0.629940788349 /* ( 1, 0) */, 0.494166211107 /* ( 1, 1) */, -0.137252703262 /* ( 1, 2) */, -0.583211843520 /* ( 1, 3) */, 0.755928946018 /* ( 2, 0) */, -0.444749589997 /* ( 2, 1) */, -0.114377252718 /* ( 2, 2) */, 0.466569474816 /* ( 2, 3) */, 0.125988157670 /* ( 3, 0) */, -0.420041279441 /* ( 3, 1) */, 0.800640769025 /* ( 3, 2) */, -0.408248290464 /* ( 3, 3) */}; // matrixf_data_qrdecomp_R [size: 4 x 4] float matrixf_data_qrdecomp_R[] = { 7.937253933194 /* ( 0, 0) */, 6.425396041157 /* ( 0, 1) */, 11.212946032607 /* ( 0, 2) */, 10.960969717268 /* ( 0, 3) */, 0.000000000000 /* ( 1, 0) */, 1.927248223319 /* ( 1, 1) */, 0.494166211107 /* ( 1, 2) */, 2.890872334978 /* ( 1, 3) */, 0.000000000000 /* ( 2, 0) */, 0.000000000000 /* ( 2, 1) */, 2.241794153271 /* ( 2, 2) */, 1.189523428266 /* ( 2, 3) */, 0.000000000000 /* ( 3, 0) */, 0.000000000000 /* ( 3, 1) */, 0.000000000000 /* ( 3, 2) */, 0.291605921760 /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/data/matrixf_data_transmul.c000066400000000000000000000117231474751757600245270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // data for testing multiply/transpose // #include // matrixf_data_transmul_x [size: 5 x 4] float matrixf_data_transmul_x[] = { 1.366575479507 /* ( 0, 0) */, 1.982354640961 /* ( 0, 1) */, 0.913504719734 /* ( 0, 2) */, 0.671039104462 /* ( 0, 3) */, 0.264611721039 /* ( 1, 0) */, 0.995791137218 /* ( 1, 1) */, -1.983934879303 /* ( 1, 2) */, -0.375840932131 /* ( 1, 3) */, 0.245937779546 /* ( 2, 0) */, -0.343152791262 /* ( 2, 1) */, -0.143777698278 /* ( 2, 2) */, -1.387172579765 /* ( 2, 3) */, 0.781192481518 /* ( 3, 0) */, 1.444583415985 /* ( 3, 1) */, 0.043851174414 /* ( 3, 2) */, 0.399744838476 /* ( 3, 3) */, -0.488068610430 /* ( 4, 0) */, 0.573721885681 /* ( 4, 1) */, -1.381630182266 /* ( 4, 2) */, -0.176615595818 /* ( 4, 3) */}; // matrixf_data_transmul_xxT [size: 5 x 5] float matrixf_data_transmul_xxT[] = { 7.082042816423 /* ( 0, 0) */, 0.271085233449 /* ( 0, 1) */, -1.406346640934 /* ( 0, 2) */, 4.239537802168 /* ( 0, 3) */, -0.910304016309 /* ( 0, 4) */, 0.271085233449 /* ( 1, 0) */, 5.138873363454 /* ( 1, 1) */, 0.529971336750 /* ( 1, 2) */, 1.407977702482 /* ( 1, 3) */, 3.249602173055 /* ( 1, 4) */, -1.406346640934 /* ( 2, 0) */, 0.529971336750 /* ( 2, 1) */, 2.123159022134 /* ( 2, 2) */, -0.864407986864 /* ( 2, 3) */, 0.126735142361 /* ( 2, 4) */, 4.239537802168 /* ( 3, 0) */, 1.407977702482 /* ( 3, 1) */, -0.864407986864 /* ( 3, 2) */, 2.858801800305 /* ( 3, 3) */, 0.316326313589 /* ( 3, 4) */, -0.910304016309 /* ( 4, 0) */, 3.249602173055 /* ( 4, 1) */, 0.126735142361 /* ( 4, 2) */, 0.316326313589 /* ( 4, 3) */, 2.507462799831 /* ( 4, 4) */}; // matrixf_data_transmul_xxH [size: 5 x 5] float matrixf_data_transmul_xxH[] = { 7.082042816423 /* ( 0, 0) */, 0.271085233449 /* ( 0, 1) */, -1.406346640934 /* ( 0, 2) */, 4.239537802168 /* ( 0, 3) */, -0.910304016309 /* ( 0, 4) */, 0.271085233449 /* ( 1, 0) */, 5.138873363454 /* ( 1, 1) */, 0.529971336750 /* ( 1, 2) */, 1.407977702482 /* ( 1, 3) */, 3.249602173055 /* ( 1, 4) */, -1.406346640934 /* ( 2, 0) */, 0.529971336750 /* ( 2, 1) */, 2.123159022134 /* ( 2, 2) */, -0.864407986864 /* ( 2, 3) */, 0.126735142361 /* ( 2, 4) */, 4.239537802168 /* ( 3, 0) */, 1.407977702482 /* ( 3, 1) */, -0.864407986864 /* ( 3, 2) */, 2.858801800305 /* ( 3, 3) */, 0.316326313589 /* ( 3, 4) */, -0.910304016309 /* ( 4, 0) */, 3.249602173055 /* ( 4, 1) */, 0.126735142361 /* ( 4, 2) */, 0.316326313589 /* ( 4, 3) */, 2.507462799831 /* ( 4, 4) */}; // matrixf_data_transmul_xTx [size: 4 x 4] float matrixf_data_transmul_xTx[] = { 2.846505957177 /* ( 0, 0) */, 3.736623075087 /* ( 0, 1) */, 1.396626890644 /* ( 0, 2) */, 0.874893716720 /* ( 0, 3) */, 3.736623075087 /* ( 1, 0) */, 7.455061797501 /* ( 1, 1) */, -0.844681524592 /* ( 1, 2) */, 1.908127088099 /* ( 1, 3) */, 1.396626890644 /* ( 2, 0) */, -0.844681524592 /* ( 2, 1) */, 6.701985390860 /* ( 2, 2) */, 1.819632522483 /* ( 2, 3) */, 0.874893716720 /* ( 3, 0) */, 1.908127088099 /* ( 3, 1) */, 1.819632522483 /* ( 3, 2) */, 2.706786656609 /* ( 3, 3) */}; // matrixf_data_transmul_xHx [size: 4 x 4] float matrixf_data_transmul_xHx[] = { 2.846505957177 /* ( 0, 0) */, 3.736623075087 /* ( 0, 1) */, 1.396626890644 /* ( 0, 2) */, 0.874893716720 /* ( 0, 3) */, 3.736623075087 /* ( 1, 0) */, 7.455061797501 /* ( 1, 1) */, -0.844681524592 /* ( 1, 2) */, 1.908127088099 /* ( 1, 3) */, 1.396626890644 /* ( 2, 0) */, -0.844681524592 /* ( 2, 1) */, 6.701985390860 /* ( 2, 2) */, 1.819632522483 /* ( 2, 3) */, 0.874893716720 /* ( 3, 0) */, 1.908127088099 /* ( 3, 1) */, 1.819632522483 /* ( 3, 2) */, 2.706786656609 /* ( 3, 3) */}; liquid-dsp-1.7.0/src/matrix/tests/gendata_write_autotests.m000066400000000000000000000224471474751757600241750ustar00rootroot00000000000000% % Write matrix autotest data % clear all; close all; % global options dirname = 'data/'; % output directory name randn('seed',0.0); % set random seed for normal distribution rand('seed',0.0); % set random seed for uniform distribution % % real floating-point data % % % matrix_add % x = randn(5,4); y = randn(5,4); z = x + y; basename = 'matrixf_data_add'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix addition'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_aug % x = randn(5,4); y = randn(5,3); z = [x y]; basename = 'matrixf_data_aug'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix augmentation'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_cgsolve % A = [ 12.7229204 0.0000000 -7.9529123 0.0000000 4.1114998 0.0000000 0.0000000 0.0000000 0.0000000 0.0651512 0.0000000 -0.2182598 0.0000000 0.0000000 0.0000000 0.0000000 -7.9529123 0.0000000 5.0315852 0.0000000 -2.5700388 -0.1105457 0.0000000 0.0000000 0.0000000 -0.2182598 0.0000000 0.7330456 0.0000000 0.0000000 0.0000000 0.0000000 4.1114998 0.0000000 -2.5700388 0.0000000 1.3381329 0.2393810 0.0784302 0.0000000 0.0000000 0.0000000 -0.1105457 0.0000000 0.2393810 7.4723883 1.9818947 -1.3733650 0.0000000 0.0000000 0.0000000 0.0000000 0.0784302 1.9818947 3.4892726 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 -1.3733650 0.0000000 2.0631149]; x = [ 0.1620522 -0.0127203 1.0433751 0.0062052 0.8781570 0.1464129 0.7825852 -0.8257846]; b = A*x; basename = 'matrixf_data_cgsolve'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing conjugate gradient solver'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,b,[basename '_b']); fclose(fid); % % matrix_chol % L = [ 1.01, 0, 0, 0; -1.42, 0.5, 0, 0; 0.32, 2.01, 0.3, 0; -1.02, -0.32, -1.65, 1.07]; A = L * L'; basename = 'matrixf_data_chol'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing Cholesky decomposition'); gendata_write_matrix(fid,L,[basename '_L']); gendata_write_matrix(fid,A,[basename '_A']); fclose(fid); % % matrix_gramschmidt % A = [1 2 1; 0 2 0; 2 3 1; 1 1 0]; V = [sqrt(6)/6, sqrt(2)/6, 2/3 ; 0 2*sqrt(2)/3, -1/3 ; sqrt(6)/3, 0, 0 ; sqrt(6)/6, -sqrt(2)/6, -2/3 ]; basename = 'matrixf_data_gramschmidt'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing Gram-Schmidt orthonormalization'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,V,[basename '_V']); fclose(fid); % % matrix_inv % x = randn(5,5); y = inv(x); basename = 'matrixf_data_inv'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix inversion'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); fclose(fid); % % matrix_linsolve % A = randn(5,5); x = randn(5,1); b = A*x; basename = 'matrixf_data_linsolve'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing linear solver'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,b,[basename '_b']); fclose(fid); % % matrix_ludecomp % A = randn(8,8); basename = 'matrixf_data_ludecomp'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing L/U decomposition'); gendata_write_matrix(fid,A,[basename '_A']); fclose(fid); % % matrix_mul % x = randn(5,4); y = randn(4,3); z = x*y; basename = 'matrixf_data_mul'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix multiplication'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_qrdecomp % A = [1 2 3 4; 5 5 7 8; 6 4 8 7; 1 0 3 1]; [Q R] = qr(A); basename = 'matrixf_data_qrdecomp'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing Q/R decomposition'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,Q,[basename '_Q']); gendata_write_matrix(fid,R,[basename '_R']); fclose(fid); % % matrix_transmul % % transpose_mul % hermitian_mul % mul_transpose % mul_hermitian % x = randn(5,4); xxT = x * x'; xxH = x * x.'; xTx = x' * x; xHx = x.' * x; basename = 'matrixf_data_transmul'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing multiply/transpose'); gendata_write_matrix(fid,x, [basename '_x']); gendata_write_matrix(fid,xxT,[basename '_xxT']); gendata_write_matrix(fid,xxH,[basename '_xxH']); gendata_write_matrix(fid,xTx,[basename '_xTx']); gendata_write_matrix(fid,xHx,[basename '_xHx']); fclose(fid); % % complex floating-point data % % % matrix_add % x = randn(5,4) + j*randn(5,4); y = randn(5,4) + j*randn(5,4); z = x + y; basename = 'matrixcf_data_add'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix addition'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_aug % x = randn(5,4) + j*randn(5,4); y = randn(5,3) + j*randn(5,3); z = [x y]; basename = 'matrixcf_data_aug'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix augmentation'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_chol % L = [ 1.01, 0, 0, 0; -1.42+0.25j, 0.5, 0, 0; 0.32-1.23j, 2.01+0.78j, 0.3, 0; -1.02+1.02j,-0.32-0.03j,-1.65+2.01j, 1.07]; A = L * L'; basename = 'matrixcf_data_chol'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing Cholesky decomposition'); gendata_write_matrix(fid,L,[basename '_L']); gendata_write_matrix(fid,A,[basename '_A']); fclose(fid); % % matrix_inv % x = randn(5,5) +j*randn(5,5); y = inv(x); basename = 'matrixcf_data_inv'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix inversion'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); fclose(fid); % % matrix_linsolve % A = randn(5,5) + j*randn(5,5); x = randn(5,1) + j*randn(5,1); b = A*x; basename = 'matrixcf_data_linsolve'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing linear solver'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,b,[basename '_b']); fclose(fid); % % matrix_ludecomp % A = randn(8,8) + j*randn(8,8); basename = 'matrixcf_data_ludecomp'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing L/U decomposition'); gendata_write_matrix(fid,A,[basename '_A']); fclose(fid); % % matrix_mul % x = randn(5,4) + j*randn(5,4); y = randn(4,3) + j*randn(4,3); z = x*y; basename = 'matrixcf_data_mul'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing matrix multiplication'); gendata_write_matrix(fid,x,[basename '_x']); gendata_write_matrix(fid,y,[basename '_y']); gendata_write_matrix(fid,z,[basename '_z']); fclose(fid); % % matrix_qrdecomp % A = [ 2.11402 - 0.57604i, 0.41750 + 1.00833i, -0.96264 - 3.62196i, -0.20679 - 1.02668i, 0.00854 + 1.61626i, 0.84695 - 0.32736i, -1.01862 - 1.10786i, -1.78877 + 1.84456i, -2.97901 - 1.30384i, 0.52289 + 1.89110i, 1.32576 - 0.36737i, 0.04717 + 0.20628i, 0.28970 + 0.64247i, -0.55916 + 0.68302i, 1.40615 + 0.62398i, -0.12767 - 0.53997i]; [Q R] = qr(A); basename = 'matrixcf_data_qrdecomp'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing Q/R decomposition'); gendata_write_matrix(fid,A,[basename '_A']); gendata_write_matrix(fid,Q,[basename '_Q']); gendata_write_matrix(fid,R,[basename '_R']); fclose(fid); % % matrix_transmul % % transpose_mul % hermitian_mul % mul_transpose % mul_hermitian % x = randn(5,4) + j*randn(5,4); xxT = x * x'; xxH = x * x.'; xTx = x' * x; xHx = x.' * x; basename = 'matrixcf_data_transmul'; filename = [dirname basename '.c']; fid = fopen(filename,'w'); gendata_write_header(fid,'data for testing multiply/transpose'); gendata_write_matrix(fid,x, [basename '_x']); gendata_write_matrix(fid,xxT,[basename '_xxT']); gendata_write_matrix(fid,xxH,[basename '_xxH']); gendata_write_matrix(fid,xTx,[basename '_xTx']); gendata_write_matrix(fid,xHx,[basename '_xHx']); fclose(fid); liquid-dsp-1.7.0/src/matrix/tests/gendata_write_header.m000066400000000000000000000035221474751757600233630ustar00rootroot00000000000000% % write_header(fid,comment) % % write copyright and header to file descriptor 'fid' with optional comment % function gendata_write_header(fid,comment) if nargin < 2, comment = 'auto-generated data file'; end; fprintf(fid,'/* Copyright (c) 2007 - 2015 Joseph Gaeddert\n'); fprintf(fid,' *\n'); fprintf(fid,' * Permission is hereby granted, free of charge, to any person obtaining a copy\n'); fprintf(fid,' * of this software and associated documentation files (the "Software"), to deal\n'); fprintf(fid,' * in the Software without restriction, including without limitation the rights\n'); fprintf(fid,' * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n'); fprintf(fid,' * copies of the Software, and to permit persons to whom the Software is\n'); fprintf(fid,' * furnished to do so, subject to the following conditions:\n'); fprintf(fid,' * \n'); fprintf(fid,' * The above copyright notice and this permission notice shall be included in\n'); fprintf(fid,' * all copies or substantial portions of the Software.\n'); fprintf(fid,' *\n'); fprintf(fid,' * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n'); fprintf(fid,' * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n'); fprintf(fid,' * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n'); fprintf(fid,' * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n'); fprintf(fid,' * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n'); fprintf(fid,' * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n'); fprintf(fid,' * THE SOFTWARE.\n'); fprintf(fid,' */\n'); fprintf(fid,'\n'); fprintf(fid,'//\n'); fprintf(fid,'// %s\n', comment); fprintf(fid,'//\n'); fprintf(fid,'\n'); fprintf(fid,'#include \n'); fprintf(fid,'\n'); liquid-dsp-1.7.0/src/matrix/tests/gendata_write_matrix.m000066400000000000000000000027021474751757600234360ustar00rootroot00000000000000% % write_matrix(fid,x,comment) % % write matrix 'x' to file descriptor 'fid' with optional comment % function gendata_write_matrix(fid,x,varname,comment) if nargin < 3, error('must specify output file descriptor, input matrix, and variable name'); elseif nargin < 4, comment = varname; end; % other options one_line_per_element = 1; % display one line per element? print_index_as_comment = 1; % print index of element as comment? % get size of matrix [rows cols] = size(x); % even though matrix might have two dimensions, we store it as % a one-dimensional array n = rows*cols; % determine if matrix is complex or not if iscomplex(x), type = 'float complex'; else, type = 'float'; end; % write array comment fprintf(fid,'// %s [size: %u x %u]\n', comment, rows, cols); % write variable declaration fprintf(fid,'%s %s[] = {\n',type, varname); % write array data n=0; for r=1:rows, for c=1:cols, n = n+1; if iscomplex(x), fprintf(fid,' %16.12f + %16.12f*_Complex_I', real(x(r,c)), imag(x(r,c))); else, fprintf(fid,' %16.12f', real(x(r,c))); end; if print_index_as_comment, fprintf(fid,' /* (%2u,%2u) */', r-1, c-1); end; if r==rows && c==cols, fprintf(fid,'};\n'); elseif c==cols || one_line_per_element, fprintf(fid,',\n'); else, fprintf(fid,', '); end; end; end; fprintf(fid,'\n'); liquid-dsp-1.7.0/src/matrix/tests/matrix_data.h000066400000000000000000000075151474751757600215340ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest matrix data definitions // #ifndef __LIQUID_MATRIX_DATA_H__ #define __LIQUID_MATRIX_DATA_H__ // // single-precision real floating-point data // // add extern float matrixf_data_add_x[]; extern float matrixf_data_add_y[]; extern float matrixf_data_add_z[]; // aug extern float matrixf_data_aug_x[]; extern float matrixf_data_aug_y[]; extern float matrixf_data_aug_z[]; // cgsolve extern float matrixf_data_cgsolve_A[]; extern float matrixf_data_cgsolve_x[]; extern float matrixf_data_cgsolve_b[]; // chol extern float matrixf_data_chol_A[]; extern float matrixf_data_chol_L[]; // gramschmidt extern float matrixf_data_gramschmidt_A[]; extern float matrixf_data_gramschmidt_V[]; // inv extern float matrixf_data_inv_x[]; extern float matrixf_data_inv_y[]; // linsolve extern float matrixf_data_linsolve_A[]; extern float matrixf_data_linsolve_x[]; extern float matrixf_data_linsolve_b[]; // ludecomp extern float matrixf_data_ludecomp_A[]; // mul extern float matrixf_data_mul_x[]; extern float matrixf_data_mul_y[]; extern float matrixf_data_mul_z[]; // qrdecomp extern float matrixf_data_qrdecomp_A[]; extern float matrixf_data_qrdecomp_Q[]; extern float matrixf_data_qrdecomp_R[]; // transmul extern float matrixf_data_transmul_x[]; extern float matrixf_data_transmul_xxT[]; extern float matrixf_data_transmul_xxH[]; extern float matrixf_data_transmul_xTx[]; extern float matrixf_data_transmul_xHx[]; // // single-precision complex floating-point data // // add extern float complex matrixcf_data_add_x[]; extern float complex matrixcf_data_add_y[]; extern float complex matrixcf_data_add_z[]; // aug extern float complex matrixcf_data_aug_x[]; extern float complex matrixcf_data_aug_y[]; extern float complex matrixcf_data_aug_z[]; // chol extern float complex matrixcf_data_chol_A[]; extern float complex matrixcf_data_chol_L[]; // inv extern float complex matrixcf_data_inv_x[]; extern float complex matrixcf_data_inv_y[]; // linsolve extern float complex matrixcf_data_linsolve_A[]; extern float complex matrixcf_data_linsolve_x[]; extern float complex matrixcf_data_linsolve_b[]; // ludecomp extern float complex matrixcf_data_ludecomp_A[]; // mul extern float complex matrixcf_data_mul_x[]; extern float complex matrixcf_data_mul_y[]; extern float complex matrixcf_data_mul_z[]; // qrdecomp extern float complex matrixcf_data_qrdecomp_A[]; extern float complex matrixcf_data_qrdecomp_Q[]; extern float complex matrixcf_data_qrdecomp_R[]; // transmul extern float complex matrixcf_data_transmul_x[]; extern float complex matrixcf_data_transmul_xxT[]; extern float complex matrixcf_data_transmul_xxH[]; extern float complex matrixcf_data_transmul_xTx[]; extern float complex matrixcf_data_transmul_xHx[]; #endif // __LIQUID_MATRIX_DATA_H__ liquid-dsp-1.7.0/src/matrix/tests/matrixcf_autotest.c000066400000000000000000000327501474751757600227760ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/matrix/tests/matrix_data.h" // test matrix addition void autotest_matrixcf_add() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 5 x 4] // z [size: 5 x 4] float complex z[20]; matrixcf_add(matrixcf_data_add_x, matrixcf_data_add_y, z, 5, 4); unsigned int i; for (i=0; i<20; i++) { CONTEND_DELTA( crealf(matrixcf_data_add_z[i]), crealf(z[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_add_z[i]), cimagf(z[i]), tol ); } } // test matrix augmentation void autotest_matrixcf_aug() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 5 x 3] // z [size: 5 x 7] float complex z[35]; matrixcf_aug(matrixcf_data_aug_x, 5, 4, matrixcf_data_aug_y, 5, 3, z, 5, 7); // print result if (liquid_autotest_verbose) { printf("augment:\n"); printf(" x: "); matrixcf_print(matrixcf_data_aug_x, 5, 4); printf(" y: "); matrixcf_print(matrixcf_data_aug_y, 5, 3); printf(" expected: "); matrixcf_print(matrixcf_data_aug_z, 5, 7); printf(" z: "); matrixcf_print(z,5,3); } unsigned int i; for (i=0; i<35; i++) { CONTEND_DELTA( crealf(matrixcf_data_aug_z[i]), crealf(z[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_aug_z[i]), cimagf(z[i]), tol ); } } // Cholesky decomposition void autotest_matrixcf_chol() { float tol = 1e-3f; // error tolerance // A [size: 4 x 4] // L [size: 4 x 4] float complex L[16]; // run decomposition matrixcf_chol(matrixcf_data_chol_A, 4, L); if (liquid_autotest_verbose) { printf("chol:\n"); printf(" A: "); matrixcf_print(matrixcf_data_chol_A, 4, 4); printf(" expected: "); matrixcf_print(matrixcf_data_chol_L, 4, 4); printf(" L: "); matrixcf_print(L, 4, 4); } unsigned int i; for (i=0; i<16; i++) { CONTEND_DELTA( crealf(matrixcf_data_chol_L[i]), crealf(L[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_chol_L[i]), cimagf(L[i]), tol ); } } // matrix inversion void autotest_matrixcf_inv() { float tol = 1e-6f; // error tolerance // x [size: 5 x 5] // y [size: 5 x 5] float complex y[25]; memmove(y, matrixcf_data_inv_x, 5*5*sizeof(float complex)); matrixcf_inv(y, 5, 5); if (liquid_autotest_verbose) { printf("inv:\n"); printf(" x: "); matrixcf_print(matrixcf_data_inv_x, 5, 5); printf(" expected: "); matrixcf_print(matrixcf_data_inv_y, 5, 5); printf(" y: "); matrixcf_print(y, 5, 5); } unsigned int i; for (i=0; i<25; i++) { CONTEND_DELTA( crealf(matrixcf_data_inv_y[i]), crealf(y[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_inv_y[i]), cimagf(y[i]), tol ); } } // linsolve (solve linear system of equations) void autotest_matrixcf_linsolve() { float tol = 1e-6f; // error tolerance // A [size: 5 x 5] // x [size: 5 x 1] // b [size: 5 x 1] float complex x[5]; // run solver matrixcf_linsolve(matrixcf_data_linsolve_A, 5, matrixcf_data_linsolve_b, x, NULL); if (liquid_autotest_verbose) { printf("linsolve:\n"); printf(" A: "); matrixcf_print(matrixcf_data_linsolve_A, 5, 5); printf(" b: "); matrixcf_print(matrixcf_data_linsolve_b, 5, 1); printf(" expected: "); matrixcf_print(matrixcf_data_linsolve_x, 5, 1); printf(" x: "); matrixcf_print(x, 5, 1); } unsigned int i; for (i=0; i<5; i++) { CONTEND_DELTA( crealf(matrixcf_data_linsolve_x[i]), crealf(x[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_linsolve_x[i]), cimagf(x[i]), tol ); } } // L/U decomp (Crout) void autotest_matrixcf_ludecomp_crout() { float tol = 1e-5f; // error tolerance float complex L[64]; float complex U[64]; float complex P[64]; float complex LU_test[64]; // run decomposition matrixcf_ludecomp_crout(matrixcf_data_ludecomp_A, 8, 8, L, U, P); // multiply LU matrixcf_mul(L, 8, 8, U, 8, 8, LU_test, 8, 8); if (liquid_autotest_verbose) { printf("ludecomp_crout:\n"); printf(" A: "); matrixcf_print(matrixcf_data_ludecomp_A, 8, 8); printf(" L: "); matrixcf_print(L, 8, 8); printf(" U: "); matrixcf_print(U, 8, 8); printf(" LU: "); matrixcf_print(LU_test, 8, 8); } unsigned int r,c; for (r=0; r<8; r++) { for (c=0; c<8; c++) { if (r < c) { CONTEND_DELTA( crealf(matrix_access(L,8,8,r,c)), 0.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(L,8,8,r,c)), 0.0f, tol ); } else if (r==c) { CONTEND_DELTA( crealf(matrix_access(U,8,8,r,c)), 1.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(U,8,8,r,c)), 0.0f, tol ); } else { CONTEND_DELTA( crealf(matrix_access(U,8,8,r,c)), 0.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(U,8,8,r,c)), 0.0f, tol ); } } } unsigned int i; for (i=0; i<64; i++) { CONTEND_DELTA( crealf(matrixcf_data_ludecomp_A[i]), crealf(LU_test[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_ludecomp_A[i]), cimagf(LU_test[i]), tol ); } } // L/U decomp (Doolittle) void autotest_matrixcf_ludecomp_doolittle() { float tol = 1e-5f; // error tolerance float complex L[64]; float complex U[64]; float complex P[64]; float complex LU_test[64]; // run decomposition matrixcf_ludecomp_doolittle(matrixcf_data_ludecomp_A, 8, 8, L, U, P); // multiply LU matrixcf_mul(L, 8, 8, U, 8, 8, LU_test, 8, 8); if (liquid_autotest_verbose) { printf("ludecomp_doolittle:\n"); printf(" A: "); matrixcf_print(matrixcf_data_ludecomp_A, 8, 8); printf(" L: "); matrixcf_print(L, 8, 8); printf(" U: "); matrixcf_print(U, 8, 8); printf(" LU: "); matrixcf_print(LU_test, 8, 8); } unsigned int r,c; for (r=0; r<8; r++) { for (c=0; c<8; c++) { if (r < c) { CONTEND_DELTA( crealf(matrix_access(L,8,8,r,c)), 0.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(L,8,8,r,c)), 0.0f, tol ); } else if (r==c) { CONTEND_DELTA( crealf(matrix_access(L,8,8,r,c)), 1.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(L,8,8,r,c)), 0.0f, tol ); } else { CONTEND_DELTA( crealf(matrix_access(U,8,8,r,c)), 0.0f, tol ); CONTEND_DELTA( cimagf(matrix_access(U,8,8,r,c)), 0.0f, tol ); } } } unsigned int i; for (i=0; i<64; i++) { CONTEND_DELTA( crealf(matrixcf_data_ludecomp_A[i]), crealf(LU_test[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_ludecomp_A[i]), cimagf(LU_test[i]), tol ); } } // test matrix multiplication void autotest_matrixcf_mul() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 4 x 3] // z [size: 5 x 3] float complex z[35]; matrixcf_mul(matrixcf_data_mul_x, 5, 4, matrixcf_data_mul_y, 4, 3, z, 5, 3); // print result if (liquid_autotest_verbose) { printf("multiplication:\n"); printf(" x: "); matrixcf_print(matrixcf_data_mul_x,5,4); printf(" y: "); matrixcf_print(matrixcf_data_mul_y,4,3); printf(" expected: "); matrixcf_print(matrixcf_data_mul_z,5,3); printf(" z: "); matrixcf_print(z,5,3); } unsigned int i; for (i=0; i<15; i++) { CONTEND_DELTA( crealf(matrixcf_data_mul_z[i]), crealf(z[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_mul_z[i]), cimagf(z[i]), tol ); } } // Q/R decomp (Gram-Schmidt) void autotest_matrixcf_qrdecomp() { float tol = 1e-4f; // error tolerance float complex Q[16]; float complex R[16]; float complex QR_test[16]; // Q*R float complex QQT_test[16]; // Q*Q^T // run decomposition matrixcf_qrdecomp_gramschmidt(matrixcf_data_qrdecomp_A, 4, 4, Q, R); // compute Q*R matrixcf_mul(Q, 4, 4, R, 4, 4, QR_test, 4, 4); // compute Q*Q^T matrixcf_mul_transpose(Q, 4, 4, QQT_test); if (liquid_autotest_verbose) { printf("qrdecomp_gramschmidt:\n"); printf(" A: "); matrixcf_print(matrixcf_data_qrdecomp_A, 4, 4); printf(" Q: "); matrixcf_print(Q, 4, 4); printf(" R: "); matrixcf_print(R, 4, 4); printf(" Q expected: "); matrixcf_print(matrixcf_data_qrdecomp_Q, 4, 4); printf(" R expected: "); matrixcf_print(matrixcf_data_qrdecomp_R, 4, 4); printf(" QR: "); matrixcf_print(QR_test, 4, 4); printf(" QQ: "); matrixcf_print(QQT_test, 4, 4); } unsigned int i; // ensure Q*R = A for (i=0; i<16; i++) { CONTEND_DELTA( crealf(matrixcf_data_qrdecomp_A[i]), crealf(QR_test[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_qrdecomp_A[i]), cimagf(QR_test[i]), tol ); } // ensure Q*Q^T = I(4) float complex I4[16]; matrixcf_eye(I4,4); for (i=0; i<16; i++) CONTEND_DELTA( QQT_test[i], I4[i], tol ); // ensure Q and R are correct for (i=0; i<16; i++) { CONTEND_DELTA( crealf(matrixcf_data_qrdecomp_Q[i]), crealf(Q[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_qrdecomp_Q[i]), cimagf(Q[i]), tol ); CONTEND_DELTA( crealf(matrixcf_data_qrdecomp_R[i]), crealf(R[i]), tol ); CONTEND_DELTA( cimagf(matrixcf_data_qrdecomp_R[i]), cimagf(R[i]), tol ); } } // transpose/multiply void autotest_matrixcf_transmul() { float tol = 1e-4f; // error tolerance float complex xxT[25]; // [size: 5 x 5] float complex xxH[25]; // [size: 5 x 5] float complex xTx[16]; // [size: 4 x 4] float complex xHx[16]; // [size: 4 x 4] // run matrix multiplications matrixcf_mul_transpose(matrixcf_data_transmul_x, 5, 4, xxT); matrixcf_mul_hermitian(matrixcf_data_transmul_x, 5, 4, xxH); matrixcf_transpose_mul(matrixcf_data_transmul_x, 5, 4, xTx); matrixcf_hermitian_mul(matrixcf_data_transmul_x, 5, 4, xHx); if (liquid_autotest_verbose) { printf("transmul:\n"); printf(" x: "); matrixcf_print(matrixcf_data_transmul_x, 5,4); printf("\n"); printf(" xxT: "); matrixcf_print(xxT, 5,5); printf(" xxT expected: "); matrixcf_print(matrixcf_data_transmul_xxT,5,5); printf("\n"); printf(" xxH: "); matrixcf_print(xxH, 5,5); printf(" xxH expected: "); matrixcf_print(matrixcf_data_transmul_xxH,5,5); printf("\n"); printf(" xTx: "); matrixcf_print(xTx, 4,4); printf(" xTx expected: "); matrixcf_print(matrixcf_data_transmul_xTx,4,4); printf("\n"); printf(" xHx: "); matrixcf_print(xHx, 4,4); printf(" xHx expected: "); matrixcf_print(matrixcf_data_transmul_xHx,4,4); printf("\n"); } // run tests unsigned int i; for (i=0; i<25; i++) { CONTEND_DELTA( crealf(matrixcf_data_transmul_xxT[i]), crealf(xxT[i]), tol); CONTEND_DELTA( cimagf(matrixcf_data_transmul_xxT[i]), cimagf(xxT[i]), tol); } for (i=0; i<25; i++) { CONTEND_DELTA( crealf(matrixcf_data_transmul_xxH[i]), crealf(xxH[i]), tol); CONTEND_DELTA( cimagf(matrixcf_data_transmul_xxH[i]), cimagf(xxH[i]), tol); } for (i=0; i<16; i++) { CONTEND_DELTA( crealf(matrixcf_data_transmul_xTx[i]), crealf(xTx[i]), tol); CONTEND_DELTA( cimagf(matrixcf_data_transmul_xTx[i]), cimagf(xTx[i]), tol); } for (i=0; i<16; i++) { CONTEND_DELTA( crealf(matrixcf_data_transmul_xHx[i]), crealf(xHx[i]), tol); CONTEND_DELTA( cimagf(matrixcf_data_transmul_xHx[i]), cimagf(xHx[i]), tol); } } liquid-dsp-1.7.0/src/matrix/tests/matrixf_autotest.c000066400000000000000000000311631474751757600226300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" // autotest data definitions #include "src/matrix/tests/matrix_data.h" // test matrix addition void autotest_matrixf_add() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 5 x 4] // z [size: 5 x 4] float z[20]; matrixf_add(matrixf_data_add_x, matrixf_data_add_y, z, 5, 4); unsigned int i; for (i=0; i<20; i++) CONTEND_DELTA( matrixf_data_add_z[i], z[i], tol ); } // test matrix augmentation void autotest_matrixf_aug() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 5 x 3] // z [size: 5 x 7] float z[35]; matrixf_aug(matrixf_data_aug_x, 5, 4, matrixf_data_aug_y, 5, 3, z, 5, 7); // print result if (liquid_autotest_verbose) { printf("augment:\n"); printf(" x: "); matrixf_print(matrixf_data_aug_x,5,4); printf(" y: "); matrixf_print(matrixf_data_aug_y,5,3); printf(" expected: "); matrixf_print(matrixf_data_aug_z,5,7); printf(" z: "); matrixf_print(z,5,3); } unsigned int i; for (i=0; i<35; i++) CONTEND_DELTA( matrixf_data_aug_z[i], z[i], tol ); } // conjugate gradient solver void autotest_matrixf_cgsolve() { float tol = 0.01; // error tolerance // A [size: 8 x 8], symmetric positive definite matrx // x [size: 8 x 1] // b [size: 8 x 1] float x[8]; matrixf_cgsolve(matrixf_data_cgsolve_A, 8, matrixf_data_cgsolve_b, x, NULL); if (liquid_autotest_verbose) { printf("cgsolve:\n"); printf(" A: "); matrixf_print(matrixf_data_cgsolve_A, 8, 8); printf(" b: "); matrixf_print(matrixf_data_cgsolve_b, 8, 1); printf(" expected: "); matrixf_print(matrixf_data_cgsolve_x, 8, 1); printf(" x: "); matrixf_print(x, 8, 1); } unsigned int i; for (i=0; i<8; i++) CONTEND_DELTA( matrixf_data_cgsolve_x[i], x[i], tol ); } // Cholesky decomposition void autotest_matrixf_chol() { float tol = 1e-4f; // error tolerance // A [size: 4 x 4] // L [size: 4 x 4] float L[16]; // run decomposition matrixf_chol(matrixf_data_chol_A, 4, L); if (liquid_autotest_verbose) { printf("chol:\n"); printf(" A: "); matrixf_print(matrixf_data_chol_A, 4, 4); printf(" expected: "); matrixf_print(matrixf_data_chol_L, 4, 4); printf(" L: "); matrixf_print(L, 4, 4); } unsigned int i; for (i=0; i<16; i++) CONTEND_DELTA( matrixf_data_chol_L[i], L[i], tol ); } // Gram-Schmidt Orthonormalization void autotest_matrixf_gramschmidt() { float tol = 1e-6f; // error tolerance // A [size: 4 x 3] // V [size: 4 x 3] float V[12]; matrixf_gramschmidt(matrixf_data_gramschmidt_A, 4, 3, V); if (liquid_autotest_verbose) { printf("gramschmidt:\n"); printf(" A: "); matrixf_print(matrixf_data_gramschmidt_A, 4, 3); printf(" expected: "); matrixf_print(matrixf_data_gramschmidt_V, 4, 3); printf(" V: "); matrixf_print(V, 4, 3); } unsigned int i; for (i=0; i<12; i++) CONTEND_DELTA( matrixf_data_gramschmidt_V[i], V[i], tol ); } // matrix inversion void autotest_matrixf_inv() { float tol = 1e-6f; // error tolerance // x [size: 5 x 5] // y [size: 5 x 5] float y[25]; memmove(y, matrixf_data_inv_x, 5*5*sizeof(float)); matrixf_inv(y, 5, 5); if (liquid_autotest_verbose) { printf("inv:\n"); printf(" x: "); matrixf_print(matrixf_data_inv_x, 5, 5); printf(" expected: "); matrixf_print(matrixf_data_inv_y, 5, 5); printf(" y: "); matrixf_print(y, 5, 5); } unsigned int i; for (i=0; i<25; i++) CONTEND_DELTA( matrixf_data_inv_y[i], y[i], tol ); } // linsolve (solve linear system of equations) void autotest_matrixf_linsolve() { float tol = 1e-6f; // error tolerance // A [size: 5 x 5] // x [size: 5 x 1] // b [size: 5 x 1] float x[5]; // run solver matrixf_linsolve(matrixf_data_linsolve_A, 5, matrixf_data_linsolve_b, x, NULL); if (liquid_autotest_verbose) { printf("linsolve:\n"); printf(" A: "); matrixf_print(matrixf_data_linsolve_A, 5, 5); printf(" b: "); matrixf_print(matrixf_data_linsolve_b, 5, 1); printf(" expected: "); matrixf_print(matrixf_data_linsolve_x, 5, 1); printf(" x: "); matrixf_print(x, 5, 1); } unsigned int i; for (i=0; i<5; i++) CONTEND_DELTA( matrixf_data_linsolve_x[i], x[i], tol ); } // L/U decomp (Crout) void autotest_matrixf_ludecomp_crout() { float tol = 1e-6f; // error tolerance float L[64]; float U[64]; float P[64]; float LU_test[64]; // run decomposition matrixf_ludecomp_crout(matrixf_data_ludecomp_A, 8, 8, L, U, P); // multiply LU matrixf_mul(L, 8, 8, U, 8, 8, LU_test, 8, 8); if (liquid_autotest_verbose) { printf("ludecomp_crout:\n"); printf(" A: "); matrixf_print(matrixf_data_ludecomp_A,8,8); printf(" L: "); matrixf_print(L, 8,8); printf(" U: "); matrixf_print(U, 8,8); printf(" LU: "); matrixf_print(LU_test, 8,8); } unsigned int r,c; for (r=0; r<8; r++) { for (c=0; c<8; c++) { if (r < c) { CONTEND_DELTA( matrix_access(L,8,8,r,c), 0.0f, tol ); } else if (r==c) { CONTEND_DELTA( matrix_access(U,8,8,r,c), 1.0f, tol ); } else { CONTEND_DELTA( matrix_access(U,8,8,r,c), 0.0f, tol ); } } } unsigned int i; for (i=0; i<64; i++) CONTEND_DELTA( matrixf_data_ludecomp_A[i], LU_test[i], tol ); } // L/U decomp (Doolittle) void autotest_matrixf_ludecomp_doolittle() { float tol = 1e-6f; // error tolerance float L[64]; float U[64]; float P[64]; float LU_test[64]; // run decomposition matrixf_ludecomp_doolittle(matrixf_data_ludecomp_A, 8, 8, L, U, P); // multiply LU matrixf_mul(L, 8, 8, U, 8, 8, LU_test, 8, 8); if (liquid_autotest_verbose) { printf("ludecomp_doolittle:\n"); printf(" A: "); matrixf_print(matrixf_data_ludecomp_A,8,8); printf(" L: "); matrixf_print(L, 8,8); printf(" U: "); matrixf_print(U, 8,8); printf(" LU: "); matrixf_print(LU_test, 8,8); } unsigned int r,c; for (r=0; r<8; r++) { for (c=0; c<8; c++) { if (r < c) { CONTEND_DELTA( matrix_access(L,8,8,r,c), 0.0f, tol ); } else if (r==c) { CONTEND_DELTA( matrix_access(L,8,8,r,c), 1.0f, tol ); } else { CONTEND_DELTA( matrix_access(U,8,8,r,c), 0.0f, tol ); } } } unsigned int i; for (i=0; i<64; i++) CONTEND_DELTA( matrixf_data_ludecomp_A[i], LU_test[i], tol ); } // test matrix multiplication void autotest_matrixf_mul() { float tol = 1e-6f; // x [size: 5 x 4] // y [size: 4 x 3] // z [size: 5 x 3] float z[35]; matrixf_mul(matrixf_data_mul_x, 5, 4, matrixf_data_mul_y, 4, 3, z, 5, 3); // print result if (liquid_autotest_verbose) { printf("multiplication:\n"); printf(" x: "); matrixf_print(matrixf_data_mul_x,5,4); printf(" y: "); matrixf_print(matrixf_data_mul_y,4,3); printf(" expected: "); matrixf_print(matrixf_data_mul_z,5,3); printf(" z: "); matrixf_print(z,5,3); } unsigned int i; for (i=0; i<15; i++) CONTEND_DELTA( matrixf_data_mul_z[i], z[i], tol ); } // Q/R decomp (Gram-Schmidt) void autotest_matrixf_qrdecomp() { float tol = 1e-4f; // error tolerance float Q[16]; float R[16]; float QR_test[16]; // Q*R float QQT_test[16]; // Q*Q^T // run decomposition matrixf_qrdecomp_gramschmidt(matrixf_data_qrdecomp_A, 4, 4, Q, R); // compute Q*R matrixf_mul(Q, 4, 4, R, 4, 4, QR_test, 4, 4); // compute Q*Q^T matrixf_mul_transpose(Q, 4, 4, QQT_test); if (liquid_autotest_verbose) { printf("qrdecomp_gramschmidt:\n"); printf(" A: "); matrixf_print(matrixf_data_qrdecomp_A,4,4); printf(" Q: "); matrixf_print(Q, 4,4); printf(" R: "); matrixf_print(R, 4,4); printf(" Q expected: "); matrixf_print(matrixf_data_qrdecomp_Q,4,4); printf(" R expected: "); matrixf_print(matrixf_data_qrdecomp_R,4,4); printf(" QR: "); matrixf_print(QR_test, 4,4); printf(" QQ: "); matrixf_print(QQT_test, 4,4); } unsigned int i; // ensure Q*R = A for (i=0; i<16; i++) CONTEND_DELTA( matrixf_data_qrdecomp_A[i], QR_test[i], tol ); // ensure Q*Q = I(4) float I4[16]; matrixf_eye(I4,4); for (i=0; i<16; i++) CONTEND_DELTA( QQT_test[i], I4[i], tol ); // ensure Q and R are correct for (i=0; i<16; i++) { CONTEND_DELTA( matrixf_data_qrdecomp_Q[i], Q[i], tol ); CONTEND_DELTA( matrixf_data_qrdecomp_R[i], R[i], tol ); } } // transpose/multiply void autotest_matrixf_transmul() { float tol = 1e-4f; // error tolerance float xxT[25]; // [size: 5 x 5] float xxH[25]; // [size: 5 x 5] float xTx[16]; // [size: 4 x 4] float xHx[16]; // [size: 4 x 4] // run matrix multiplications matrixf_mul_transpose(matrixf_data_transmul_x, 5, 4, xxT); matrixf_mul_hermitian(matrixf_data_transmul_x, 5, 4, xxH); matrixf_transpose_mul(matrixf_data_transmul_x, 5, 4, xTx); matrixf_hermitian_mul(matrixf_data_transmul_x, 5, 4, xHx); if (liquid_autotest_verbose) { printf("transmul:\n"); printf(" x: "); matrixf_print(matrixf_data_transmul_x, 5,4); printf("\n"); printf(" xxT: "); matrixf_print(xxT, 5,5); printf(" xxT expected: "); matrixf_print(matrixf_data_transmul_xxT,5,5); printf("\n"); printf(" xxH: "); matrixf_print(xxH, 5,5); printf(" xxH expected: "); matrixf_print(matrixf_data_transmul_xxH,5,5); printf("\n"); printf(" xTx: "); matrixf_print(xTx, 4,4); printf(" xTx expected: "); matrixf_print(matrixf_data_transmul_xTx,4,4); printf("\n"); printf(" xHx: "); matrixf_print(xHx, 4,4); printf(" xHx expected: "); matrixf_print(matrixf_data_transmul_xHx,4,4); printf("\n"); } // run tests unsigned int i; for (i=0; i<25; i++) CONTEND_DELTA( matrixf_data_transmul_xxT[i], xxT[i], tol); for (i=0; i<25; i++) CONTEND_DELTA( matrixf_data_transmul_xxH[i], xxH[i], tol); for (i=0; i<16; i++) CONTEND_DELTA( matrixf_data_transmul_xTx[i], xTx[i], tol); for (i=0; i<16; i++) CONTEND_DELTA( matrixf_data_transmul_xHx[i], xHx[i], tol); } liquid-dsp-1.7.0/src/matrix/tests/smatrixb_autotest.c000066400000000000000000000245221474751757600230100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTESTS: basic sparse matrix functionality // // test sparse binary matrix methods void autotest_smatrixb_vmul() { // A = [ // 1 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 1 0 0 0 0 0 0 0 0 // 1 0 0 0 0 0 0 0 1 1 0 0 // 0 0 1 0 0 0 1 1 0 0 0 0 // 0 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 0 0 0 1 0 1 0 1 0 // 1 0 1 0 0 0 0 0 0 0 1 1 // 0 0 1 0 0 1 1 0 0 0 0 0] // // x = [ 1 1 0 0 1 0 0 1 1 1 0 1 ] // y = [ 1 0 1 1 0 1 0 0 ] // // create sparse matrix and set values smatrixb A = smatrixb_create(8,12); smatrixb_set(A,0,0, 1); smatrixb_set(A,2,0, 1); smatrixb_set(A,6,0, 1); smatrixb_set(A,3,2, 1); smatrixb_set(A,6,2, 1); smatrixb_set(A,7,2, 1); smatrixb_set(A,1,3, 1); smatrixb_set(A,7,5, 1); smatrixb_set(A,3,6, 1); smatrixb_set(A,5,6, 1); smatrixb_set(A,7,6, 1); smatrixb_set(A,3,7, 1); smatrixb_set(A,2,8, 1); smatrixb_set(A,5,8, 1); smatrixb_set(A,2,9, 1); smatrixb_set(A,5,10, 1); smatrixb_set(A,6,10, 1); smatrixb_set(A,6,11, 1); // generate vectors unsigned char x[12] = {1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1}; unsigned char y_test[8] = {1, 0, 1, 1, 0, 1, 0, 0}; unsigned char y[8]; // multiply and run test smatrixb_vmul(A,x,y); CONTEND_EQUALITY( y[0], y_test[0] ); CONTEND_EQUALITY( y[1], y_test[1] ); CONTEND_EQUALITY( y[2], y_test[2] ); CONTEND_EQUALITY( y[3], y_test[3] ); CONTEND_EQUALITY( y[4], y_test[4] ); CONTEND_EQUALITY( y[5], y_test[5] ); CONTEND_EQUALITY( y[6], y_test[6] ); CONTEND_EQUALITY( y[7], y_test[7] ); // print results (verbose) if (liquid_autotest_verbose) { printf("\ncompact form:\n"); smatrixb_print(A); printf("\nexpanded form:\n"); smatrixb_print_expanded(A); unsigned int i; unsigned int j; printf("x = ["); for (j=0; j<12; j++) printf("%2u", x[j]); printf(" ];\n"); printf("y = ["); for (i=0; i<8; i++) printf("%2u", y[i]); printf(" ];\n"); printf("y_test = ["); for (i=0; i<8; i++) printf("%2u", y_test[i]); printf(" ];\n"); } // destroy matrix object smatrixb_destroy(A); } // test sparse binary matrix multiplication void autotest_smatrixb_mul() { // a: [8 x 12] unsigned char a_test[96] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0}; // b: [12 x 5] unsigned char b_test[60] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0}; // output: [8 x 5] unsigned char c_test[40] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0}; smatrixb a = smatrixb_create_array(a_test, 8,12); smatrixb b = smatrixb_create_array(b_test, 12, 5); smatrixb c = smatrixb_create(8, 5); // compute output smatrixb_mul(a,b,c); // print results (verbose) if (liquid_autotest_verbose) { printf("a:\n"); smatrixb_print_expanded(a); printf("b:\n"); smatrixb_print_expanded(b); printf("c:\n"); smatrixb_print_expanded(c); } unsigned int i; unsigned int j; for (i=0; i<8; i++) { for (j=0; j<5; j++) { CONTEND_EQUALITY( smatrixb_get(c,i,j), c_test[i*5+j]); } } // destroy objects smatrixb_destroy(a); smatrixb_destroy(b); smatrixb_destroy(c); } // void autotest_smatrixb_mulf() { // A = [ // 1 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 1 0 0 0 0 0 0 0 0 // 1 0 0 0 0 0 0 0 1 1 0 0 // 0 0 1 0 0 0 1 1 0 0 0 0 // 0 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 0 0 0 1 0 1 0 1 0 // 1 0 1 0 0 0 0 0 0 0 1 1 // 0 0 1 0 0 1 1 0 0 0 0 0] // float tol = 1e-6f; // create sparse matrix and set values smatrixb A = smatrixb_create(8,12); smatrixb_set(A,0,0, 1); smatrixb_set(A,2,0, 1); smatrixb_set(A,6,0, 1); smatrixb_set(A,3,2, 1); smatrixb_set(A,6,2, 1); smatrixb_set(A,7,2, 1); smatrixb_set(A,1,3, 1); smatrixb_set(A,7,5, 1); smatrixb_set(A,3,6, 1); smatrixb_set(A,5,6, 1); smatrixb_set(A,7,6, 1); smatrixb_set(A,3,7, 1); smatrixb_set(A,2,8, 1); smatrixb_set(A,5,8, 1); smatrixb_set(A,2,9, 1); smatrixb_set(A,5,10, 1); smatrixb_set(A,6,10, 1); smatrixb_set(A,6,11, 1); // generate vectors float x[36] = { -4.3, -0.7, 3.7, -1.7, 2.8, 4.3, 2.0, 1.9, 0.6, 3.6, 1.0, -3.7, 4.3, 0.7, 2.1, 4.6, 0.5, 0.8, 1.6, -3.8, -0.8, -1.9, -2.1, 2.8, -1.5, 2.5, 0.8, 8.4, 1.5, -3.1, -5.8, 0.0, 2.5, -4.9, -2.1, -1.5}; float y_test[24] = { -4.3, -0.7, 3.7, 3.6, 1.0, -3.7, 2.6, 3.3, 1.4, 1.7, -4.0, 2.6, 0.0, 0.0, 0.0, -5.7, -1.3, 2.5, -13.0, -0.9, 5.3, 8.2, -1.4, 0.6}; float y[24]; // multiply and run test smatrixb_mulf(A, x,12,3, y, 8,3); unsigned int i; for (i=0; i<24; i++) CONTEND_DELTA( y[i], y_test[i], tol ); // print results (verbose) if (liquid_autotest_verbose) { printf("A:\n"); smatrixb_print_expanded(A); printf("x = [\n"); for (i=0; i<36; i++) printf("%6.2f%s", x[i], ((i+1)%3)==0 ? "\n" : ""); printf(" ];\n"); printf("y = [\n"); for (i=0; i<24; i++) printf("%6.2f%s", y[i], ((i+1)%3)==0 ? "\n" : ""); printf(" ];\n"); printf("y_test = [\n"); for (i=0; i<24; i++) printf("%6.2f%s", y_test[i], ((i+1)%3)==0 ? "\n" : ""); printf(" ];\n"); } // destroy matrix object smatrixb_destroy(A); } // void autotest_smatrixb_vmulf() { // A = [ // 1 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 1 0 0 0 0 0 0 0 0 // 1 0 0 0 0 0 0 0 1 1 0 0 // 0 0 1 0 0 0 1 1 0 0 0 0 // 0 0 0 0 0 0 0 0 0 0 0 0 // 0 0 0 0 0 0 1 0 1 0 1 0 // 1 0 1 0 0 0 0 0 0 0 1 1 // 0 0 1 0 0 1 1 0 0 0 0 0] // // x = [3.4,-5.7, 0.3, 2.3, 1.9, 3.9, 2.3,-4.0,-0.5, 1.5,-0.6,-1.0]^T // y = [3.4, 2.3, 4.4,-1.4, 0.0, 1.2, 2.1, 6.5]^T // float tol = 1e-6f; // create sparse matrix and set values smatrixb A = smatrixb_create(8,12); smatrixb_set(A,0,0, 1); smatrixb_set(A,2,0, 1); smatrixb_set(A,6,0, 1); smatrixb_set(A,3,2, 1); smatrixb_set(A,6,2, 1); smatrixb_set(A,7,2, 1); smatrixb_set(A,1,3, 1); smatrixb_set(A,7,5, 1); smatrixb_set(A,3,6, 1); smatrixb_set(A,5,6, 1); smatrixb_set(A,7,6, 1); smatrixb_set(A,3,7, 1); smatrixb_set(A,2,8, 1); smatrixb_set(A,5,8, 1); smatrixb_set(A,2,9, 1); smatrixb_set(A,5,10, 1); smatrixb_set(A,6,10, 1); smatrixb_set(A,6,11, 1); // generate vectors float x[12] = { 3.4, -5.7, 0.3, 2.3, 1.9, 3.9, 2.3, -4.0, -0.5, 1.5, -0.6, -1.0}; float y_test[8] = { 3.4, 2.3, 4.4, -1.4, 0.0, 1.2, 2.1, 6.5}; float y[8]; // multiply and run test smatrixb_vmulf(A,x,y); CONTEND_DELTA( y[0], y_test[0], tol ); CONTEND_DELTA( y[1], y_test[1], tol ); CONTEND_DELTA( y[2], y_test[2], tol ); CONTEND_DELTA( y[3], y_test[3], tol ); CONTEND_DELTA( y[4], y_test[4], tol ); CONTEND_DELTA( y[5], y_test[5], tol ); CONTEND_DELTA( y[6], y_test[6], tol ); CONTEND_DELTA( y[7], y_test[7], tol ); // print results (verbose) if (liquid_autotest_verbose) { printf("\ncompact form:\n"); smatrixb_print(A); printf("\nexpanded form:\n"); smatrixb_print_expanded(A); unsigned int i; unsigned int j; printf("x = ["); for (j=0; j<12; j++) printf("%8.4f", x[j]); printf(" ];\n"); printf("y = ["); for (i=0; i<8; i++) printf("%8.4f", y[i]); printf(" ];\n"); printf("y_test = ["); for (i=0; i<8; i++) printf("%8.4f", y_test[i]); printf(" ];\n"); } // destroy matrix object smatrixb_destroy(A); } liquid-dsp-1.7.0/src/matrix/tests/smatrixf_autotest.c000066400000000000000000000064371474751757600230210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTESTS: basic sparse matrix functionality // // test sparse floating-point vector multiplication void autotest_smatrixf_vmul() { float tol = 1e-6f; // A = [ // 0 0 0 0 4 // 0 0 0 0 0 // 0 0 0 3 0 // 2 0 0 0 1 // create sparse matrix and set values smatrixf A = smatrixf_create(4, 5); smatrixf_set(A, 0,4, 4); smatrixf_set(A, 2,3, 3); smatrixf_set(A, 3,0, 2); smatrixf_set(A, 3,4, 0); smatrixf_set(A, 3,4, 1); // initialize input vector float x[5] = {7, 1, 5, 2, 2}; float y_test[4] = {8, 0, 6, 16}; float y[4]; // multiply and run test smatrixf_vmul(A,x,y); // check values CONTEND_DELTA( y[0], y_test[0], tol ); CONTEND_DELTA( y[1], y_test[1], tol ); CONTEND_DELTA( y[2], y_test[2], tol ); CONTEND_DELTA( y[3], y_test[3], tol ); smatrixf_destroy(A); } // test sparse floating-point matrix multiplication void autotest_smatrixf_mul() { float tol = 1e-6f; // initialize matrices smatrixf a = smatrixf_create(4, 5); smatrixf b = smatrixf_create(5, 3); smatrixf c = smatrixf_create(4, 3); // initialize 'a' // 0 0 0 0 4 // 0 0 0 0 0 // 0 0 0 3 0 // 2 0 0 0 1 smatrixf_set(a, 0,4, 4); smatrixf_set(a, 2,3, 3); smatrixf_set(a, 3,0, 2); smatrixf_set(a, 3,4, 0); smatrixf_set(a, 3,4, 1); // initialize 'b' // 7 6 0 // 0 0 0 // 0 0 0 // 0 5 0 // 2 0 0 smatrixf_set(b, 0,0, 7); smatrixf_set(b, 0,1, 6); smatrixf_set(b, 3,1, 5); smatrixf_set(b, 4,0, 2); // compute 'c' // 8 0 0 // 0 0 0 // 0 15 0 // 16 12 0 smatrixf_mul(a,b,c); float c_test[12] = { 8, 0, 0, 0, 0, 0, 0, 15, 0, 16, 12, 0}; // check values unsigned int i; unsigned int j; for (i=0; i<4; i++) { for (j=0; j<3; j++) { CONTEND_DELTA(smatrixf_get(c,i,j), matrixf_access(c_test,4,3,i,j), tol); } } smatrixf_destroy(a); smatrixf_destroy(b); smatrixf_destroy(c); } liquid-dsp-1.7.0/src/matrix/tests/smatrixi_autotest.c000066400000000000000000000063201474751757600230130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTESTS: basic sparse matrix functionality // // test sparse integer vector multiplication void autotest_smatrixi_vmul() { // A = [ // 0 0 0 0 4 // 0 0 0 0 0 // 0 0 0 3 0 // 2 0 0 0 1 // create sparse matrix and set values smatrixi A = smatrixi_create(4, 5); smatrixi_set(A, 0,4, 4); smatrixi_set(A, 2,3, 3); smatrixi_set(A, 3,0, 2); smatrixi_set(A, 3,4, 0); smatrixi_set(A, 3,4, 1); // initialize input vector short int x[5] = {7, 1, 5, 2, 2}; short int y_test[4] = {8, 0, 6, 16}; short int y[4]; // multiply and run test smatrixi_vmul(A,x,y); // check values CONTEND_EQUALITY( y[0], y_test[0] ); CONTEND_EQUALITY( y[1], y_test[1] ); CONTEND_EQUALITY( y[2], y_test[2] ); CONTEND_EQUALITY( y[3], y_test[3] ); smatrixi_destroy(A); } // test sparse integer matrix multiplication void autotest_smatrixi_mul() { // initialize matrices smatrixi a = smatrixi_create(4, 5); smatrixi b = smatrixi_create(5, 3); smatrixi c = smatrixi_create(4, 3); // initialize 'a' // 0 0 0 0 4 // 0 0 0 0 0 // 0 0 0 3 0 // 2 0 0 0 1 smatrixi_set(a, 0,4, 4); smatrixi_set(a, 2,3, 3); smatrixi_set(a, 3,0, 2); smatrixi_set(a, 3,4, 0); smatrixi_set(a, 3,4, 1); // initialize 'b' // 7 6 0 // 0 0 0 // 0 0 0 // 0 5 0 // 2 0 0 smatrixi_set(b, 0,0, 7); smatrixi_set(b, 0,1, 6); smatrixi_set(b, 3,1, 5); smatrixi_set(b, 4,0, 2); // compute 'c' // 8 0 0 // 0 0 0 // 0 15 0 // 16 12 0 smatrixi_mul(a,b,c); short int c_test[12] = { 8, 0, 0, 0, 0, 0, 0, 15, 0, 16, 12, 0}; // check values unsigned int i; unsigned int j; for (i=0; i<4; i++) { for (j=0; j<3; j++) { CONTEND_EQUALITY(smatrixi_get(c,i,j), matrixf_access(c_test,4,3,i,j)) } } smatrixi_destroy(a); smatrixi_destroy(b); smatrixi_destroy(c); } liquid-dsp-1.7.0/src/modem/000077500000000000000000000000001474751757600155115ustar00rootroot00000000000000liquid-dsp-1.7.0/src/modem/bench/000077500000000000000000000000001474751757600165705ustar00rootroot00000000000000liquid-dsp-1.7.0/src/modem/bench/freqdem_benchmark.c000066400000000000000000000056351474751757600224020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // frequency demodulator benchmark void benchmark_freqdem(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { // create demodulator float kf = 0.05f; // modulation index freqdem dem = freqdem_create(kf); float complex r[20]; // modulated signal float m[20]; // message signal unsigned long int i; // generate modulated signal for (i=0; i<20; i++) r[i] = 0.3f*cexpf(_Complex_I*2*M_PI*i/20.0f); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { freqdem_demodulate(dem, r[ 0], &m[ 0]); freqdem_demodulate(dem, r[ 1], &m[ 1]); freqdem_demodulate(dem, r[ 2], &m[ 2]); freqdem_demodulate(dem, r[ 3], &m[ 3]); freqdem_demodulate(dem, r[ 4], &m[ 4]); freqdem_demodulate(dem, r[ 5], &m[ 5]); freqdem_demodulate(dem, r[ 6], &m[ 6]); freqdem_demodulate(dem, r[ 7], &m[ 7]); freqdem_demodulate(dem, r[ 8], &m[ 8]); freqdem_demodulate(dem, r[ 9], &m[ 9]); freqdem_demodulate(dem, r[10], &m[10]); freqdem_demodulate(dem, r[11], &m[11]); freqdem_demodulate(dem, r[12], &m[12]); freqdem_demodulate(dem, r[13], &m[13]); freqdem_demodulate(dem, r[14], &m[14]); freqdem_demodulate(dem, r[15], &m[15]); freqdem_demodulate(dem, r[16], &m[16]); freqdem_demodulate(dem, r[17], &m[17]); freqdem_demodulate(dem, r[18], &m[18]); freqdem_demodulate(dem, r[19], &m[19]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 20; // destroy demodulator freqdem_destroy(dem); } liquid-dsp-1.7.0/src/modem/bench/freqmod_benchmark.c000066400000000000000000000057511474751757600224130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // frequency modulator benchmark void benchmark_freqmod(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { // create modulator float kf = 0.05f; // modulation index freqmod mod = freqmod_create(kf); float m[20]; // message signal float complex r[20]; // modulated signal unsigned long int i; // generate message signal (sum of sines) for (i=0; i<20; i++) { m[i] = 0.3f*cosf(2*M_PI*1*i/20.0f + 0.0f) + 0.2f*cosf(2*M_PI*2*i/20.0f + 0.4f) + 0.4f*cosf(2*M_PI*3*i/20.0f + 1.7f); } // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { freqmod_modulate(mod, m[ 0], &r[ 0]); freqmod_modulate(mod, m[ 1], &r[ 1]); freqmod_modulate(mod, m[ 2], &r[ 2]); freqmod_modulate(mod, m[ 3], &r[ 3]); freqmod_modulate(mod, m[ 4], &r[ 4]); freqmod_modulate(mod, m[ 5], &r[ 5]); freqmod_modulate(mod, m[ 6], &r[ 6]); freqmod_modulate(mod, m[ 7], &r[ 7]); freqmod_modulate(mod, m[ 8], &r[ 8]); freqmod_modulate(mod, m[ 9], &r[ 9]); freqmod_modulate(mod, m[10], &r[10]); freqmod_modulate(mod, m[11], &r[11]); freqmod_modulate(mod, m[12], &r[12]); freqmod_modulate(mod, m[13], &r[13]); freqmod_modulate(mod, m[14], &r[14]); freqmod_modulate(mod, m[15], &r[15]); freqmod_modulate(mod, m[16], &r[16]); freqmod_modulate(mod, m[17], &r[17]); freqmod_modulate(mod, m[18], &r[18]); freqmod_modulate(mod, m[19], &r[19]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 20; // destroy modulator freqmod_destroy(mod); } liquid-dsp-1.7.0/src/modem/bench/fskdem_benchmark.c000066400000000000000000000106401474751757600222200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" #define FSKDEM_BENCH_API(m,k,bandwidth) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { fskdem_bench(_start, _finish, _num_iterations, m, k, bandwidth); } // Helper function to keep code base small void fskdem_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _m, unsigned int _k, float _bandwidth) { // normalize number of iterations *_num_iterations /= _k; if (*_num_iterations < 1) *_num_iterations = 1; // initialize demodulator fskdem dem = fskdem_create(_m,_k,_bandwidth); //unsigned int M = 1 << _m; // constellation size unsigned long int i; // generate input vector to demodulate (spiral) float complex buf[_k+10]; for (i=0; i<_k+10; i++) buf[i] = 0.07 * i * cexpf(_Complex_I*2*M_PI*0.1*i); // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fskdem_demodulate(dem, &buf[0]); fskdem_demodulate(dem, &buf[1]); fskdem_demodulate(dem, &buf[2]); fskdem_demodulate(dem, &buf[3]); fskdem_demodulate(dem, &buf[4]); fskdem_demodulate(dem, &buf[5]); fskdem_demodulate(dem, &buf[6]); fskdem_demodulate(dem, &buf[7]); fskdem_demodulate(dem, &buf[8]); fskdem_demodulate(dem, &buf[9]); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 10; fskdem_destroy(dem); } // BENCHMARKS: basic properties: M=2^m, k = 2*M, bandwidth = 0.25 void benchmark_fskdem_norm_M2 FSKDEM_BENCH_API( 1, 4, 0.25f ) void benchmark_fskdem_norm_M4 FSKDEM_BENCH_API( 2, 8, 0.25f ) void benchmark_fskdem_norm_M8 FSKDEM_BENCH_API( 3, 16, 0.25f ) void benchmark_fskdem_norm_M16 FSKDEM_BENCH_API( 4, 32, 0.25f ) void benchmark_fskdem_norm_M32 FSKDEM_BENCH_API( 5, 64, 0.25f ) void benchmark_fskdem_norm_M64 FSKDEM_BENCH_API( 6, 128, 0.25f ) void benchmark_fskdem_norm_M128 FSKDEM_BENCH_API( 7, 256, 0.25f ) void benchmark_fskdem_norm_M256 FSKDEM_BENCH_API( 8, 512, 0.25f ) void benchmark_fskdem_norm_M512 FSKDEM_BENCH_API( 9, 1024, 0.25f ) void benchmark_fskdem_norm_M1024 FSKDEM_BENCH_API(10, 2048, 0.25f ) // BENCHMARKS: obscure properties: M=2^m, k not relative to M, bandwidth basically irrational void benchmark_fskdem_misc_M2 FSKDEM_BENCH_API( 1, 5, 0.3721451) void benchmark_fskdem_misc_M4 FSKDEM_BENCH_API( 2, 10, 0.3721451) void benchmark_fskdem_misc_M8 FSKDEM_BENCH_API( 3, 20, 0.3721451) void benchmark_fskdem_misc_M16 FSKDEM_BENCH_API( 4, 30, 0.3721451) void benchmark_fskdem_misc_M32 FSKDEM_BENCH_API( 5, 60, 0.3721451) void benchmark_fskdem_misc_M64 FSKDEM_BENCH_API( 6, 100, 0.3721451) void benchmark_fskdem_misc_M128 FSKDEM_BENCH_API( 7, 200, 0.3721451) void benchmark_fskdem_misc_M256 FSKDEM_BENCH_API( 8, 500, 0.3721451) void benchmark_fskdem_misc_M512 FSKDEM_BENCH_API( 9, 1000, 0.3721451) void benchmark_fskdem_misc_M1024 FSKDEM_BENCH_API(10, 2000, 0.3721451) liquid-dsp-1.7.0/src/modem/bench/fskmod_benchmark.c000066400000000000000000000105401474751757600222310ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" #define FSKMOD_BENCH_API(m,k,bandwidth) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { fskmod_bench(_start, _finish, _num_iterations, m, k, bandwidth); } // Helper function to keep code base small void fskmod_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _m, unsigned int _k, float _bandwidth) { // normalize number of iterations *_num_iterations /= _k; if (*_num_iterations < 1) *_num_iterations = 1; // initialize modulator fskmod mod = fskmod_create(_m,_k,_bandwidth); unsigned int M = 1 << _m; // constellation size float complex buf[_k]; // transmit buffer unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { fskmod_modulate(mod, (i+ 0) % M, buf); fskmod_modulate(mod, (i+ 1) % M, buf); fskmod_modulate(mod, (i+ 2) % M, buf); fskmod_modulate(mod, (i+ 3) % M, buf); fskmod_modulate(mod, (i+ 4) % M, buf); fskmod_modulate(mod, (i+ 5) % M, buf); fskmod_modulate(mod, (i+ 6) % M, buf); fskmod_modulate(mod, (i+ 7) % M, buf); fskmod_modulate(mod, (i+ 8) % M, buf); fskmod_modulate(mod, (i+ 9) % M, buf); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 10; fskmod_destroy(mod); } // BENCHMARKS: basic properties: M=2^m, k = 2*M, bandwidth = 0.25 void benchmark_fskmod_norm_M2 FSKMOD_BENCH_API( 1, 4, 0.25f ) void benchmark_fskmod_norm_M4 FSKMOD_BENCH_API( 2, 8, 0.25f ) void benchmark_fskmod_norm_M8 FSKMOD_BENCH_API( 3, 16, 0.25f ) void benchmark_fskmod_norm_M16 FSKMOD_BENCH_API( 4, 32, 0.25f ) void benchmark_fskmod_norm_M32 FSKMOD_BENCH_API( 5, 64, 0.25f ) void benchmark_fskmod_norm_M64 FSKMOD_BENCH_API( 6, 128, 0.25f ) void benchmark_fskmod_norm_M128 FSKMOD_BENCH_API( 7, 256, 0.25f ) void benchmark_fskmod_norm_M256 FSKMOD_BENCH_API( 8, 512, 0.25f ) void benchmark_fskmod_norm_M512 FSKMOD_BENCH_API( 9, 1024, 0.25f ) void benchmark_fskmod_norm_M1024 FSKMOD_BENCH_API(10, 2048, 0.25f ) // BENCHMARKS: obscure properties: M=2^m, k not relative to M, bandwidth basically irrational void benchmark_fskmod_misc_M2 FSKMOD_BENCH_API( 1, 5, 0.3721451) void benchmark_fskmod_misc_M4 FSKMOD_BENCH_API( 2, 10, 0.3721451) void benchmark_fskmod_misc_M8 FSKMOD_BENCH_API( 3, 20, 0.3721451) void benchmark_fskmod_misc_M16 FSKMOD_BENCH_API( 4, 30, 0.3721451) void benchmark_fskmod_misc_M32 FSKMOD_BENCH_API( 5, 60, 0.3721451) void benchmark_fskmod_misc_M64 FSKMOD_BENCH_API( 6, 100, 0.3721451) void benchmark_fskmod_misc_M128 FSKMOD_BENCH_API( 7, 200, 0.3721451) void benchmark_fskmod_misc_M256 FSKMOD_BENCH_API( 8, 500, 0.3721451) void benchmark_fskmod_misc_M512 FSKMOD_BENCH_API( 9, 1000, 0.3721451) void benchmark_fskmod_misc_M1024 FSKMOD_BENCH_API(10, 2000, 0.3721451) liquid-dsp-1.7.0/src/modem/bench/gmskmodem_benchmark.c000066400000000000000000000062051474751757600227340ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // void benchmark_gmskmodem_modulate(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // options unsigned int k=2; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.3f; // bandwidth-time product // create modem object gmskmod mod = gmskmod_create(k, m, BT); float complex x[k]; unsigned int symbol_in = 0; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); gmskmod_modulate(mod, symbol_in, x); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // destroy modem objects gmskmod_destroy(mod); } // void benchmark_gmskmodem_demodulate(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // options unsigned int k=2; // filter samples/symbol unsigned int m=3; // filter delay (symbols) float BT=0.3f; // bandwidth-time product // create modem object gmskdem demod = gmskdem_create(k, m, BT); float complex x[k]; unsigned int symbol_out = 0; unsigned long int i; for (i=0; i #include #include #include #include "liquid.internal.h" #define MODEM_DEMODSOFT_BENCH_API(MS) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { modemcf_demodulate_soft_bench(_start, _finish, _num_iterations, MS); } // Helper function to keep code base small void modemcf_demodulate_soft_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, modulation_scheme _ms) { // initialize modulator modemcf demod = modemcf_create(_ms); // normalize number of iterations unsigned int bps = modemcf_get_bps(demod); switch (_ms) { case LIQUID_MODEM_UNKNOWN: liquid_error(LIQUID_EINT,"modemcf_modulate_bench(), unknown modem scheme"); return; case LIQUID_MODEM_ARB16OPT: case LIQUID_MODEM_ARB32OPT: case LIQUID_MODEM_ARB64OPT: case LIQUID_MODEM_ARB128OPT: case LIQUID_MODEM_ARB256OPT: case LIQUID_MODEM_ARB64VT: case LIQUID_MODEM_ARB: *_num_iterations /= 2*(1< #include #include #include #include "liquid.internal.h" #define MODEM_DEMODULATE_BENCH_API(MS) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { modemcf_demodulate_bench(_start, _finish, _num_iterations, MS); } // Helper function to keep code base small void modemcf_demodulate_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, modulation_scheme _ms) { // initialize modulator modemcf demod = modemcf_create(_ms); // normalize number of iterations unsigned int bps = modemcf_get_bps(demod); switch (_ms) { case LIQUID_MODEM_UNKNOWN: liquid_error(LIQUID_EINT,"modemcf_modulate_bench(), unknown modem scheme"); return; case LIQUID_MODEM_ARB16OPT: case LIQUID_MODEM_ARB32OPT: case LIQUID_MODEM_ARB64OPT: case LIQUID_MODEM_ARB128OPT: case LIQUID_MODEM_ARB256OPT: case LIQUID_MODEM_ARB64VT: case LIQUID_MODEM_ARB: *_num_iterations /= 2*(1< #include #include #include "liquid.internal.h" #define MODEM_MODULATE_BENCH_API(MS) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { modemcf_modulate_bench(_start, _finish, _num_iterations, MS); } // Helper function to keep code base small void modemcf_modulate_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, modulation_scheme _ms) { // initialize modulator modemcf mod = modemcf_create(_ms); unsigned long int i; float complex x; unsigned int symbol_in = 0; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { modemcf_modulate(mod, symbol_in, &x); modemcf_modulate(mod, symbol_in, &x); modemcf_modulate(mod, symbol_in, &x); modemcf_modulate(mod, symbol_in, &x); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; modemcf_destroy(mod); } // specific modems void benchmark_modulate_bpsk MODEM_MODULATE_BENCH_API(LIQUID_MODEM_BPSK) void benchmark_modulate_qpsk MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QPSK) void benchmark_modulate_ook MODEM_MODULATE_BENCH_API(LIQUID_MODEM_OOK) void benchmark_modulate_sqam32 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_SQAM32) void benchmark_modulate_sqam128 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_SQAM128) // ASK void benchmark_modulate_ask2 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ASK2) void benchmark_modulate_ask4 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ASK4) void benchmark_modulate_ask8 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ASK8) void benchmark_modulate_ask16 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ASK16) // PSK void benchmark_modulate_psk2 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK2) void benchmark_modulate_psk4 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK4) void benchmark_modulate_psk8 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK8) void benchmark_modulate_psk16 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK16) void benchmark_modulate_psk32 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK32) void benchmark_modulate_psk64 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_PSK64) // Differential PSK void benchmark_modulate_dpsk2 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK2) void benchmark_modulate_dpsk4 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK4) void benchmark_modulate_dpsk8 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK8) void benchmark_modulate_dpsk16 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK16) void benchmark_modulate_dpsk32 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK32) void benchmark_modulate_dpsk64 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_DPSK64) // QAM void benchmark_modulate_qam4 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM4) void benchmark_modulate_qam8 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM8) void benchmark_modulate_qam16 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM16) void benchmark_modulate_qam32 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM32) void benchmark_modulate_qam64 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM64) void benchmark_modulate_qam128 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM128) void benchmark_modulate_qam256 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_QAM256) // APSK void benchmark_modulate_apsk4 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK4) void benchmark_modulate_apsk8 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK8) void benchmark_modulate_apsk16 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK16) void benchmark_modulate_apsk32 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK32) void benchmark_modulate_apsk64 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK64) void benchmark_modulate_apsk128 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK128) void benchmark_modulate_apsk256 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_APSK256) // ARB void benchmark_modulate_arbV29 MODEM_MODULATE_BENCH_API(LIQUID_MODEM_V29) void benchmark_modulate_arb16opt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB16OPT) void benchmark_modulate_arb32opt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB32OPT) void benchmark_modulate_arb64opt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB64OPT) void benchmark_modulate_arb128opt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB128OPT) void benchmark_modulate_arb256opt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB256OPT) void benchmark_modulate_arb64vt MODEM_MODULATE_BENCH_API(LIQUID_MODEM_ARB64VT) liquid-dsp-1.7.0/src/modem/src/000077500000000000000000000000001474751757600163005ustar00rootroot00000000000000liquid-dsp-1.7.0/src/modem/src/ampmodem.c000066400000000000000000000276401474751757600202540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Amplitude modulator/demodulator // #include #include #include #include "liquid.internal.h" // internal methods for specific demodulation methods int ampmodem_demod_dsb_peak_detect(ampmodem _q, float complex _x, float * _m); int ampmodem_demod_dsb_pll_carrier(ampmodem _q, float complex _x, float * _m); int ampmodem_demod_dsb_pll_costas (ampmodem _q, float complex _x, float * _m); int ampmodem_demod_ssb_pll_carrier(ampmodem _q, float complex _x, float * _m); int ampmodem_demod_ssb (ampmodem _q, float complex _x, float * _m); struct ampmodem_s { // modulation index float mod_index; // modulation type (e.g. LIQUID_AMPMODEM_DSB) liquid_ampmodem_type type; // suppressed carrier flag int suppressed_carrier; // demod and helper objects unsigned int m; // filter semi-length for all objects nco_crcf mixer; // mixer and phase-locked loop firfilt_rrrf dcblock; // carrier suppression filter firhilbf hilbert; // hilbert transform (single side-band) firfilt_crcf lowpass; // low-pass filter for SSB PLL wdelaycf delay; // delay buffer to align to low-pass filter delay // demodulation function pointer int (*demod)(ampmodem _q, float complex _x, float * _m); }; // create ampmodem object // _mod_index : modulation index // _type : AM type (e.g. LIQUID_AMPMODEM_DSB) // _suppressed_carrier : carrier suppression flag ampmodem ampmodem_create(float _mod_index, liquid_ampmodem_type _type, int _suppressed_carrier) { // validate input switch (_type) { case LIQUID_AMPMODEM_DSB: case LIQUID_AMPMODEM_USB: case LIQUID_AMPMODEM_LSB: break; default: return liquid_error_config("ampmodem_create(), invalid modem type: %d", (int)_type); } // create main object ampmodem q = (ampmodem) malloc(sizeof(struct ampmodem_s)); // set internal properties q->type = _type; q->mod_index = _mod_index; q->suppressed_carrier = (_suppressed_carrier != 0); q->m = 25; // create nco, pll objects q->mixer = nco_crcf_create(LIQUID_NCO); nco_crcf_pll_set_bandwidth(q->mixer,0.001f); // carrier suppression filter q->dcblock = firfilt_rrrf_create_dc_blocker(q->m, 20.0f); // Hilbert transform for single side-band recovery q->hilbert = firhilbf_create(q->m, 60.0f); // carrier admittance filter for phase-locked loop q->lowpass = firfilt_crcf_create_kaiser(2*q->m+1, 0.01f, 40.0f, 0.0f); // delay buffer q->delay = wdelaycf_create(q->m); // set appropriate demod function pointer q->demod = NULL; if (q->type == LIQUID_AMPMODEM_DSB) { // double side-band q->demod = q->suppressed_carrier ? ampmodem_demod_dsb_pll_costas : //ampmodem_demod_dsb_peak_detect; ampmodem_demod_dsb_pll_carrier; } else { // single side-band q->demod = q->suppressed_carrier ? ampmodem_demod_ssb : ampmodem_demod_ssb_pll_carrier; } // reset object and return ampmodem_reset(q); return q; } int ampmodem_destroy(ampmodem _q) { // destroy objects nco_crcf_destroy (_q->mixer); firfilt_rrrf_destroy(_q->dcblock); firhilbf_destroy (_q->hilbert); firfilt_crcf_destroy(_q->lowpass); wdelaycf_destroy (_q->delay); // free main object memory free(_q); return LIQUID_OK; } int ampmodem_print(ampmodem _q) { printf("type) { case LIQUID_AMPMODEM_DSB: printf(", type=\"DSB\""); break; case LIQUID_AMPMODEM_USB: printf(", type=\"USB\""); break; case LIQUID_AMPMODEM_LSB: printf(", type=\"LSB\""); break; default: printf(", type=\"?\""); } printf(", carrier_suppressed=%s", _q->suppressed_carrier ? "true" : "false"); printf(", mod_index=%g", _q->mod_index); printf(">\n"); return LIQUID_OK; } // reset all internal objects int ampmodem_reset(ampmodem _q) { nco_crcf_reset (_q->mixer); firfilt_rrrf_reset(_q->dcblock); firhilbf_reset (_q->hilbert); firfilt_crcf_reset(_q->lowpass); wdelaycf_reset (_q->delay); return LIQUID_OK; } // accessor methods unsigned int ampmodem_get_delay_mod(ampmodem _q) { switch (_q->type) { case LIQUID_AMPMODEM_DSB: return 0; case LIQUID_AMPMODEM_USB: case LIQUID_AMPMODEM_LSB: return 2*_q->m; default: liquid_error(LIQUID_EINT,"ampmodem_get_delay_mod(), internal error, invalid mod type"); } return 0; } unsigned int ampmodem_get_delay_demod(ampmodem _q) { switch (_q->type) { case LIQUID_AMPMODEM_DSB: return _q->suppressed_carrier ? 0 : 2*_q->m; case LIQUID_AMPMODEM_USB: case LIQUID_AMPMODEM_LSB: return _q->suppressed_carrier ? 2*_q->m : 4*_q->m; default: liquid_error(LIQUID_EINT,"ampmodem_get_delay_demod(), internal error, invalid mod type"); } return 0; } int ampmodem_modulate(ampmodem _q, float _x, float complex * _y) { float complex x_hat = 0.0f; if (_q->type == LIQUID_AMPMODEM_DSB) { x_hat = _x; } else { // push through Hilbert transform // LIQUID_AMPMODEM_USB: // LIQUID_AMPMODEM_LSB: conjugate Hilbert transform output firhilbf_r2c_execute(_q->hilbert, _x, &x_hat); if (_q->type == LIQUID_AMPMODEM_LSB) x_hat = conjf(x_hat); } // save result *_y = x_hat * _q->mod_index + (_q->suppressed_carrier ? 0.0f : 1.0f); return LIQUID_OK; } // modulate block of samples // _q : ampmodem object // _m : message signal m(t), [size: _n x 1] // _n : number of input, output samples // _s : complex baseband signal s(t) [size: _n x 1] int ampmodem_modulate_block(ampmodem _q, float * _m, unsigned int _n, float complex * _s) { // TODO: implement more efficient method unsigned int i; for (i=0; i<_n; i++) ampmodem_modulate(_q, _m[i], &_s[i]); return LIQUID_OK; } // demodulate int ampmodem_demodulate(ampmodem _q, float complex _y, float * _x) { // invoke internal type-specific method return _q->demod(_q, _y, _x); } // demodulate block of samples // _q : frequency demodulator object // _y : received signal r(t) [size: _n x 1] // _n : number of input, output samples // _x : message signal m(t), [size: _n x 1] int ampmodem_demodulate_block(ampmodem _q, float complex * _y, unsigned int _n, float * _x) { unsigned int i; int rc; for (i=0; i<_n; i++) { // invoke internal type-specific method //ampmodem_demodulate(_q, _y[i], &_x[i]); if ( (rc = _q->demod(_q, _y[i], &_x[i])) ) return rc; } return LIQUID_OK; } // // internal methods // int ampmodem_demod_dsb_peak_detect(ampmodem _q, float complex _x, float * _y) { // compute signal magnitude float v = cabsf(_x); // apply DC blocking filter firfilt_rrrf_push (_q->dcblock, v); firfilt_rrrf_execute(_q->dcblock, &v); // set output *_y = v / _q->mod_index; return LIQUID_OK; } int ampmodem_demod_dsb_pll_carrier(ampmodem _q, float complex _x, float * _y) { // split signal into two branches: // 0. low-pass filter for carrier recovery and // 1. delay to align signal output float complex x0, x1; firfilt_crcf_push (_q->lowpass, _x); firfilt_crcf_execute(_q->lowpass, &x0); wdelaycf_push (_q->delay, _x); wdelaycf_read (_q->delay, &x1); // mix each signal down float complex v0, v1; nco_crcf_mix_down(_q->mixer, x0, &v0); nco_crcf_mix_down(_q->mixer, x1, &v1); // compute phase error float phase_error = cargf(v0); // adjust nco, pll objects nco_crcf_pll_step(_q->mixer, phase_error); // step nco nco_crcf_step(_q->mixer); // keep in-phase component float m = crealf(v1) / _q->mod_index; // apply DC block, writing directly to output firfilt_rrrf_push (_q->dcblock, m); firfilt_rrrf_execute(_q->dcblock, _y); return LIQUID_OK; } int ampmodem_demod_dsb_pll_costas(ampmodem _q, float complex _x, float * _y) { // mix signal down float complex v; nco_crcf_mix_down(_q->mixer, _x, &v); // compute phase error //float phase_error = crealf(v)*cimagf(v); float phase_error = cimagf(v) * (crealf(v) > 0 ? 1 : -1); // adjust nco, pll objects nco_crcf_pll_step(_q->mixer, phase_error); // step nco nco_crcf_step(_q->mixer); // keep in-phase component (ignore modulation index) *_y = crealf(v) / _q->mod_index; return LIQUID_OK; } int ampmodem_demod_ssb_pll_carrier(ampmodem _q, float complex _x, float * _y) { // split signal into two branches: // 0. low-pass filter for carrier recovery and // 1. delay to align signal output float complex x0, x1; firfilt_crcf_push (_q->lowpass, _x); firfilt_crcf_execute(_q->lowpass, &x0); wdelaycf_push (_q->delay, _x); wdelaycf_read (_q->delay, &x1); // mix each signal down float complex v0, v1; nco_crcf_mix_down(_q->mixer, x0, &v0); nco_crcf_mix_down(_q->mixer, x1, &v1); // compute phase error float phase_error = cimagf(v0); // adjust nco, pll objects nco_crcf_pll_step(_q->mixer, phase_error); // step nco nco_crcf_step(_q->mixer); // apply hilbert transform and retrieve both upper and lower side-bands float m_lsb, m_usb; firhilbf_c2r_execute(_q->hilbert, v1, &m_lsb, &m_usb); // recover message float m = 0.5f * (_q->type == LIQUID_AMPMODEM_USB ? m_usb : m_lsb) / _q->mod_index; // apply DC block, writing directly to output firfilt_rrrf_push (_q->dcblock, m); firfilt_rrrf_execute(_q->dcblock, _y); return LIQUID_OK; } int ampmodem_demod_ssb(ampmodem _q, float complex _x, float * _y) { // apply hilbert transform and retrieve both upper and lower side-bands float m_lsb, m_usb; firhilbf_c2r_execute(_q->hilbert, _x, &m_lsb, &m_usb); // recover message *_y = 0.5f * (_q->type == LIQUID_AMPMODEM_USB ? m_usb : m_lsb) / _q->mod_index; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/cpfskdem.proto.c000066400000000000000000000413211474751757600214030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // continuous phase frequency-shift keying demodulator #include #include #include #include "liquid.internal.h" #define DEBUG_CPFSKDEM() 0 // initialize coherent demodulator int CPFSKDEM(_init_coherent)(CPFSKDEM() _q); // initialize non-coherent demodulator int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q); // demodulate array of samples (coherent) unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, TC * _y); // demodulate array of samples (non-coherent) unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, TC * _y); // cpfskdem struct CPFSKDEM(_s) { // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol unsigned int m; // filter delay (symbols) float beta; // filter bandwidth parameter float h; // modulation index int type; // filter type (e.g. LIQUID_CPFSK_GMSK) unsigned int M; // constellation size unsigned int symbol_delay; // receiver filter delay [symbols] // demodulator type enum { CPFSKDEM_COHERENT=0, // coherent demodulator CPFSKDEM_NONCOHERENT // non-coherent demodulator } demod_type; // demodulation function pointer #if 0 void (*demodulate)(CPFSKDEM() _q, TC _y, unsigned int * _s, unsigned int * _nw); #else unsigned int (*demodulate)(CPFSKDEM() _q, TC * _y); #endif // common data structure shared between coherent and non-coherent // demodulator receivers union { // coherent demodulator struct { //nco_crcf nco; // oscillator/phase-locked loop //firpfb_crcf mf; // matched filter //firpfb_crcf dmf; // matched filter (derivative) //eqlms_rrrf equalizer; } coherent; // non-coherent demodulator struct { firfilt_crcf mf; // matched filter } noncoherent; } demod; // state variables unsigned int index; // debug unsigned int counter; // sample counter float complex z_prime; // (coherent only) }; // create CPFSKDEM() object (frequency demodulator) // _bps : bits per symbol, _bps > 0 // _h : modulation index, _h > 0 // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) CPFSKDEM() CPFSKDEM(_create)(unsigned int _bps, float _h, unsigned int _k, unsigned int _m, float _beta, int _type) { // validate input if (_bps == 0) return liquid_error_config("cpfskdem_create(), bits/symbol must be greater than 0"); if (_h <= 0.0f) return liquid_error_config("cpfskdem_create(), modulation index must be greater than 0"); if (_k < 2 || (_k%2)) return liquid_error_config("cpfskdem_create(), samples/symbol must be greater than 2 and even"); if (_m == 0) return liquid_error_config("cpfskdem_create(), filter delay must be greater than 0"); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("cpfskdem_create(), filter roll-off must be in (0,1]"); switch(_type) { case LIQUID_CPFSK_SQUARE: case LIQUID_CPFSK_RCOS_FULL: case LIQUID_CPFSK_RCOS_PARTIAL: case LIQUID_CPFSK_GMSK: break; default: return liquid_error_config("cpfskdem_create(), invalid filter type '%d'", _type); } // create main object memory CPFSKDEM() q = (cpfskdem) malloc(sizeof(struct CPFSKDEM(_s))); // set basic internal properties q->bps = _bps; // bits per symbol q->h = _h; // modulation index q->k = _k; // samples per symbol q->m = _m; // filter delay (symbols) q->beta = _beta; // filter roll-off factor (only for certain filters) q->type = _type; // filter type // derived values q->M = 1 << q->bps; // constellation size // coherent or non-coherent? // TODO: allow user to specify if (q->h > 0.66667f) { //cpfskdem_init_noncoherent(q); fprintf(stderr,"warning: cpfskdem_create(), coherent demodulation with h > 2/3 not recommended\n"); } CPFSKDEM(_init_noncoherent)(q); // reset modem object CPFSKDEM(_reset)(q); #if DEBUG_CPFSKDEM printf("clear all; close all; y=[]; z=[];\n"); #endif return q; } // Copy object including all internal objects and state CPFSKDEM() CPFSKDEM(_copy)(CPFSKDEM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("cpfskdem_copy(), object cannot be NULL"); // create filter object and copy base parameters CPFSKDEM() q_copy = (CPFSKDEM()) malloc(sizeof(struct CPFSKDEM(_s))); memmove(q_copy, q_orig, sizeof(struct CPFSKDEM(_s))); // copy objects if (q_orig->demod_type == CPFSKDEM_COHERENT) { //return liquid_error_config("cpfskdem_copy(), coherent mode not supported"); liquid_error(LIQUID_EINT,"cpfskdem_copy(), coherent mode not supported"); return NULL; } else { q_copy->demod.noncoherent.mf = firfilt_crcf_copy(q_orig->demod.noncoherent.mf); } // return new object return q_copy; } // create demodulator object for minimum-shift keying // _k : samples/symbol, _k > 1, _k even CPFSKDEM() CPFSKDEM(_create_msk)(unsigned int _k) { return CPFSKDEM(_create)(1, 0.5f, _k, 1, 1.0f, LIQUID_CPFSK_SQUARE); } // create demodulator object for Gauss minimum-shift keying // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _BT : bandwidth-time factor, 0 < _BT < 1 CPFSKDEM() CPFSKDEM(_create_gmsk)(unsigned int _k, unsigned int _m, float _BT) { return CPFSKDEM(_create)(1, 0.5f, _k, _m, _BT, LIQUID_CPFSK_GMSK); } // initialize non-coherent demodulator int CPFSKDEM(_init_coherent)(CPFSKDEM() _q) { return liquid_error(LIQUID_EUMODE,"cpfskdem_init_coherent(), unsupported mode"); } // initialize noncoherent demodulator int CPFSKDEM(_init_noncoherent)(CPFSKDEM() _q) { // specify coherent receiver _q->demod_type = CPFSKDEM_NONCOHERENT; // set demodulate function pointer _q->demodulate = cpfskdem_demodulate_noncoherent; // create object depending upon input type float bw = 0.0f; float beta = 0.0f; float gmsk_bt = _q->beta; switch(_q->type) { case LIQUID_CPFSK_SQUARE: //bw = 0.9f / (float)k; bw = 0.4f; _q->symbol_delay = _q->m; _q->demod.noncoherent.mf = firfilt_crcf_create_kaiser(2*_q->k*_q->m+1, bw, 60.0f, 0.0f); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.0f * bw); break; case LIQUID_CPFSK_RCOS_FULL: if (_q->M==2) { _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.5f,0); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 1.33f / (float)_q->k); _q->symbol_delay = _q->m; } else { _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.9f,0); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 3.25f / (float)_q->k); _q->symbol_delay = 0; // TODO: fix this value } break; case LIQUID_CPFSK_RCOS_PARTIAL: if (_q->M==2) { _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,0.3f,0); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 1.10f / (float)_q->k); _q->symbol_delay = _q->m; } else { _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k/2,2*_q->m,0.27f,0); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.90f / (float)_q->k); _q->symbol_delay = 0; // TODO: fix this value } break; case LIQUID_CPFSK_GMSK: bw = 0.5f / (float)_q->k; // TODO: figure out beta value here beta = (_q->M == 2) ? 0.8*gmsk_bt : 1.0*gmsk_bt; _q->demod.noncoherent.mf = firfilt_crcf_create_rnyquist(LIQUID_FIRFILT_GMSKRX,_q->k,_q->m,beta,0); firfilt_crcf_set_scale(_q->demod.noncoherent.mf, 2.0f * bw); _q->symbol_delay = _q->m; break; default: return liquid_error(LIQUID_EICONFIG,"cpfskdem_init_noncoherent(), invalid tx filter type"); } return LIQUID_OK; } // destroy modem object int CPFSKDEM(_destroy)(CPFSKDEM() _q) { #if DEBUG_CPFSKDEM printf("figure('position',[100 100 400 400]);\n"); printf("n=length(z); i=1:%u:n; plot(z,'-',z(i),'o');\n", _q->k); printf("axis square; axis([-1 1 -1 1]*1.5); grid on;\n"); #endif switch(_q->demod_type) { case CPFSKDEM_COHERENT: return liquid_error(LIQUID_EINT,"cpfskdem_destroy(), coherent mode not supported"); break; case CPFSKDEM_NONCOHERENT: firfilt_crcf_destroy(_q->demod.noncoherent.mf); break; } // free main object memory free(_q); return LIQUID_OK; } // print modulation internals int CPFSKDEM(_print)(CPFSKDEM() _q) { printf("bps, _q->h, _q->k, _q->m, _q->beta); switch(_q->type) { case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; case LIQUID_CPFSK_RCOS_FULL: printf(", type=\"rcos-full\""); break; case LIQUID_CPFSK_RCOS_PARTIAL: printf(", type=\"rcos-partial\""); break; case LIQUID_CPFSK_GMSK: printf(", type=\"gmsk\""); break; default:; } printf(">\n"); return LIQUID_OK; } // reset modem object int CPFSKDEM(_reset)(CPFSKDEM() _q) { switch(_q->demod_type) { case CPFSKDEM_COHERENT: firfilt_crcf_reset(_q->demod.noncoherent.mf); break; case CPFSKDEM_NONCOHERENT: break; default: break; } _q->index = 0; _q->counter = _q->k-1; _q->z_prime = 0; return LIQUID_OK; } // Get demodulator's number of bits per symbol unsigned int CPFSKDEM(_get_bits_per_symbol)(CPFSKDEM() _q) { return _q->bps; } // Get demodulator's modulation index float CPFSKDEM(_get_modulation_index)(CPFSKDEM() _q) { return _q->h; } // Get demodulator's number of samples per symbol unsigned int CPFSKDEM(_get_samples_per_symbol)(CPFSKDEM() _q) { return _q->k; } // Get demodulator's filter delay [symbols] unsigned int CPFSKDEM(_get_delay)(CPFSKDEM() _q) { return _q->symbol_delay; } // Get demodulator's bandwidth parameter float CPFSKDEM(_get_beta)(CPFSKDEM() _q) { return _q->beta; } // Get demodulator's filter type int CPFSKDEM(_get_type)(CPFSKDEM() _q) { return _q->type; } #if 0 // demodulate array of samples // _q : continuous-phase frequency demodulator object // _y : input sample array [size: _n x 1] // _n : input sample array length // _s : output symbol array // _nw : number of output symbols written int CPFSKDEM(_demodulate)(CPFSKDEM() _q, TC * _y, unsigned int _n, unsigned int * _s, unsigned int * _nw) { // iterate through each sample calling type-specific demodulation function unsigned int i; unsigned int num_written = 0; for (i=0; i<_n; i++) { unsigned int nw; _q->demodulate(_q, _y[i], &_s[num_written], &nw); // update number of symbols written num_written += nw; } // set output number of bits written *_nw = num_written; return LIQUID_OK; } // demodulate array of samples (coherent) int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, TC _y, unsigned int * _s, unsigned int * _nw) { // clear output counter *_nw = 0; // push input sample through filter firfilt_crcf_push(_q->demod.noncoherent.mf, _y); #if DEBUG_CPFSKDEM // compute output sample float complex zp; firfilt_crcf_execute(_q->demod.noncoherent.mf, &zp); printf("y(end+1) = %12.8f + 1i*%12.8f;\n", crealf(_y), cimagf(_y)); printf("z(end+1) = %12.8f + 1i*%12.8f;\n", crealf(zp), cimagf(zp)); #endif // decimate output _q->counter++; if ( (_q->counter % _q->k)==0 ) { // reset sample counter _q->counter = 0; // compute output sample float complex z; firfilt_crcf_execute(_q->demod.noncoherent.mf, &z); // compute instantaneous frequency scaled by modulation index // TODO: pre-compute scaling factor float phi_hat = cargf(conjf(_q->z_prime) * z) / (_q->h * M_PI); // estimate transmitted symbol float v = (phi_hat + (_q->M-1.0))*0.5f; unsigned int sym_out = ((int) roundf(v)) % _q->M; // save current point _q->z_prime = z; #if 1 // print result to screen printf(" %3u : %12.8f + j%12.8f, (%1u)\n", _q->index++, crealf(z), cimagf(z), phi_hat, v, sym_out); #endif // save output *_s = sym_out; *_nw = 1; } return LIQUID_OK; } // demodulate array of samples (non-coherent) int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, float complex _y, unsigned int * _s, unsigned int * _nw) { *_nw = 0; return LIQUID_OK; } #else // demodulate array of samples // _q : continuous-phase frequency demodulator object // _y : input sample array [size: _k x 1] unsigned int CPFSKDEM(_demodulate)(CPFSKDEM() _q, TC * _y) { return _q->demodulate(_q, _y); } // demodulate array of samples (coherent) unsigned int CPFSKDEM(_demodulate_coherent)(CPFSKDEM() _q, TC * _y) { liquid_error(LIQUID_EINT,"cpfskdem_demodulate_coherent(), coherent mode not supported"); return 0; } // demodulate array of samples (non-coherent) unsigned int CPFSKDEM(_demodulate_noncoherent)(CPFSKDEM() _q, TC * _y) { unsigned int i; unsigned int sym_out = 0; for (i=0; i<_q->k; i++) { // push input sample through filter firfilt_crcf_push(_q->demod.noncoherent.mf, _y[i]); #if DEBUG_CPFSKDEM // compute output sample float complex zp; firfilt_crcf_execute(_q->demod.noncoherent.mf, &zp); printf("y(end+1) = %12.8f + %12.8fj;\n", crealf(_y[i]), cimagf(_y[i])); printf("z(end+1) = %12.8f + %12.8fj;\n", crealf( zp), cimagf( zp)); #endif // decimate output if ( i == 0 ) { // compute output sample float complex z; firfilt_crcf_execute(_q->demod.noncoherent.mf, &z); // compute instantaneous frequency scaled by modulation index // TODO: pre-compute scaling factor float phi_hat = cargf(conjf(_q->z_prime) * z) / (_q->h * M_PI); // estimate transmitted symbol float v = (phi_hat + (_q->M-1.0))*0.5f; sym_out = ((int) roundf(v)) % _q->M; // save current point _q->z_prime = z; #if DEBUG_CPFSKDEM // print result to screen printf("%% %3u : %12.8f + j%12.8f, (%1u)\n", _q->index++, crealf(z), cimagf(z), phi_hat, v, sym_out); #endif } } return sym_out; } #endif liquid-dsp-1.7.0/src/modem/src/cpfskmod.proto.c000066400000000000000000000273751474751757600214320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // continuous phase frequency-shift keying modulator #include #include #include #include "liquid.internal.h" // design transmit filter int CPFSKMOD(_firdes)(unsigned int _k, unsigned int _m, float _beta, int _type, float * _h, unsigned int _h_len); struct CPFSKMOD(_s) { // common unsigned int bps; // bits per symbol unsigned int k; // samples per symbol unsigned int m; // filter delay (symbols) float beta; // filter bandwidth parameter float h; // modulation index int type; // filter type (e.g. LIQUID_CPFSK_SQUARE) unsigned int M; // constellation size unsigned int symbol_delay; // transmit filter delay [symbols] // pulse-shaping filter T * ht; // filter coefficients unsigned int ht_len; // filter length firinterp_rrrf interp; // phase interpolator // phase integrator T * phase_interp; // phase interpolation buffer T b0, b1, a1, v0, v1; // integrator }; // create CPFSKMOD() object (frequency modulator) // _bps : bits per symbol, _bps > 0 // _h : modulation index, _h > 0 // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _beta : filter bandwidth parameter, _beta > 0 // _type : filter type (e.g. LIQUID_CPFSK_SQUARE) CPFSKMOD() CPFSKMOD(_create)(unsigned int _bps, float _h, unsigned int _k, unsigned int _m, float _beta, int _type) { // validate input if (_bps == 0) return liquid_error_config("cpfskmod_create(), bits/symbol must be greater than 0"); if (_h <= 0.0f) return liquid_error_config("cpfskmod_create(), modulation index must be greater than 0"); if (_k < 2 || (_k%2)) return liquid_error_config("cpfskmod_create(), samples/symbol must be greater than 2 and even"); if (_m == 0) return liquid_error_config("cpfskmod_create(), filter delay must be greater than 0"); if (_beta <= 0.0f || _beta > 1.0f) return liquid_error_config("cpfskmod_create(), filter roll-off must be in (0,1]"); switch(_type) { case LIQUID_CPFSK_SQUARE: case LIQUID_CPFSK_RCOS_FULL: case LIQUID_CPFSK_RCOS_PARTIAL: case LIQUID_CPFSK_GMSK: break; default: return liquid_error_config("cpfskmod_create(), invalid filter type '%d'", _type); } // create main object memory CPFSKMOD() q = (CPFSKMOD()) malloc(sizeof(struct CPFSKMOD(_s))); // set basic internal properties q->bps = _bps; // bits per symbol q->h = _h; // modulation index q->k = _k; // samples per symbol q->m = _m; // filter delay (symbols) q->beta = _beta; // filter roll-off factor (only for certain filters) q->type = _type; // filter type // derived values q->M = 1 << q->bps; // constellation size // create object depending upon input type q->b0 = 0.5f; q->b1 = 0.5f; q->a1 = -1.0f; q->ht_len = 0; q->ht = NULL; unsigned int i; switch(q->type) { case LIQUID_CPFSK_SQUARE: q->ht_len = q->k; q->symbol_delay = 1; // modify integrator q->b0 = 0.0f; q->b1 = 1.0f; break; case LIQUID_CPFSK_RCOS_FULL: q->ht_len = q->k; q->symbol_delay = 1; break; case LIQUID_CPFSK_RCOS_PARTIAL: // TODO: adjust response based on 'm' q->ht_len = 3*q->k; q->symbol_delay = 2; break; case LIQUID_CPFSK_GMSK: q->symbol_delay = q->m + 1; q->ht_len = 2*(q->k)*(q->m) + (q->k) + 1; break; default: return liquid_error_config("cpfskmod_create(), invalid filter type '%d'", q->type); } // create pulse-shaping filter and scale by modulation index q->ht = (T*) malloc(q->ht_len *sizeof(T)); CPFSKMOD(_firdes)(q->k, q->m, q->beta, q->type, q->ht, q->ht_len); for (i=0; iht_len; i++) q->ht[i] *= M_PI * q->h; q->interp = firinterp_rrrf_create(q->k, q->ht, q->ht_len); // allocate buffer for phase interpolation q->phase_interp = (T*) malloc(q->k*sizeof(T)); // reset modem object cpfskmod_reset(q); return q; } // create modulator object for minimum-shift keying // _k : samples/symbol, _k > 1, _k even CPFSKMOD() CPFSKMOD(_create_msk)(unsigned int _k) { return CPFSKMOD(_create)(1, 0.5f, _k, 1, 1.0f, LIQUID_CPFSK_SQUARE); } // create modulator object for minimum-shift keying // _k : samples/symbol, _k > 1, _k even // _m : filter delay (symbols), _m > 0 // _BT : bandwidth-time factor, 0 < _BT < 1 CPFSKMOD() CPFSKMOD(_create_gmsk)(unsigned int _k, unsigned int _m, float _BT) { return CPFSKMOD(_create)(1, 0.5f, _k, _m, _BT, LIQUID_CPFSK_GMSK); } // Copy object including all internal objects and state CPFSKMOD() CPFSKMOD(_copy)(CPFSKMOD() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("cpfskmod_copy(), object cannot be NULL"); // create filter object and copy base parameters CPFSKMOD() q_copy = (CPFSKMOD()) malloc(sizeof(struct CPFSKMOD(_s))); memmove(q_copy, q_orig, sizeof(struct CPFSKMOD(_s))); // copy objects, arrays q_copy->interp = firinterp_rrrf_copy(q_orig->interp); q_copy->ht = (T*) liquid_malloc_copy(q_orig->ht, q_orig->ht_len, sizeof(T)); q_copy->phase_interp = (T*) liquid_malloc_copy(q_orig->phase_interp, q_orig->k, sizeof(T)); // return new object return q_copy; } // destroy modulator object int CPFSKMOD(_destroy)(CPFSKMOD() _q) { // destroy pulse-shaping filter/interpolator free(_q->ht); free(_q->phase_interp); firinterp_rrrf_destroy(_q->interp); // free main object memory free(_q); return LIQUID_OK; } // print modulator object internals int CPFSKMOD(_print)(CPFSKMOD() _q) { printf("bps, _q->h, _q->k, _q->m, _q->beta); switch(_q->type) { case LIQUID_CPFSK_SQUARE: printf(", type=\"square\""); break; case LIQUID_CPFSK_RCOS_FULL: printf(", type=\"rcos-full\""); break; case LIQUID_CPFSK_RCOS_PARTIAL: printf(", type=\"rcos-partial\""); break; case LIQUID_CPFSK_GMSK: printf(", type=\"gmsk\""); break; default:; } printf(">\n"); return LIQUID_OK; } // reset state int CPFSKMOD(_reset)(CPFSKMOD() _q) { // reset interpolator firinterp_rrrf_reset(_q->interp); // reset phase integrator _q->v0 = 0.0f; _q->v1 = 0.0f; return LIQUID_OK; } // Get modulator's number of bits per symbol unsigned int CPFSKMOD(_get_bits_per_symbol)(CPFSKMOD() _q) { return _q->bps; } // Get modulator's modulation index float CPFSKMOD(_get_modulation_index)(CPFSKMOD() _q) { return _q->h; } // Get modulator's number of samples per symbol unsigned int CPFSKMOD(_get_samples_per_symbol)(CPFSKMOD() _q) { return _q->k; } // Get modulator's filter delay [symbols] unsigned int CPFSKMOD(_get_delay)(CPFSKMOD() _q) { return _q->symbol_delay; } // Get modulator's bandwidth parameter float CPFSKMOD(_get_beta)(CPFSKMOD() _q) { return _q->beta; } // Get modulator's filter type int CPFSKMOD(_get_type)(CPFSKMOD() _q) { return _q->type; } // modulate sample // _q : frequency modulator object // _s : input symbol // _y : output sample array [size: _k x 1] int CPFSKMOD(_modulate)(CPFSKMOD() _q, unsigned int _s, TC * _y) { // run interpolator float v = 2.0f*_s - (float)(_q->M) + 1.0f; firinterp_rrrf_execute(_q->interp, v, _q->phase_interp); // integrate phase state unsigned int i; float theta; for (i=0; i<_q->k; i++) { // push phase through integrator _q->v0 = _q->phase_interp[i] - _q->v1*_q->a1; theta = _q->v0*_q->b0 + _q->v1*_q->b1; _q->v1 = _q->v0; // constrain state if (_q->v1 > 2*M_PI) _q->v1 -= 2*M_PI; if (_q->v1 < -2*M_PI) _q->v1 += 2*M_PI; // compute output _y[i] = liquid_cexpjf(theta); } return LIQUID_OK; } // // internal methods // // design transmit filter int CPFSKMOD(_firdes)(unsigned int _k, unsigned int _m, float _beta, int _type, float * _ht, unsigned int _ht_len) { unsigned int i; // create filter based on specified type switch(_type) { case LIQUID_CPFSK_SQUARE: // square pulse if (_ht_len != _k) return liquid_error(LIQUID_EICONFIG,"cpfskmodem_firdes(), invalid filter length (square)"); for (i=0; i<_ht_len; i++) _ht[i] = 1.0f; break; case LIQUID_CPFSK_RCOS_FULL: // full-response raised-cosine pulse if (_ht_len != _k) return liquid_error(LIQUID_EICONFIG,"cpfskmodem_firdes(), invalid filter length (rcos)"); for (i=0; i<_ht_len; i++) _ht[i] = 1.0f - cosf(2.0f*M_PI*i/(float)_ht_len); break; case LIQUID_CPFSK_RCOS_PARTIAL: // full-response raised-cosine pulse if (_ht_len != 3*_k) return liquid_error(LIQUID_EICONFIG,"cpfskmodem_firdes(), invalid filter length (rcos)"); // initialize with zeros for (i=0; i<_ht_len; i++) _ht[i] = 0.0f; // adding raised-cosine pulse with half-symbol delay for (i=0; i<2*_k; i++) _ht[i+_k/2] = 1.0f - cosf(2.0f*M_PI*i/(float)(2*_k)); break; case LIQUID_CPFSK_GMSK: // Gauss minimum-shift keying pulse if (_ht_len != 2*_k*_m + _k + 1) return liquid_error(LIQUID_EICONFIG,"cpfskmodem_firdes(), invalid filter length (gmsk)"); // initialize with zeros for (i=0; i<_ht_len; i++) _ht[i] = 0.0f; // adding Gauss pulse with half-symbol delay liquid_firdes_gmsktx(_k,_m,_beta,0.0f,&_ht[_k/2]); break; default: return liquid_error(LIQUID_EINT,"cpfskmodem_firdes(), invalid filter type '%d'", _type); } // normalize pulse area to unity float ht_sum = 0.0f; for (i=0; i<_ht_len; i++) ht_sum += _ht[i]; for (i=0; i<_ht_len; i++) _ht[i] *= 1.0f / ht_sum; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/freqdem.proto.c000066400000000000000000000065541474751757600212430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Frequency demodulator // #include #include #include #include "liquid.internal.h" // freqdem struct FREQDEM(_s) { // common float kf; // modulation index T ref; // 1/(2*pi*kf) TC r_prime; // previous received sample }; // create freqdem object // _kf : modulation factor FREQDEM() FREQDEM(_create)(float _kf) { // validate input if (_kf <= 0.0f) return liquid_error_config("freqdem%s_create(), modulation factor %12.4e must be greater than 0", EXTENSION, _kf); // create main object memory FREQDEM() q = (freqdem) malloc(sizeof(struct FREQDEM(_s))); // set internal modulation factor q->kf = _kf; // compute derived values q->ref = 1.0f / (2*M_PI*q->kf); // reset modem object FREQDEM(_reset)(q); // return object return q; } // destroy modem object int FREQDEM(_destroy)(FREQDEM() _q) { // free main object memory free(_q); return LIQUID_OK; } // print modulation internals int FREQDEM(_print)(FREQDEM() _q) { printf("\n", _q->kf); return LIQUID_OK; } // reset modem object int FREQDEM(_reset)(FREQDEM() _q) { // clear complex phase term _q->r_prime = 0; return LIQUID_OK; } // demodulate sample // _q : FM demodulator object // _r : received signal // _m : output message signal int FREQDEM(_demodulate)(FREQDEM() _q, TC _r, T * _m) { // compute phase difference and normalize by modulation index *_m = cargf( conjf(_q->r_prime)*_r ) * _q->ref; // save previous input sample _q->r_prime = _r; return LIQUID_OK; } // demodulate block of samples // _q : frequency demodulator object // _r : received signal r(t) [size: _n x 1] // _n : number of input, output samples // _m : message signal m(t), [size: _n x 1] int FREQDEM(_demodulate_block)(FREQDEM() _q, TC * _r, unsigned int _n, T * _m) { // TODO: implement more efficient method unsigned int i; for (i=0; i<_n; i++) FREQDEM(_demodulate)(_q, _r[i], &_m[i]); return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/freqmod.proto.c000066400000000000000000000105331474751757600212450ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Frequency modulator // #include #include #include #include #include "liquid.internal.h" // freqmod struct FREQMOD(_s) { float kf; // modulation factor for FM T ref; // phase reference: kf*2^16 // look-up table unsigned int sincos_table_len; // table length: 10 bits uint16_t sincos_table_phase; // accumulated phase: 16 bits TC * sincos_table; // sin|cos look-up table: 2^10 entries }; // create freqmod object // _kf : modulation factor FREQMOD() FREQMOD(_create)(float _kf) { // validate input if (_kf <= 0.0f) return liquid_error_config("freqmod%s_create(), modulation factor %12.4e must be greater than 0", EXTENSION, _kf); // create main object memory FREQMOD() q = (freqmod) malloc(sizeof(struct FREQMOD(_s))); // set modulation factor q->kf = _kf; q->ref = q->kf * (1<<16); // initialize look-up table q->sincos_table_len = 1024; q->sincos_table = (TC*) malloc( q->sincos_table_len*sizeof(TC) ); unsigned int i; for (i=0; isincos_table_len; i++) { q->sincos_table[i] = cexpf(_Complex_I*2*M_PI*(float)i / (float)(q->sincos_table_len) ); } // reset modem object FREQMOD(_reset)(q); // return object return q; } // destroy modem object int FREQMOD(_destroy)(FREQMOD() _q) { // free table free(_q->sincos_table); // free main object memory free(_q); return LIQUID_OK; } // print modulation internals int FREQMOD(_print)(FREQMOD() _q) { printf("kf); printf(", tablen=%u", _q->sincos_table_len); printf(">\n"); return LIQUID_OK; } // reset modem object int FREQMOD(_reset)(FREQMOD() _q) { // reset phase accumulation _q->sincos_table_phase = 0; return LIQUID_OK; } // modulate sample // _q : frequency modulator object // _m : message signal m(t) // _s : complex baseband signal s(t) int FREQMOD(_modulate)(FREQMOD() _q, T _m, TC * _s) { // accumulate phase; this wraps around a 16-bit boundary and ensures // that negative numbers are mapped to positive numbers _q->sincos_table_phase = (_q->sincos_table_phase + (1<<16) + (int)roundf(_q->ref*_m)) & 0xffff; // compute table index: mask out 10 most significant bits with rounding // (adding 0x0020 effectively rounds to nearest value with 10 bits of // precision) unsigned int index = ( (_q->sincos_table_phase+0x0020) >> 6) & 0x03ff; // return table value at index *_s = _q->sincos_table[index]; return LIQUID_OK; } // modulate block of samples // _q : frequency modulator object // _m : message signal m(t), [size: _n x 1] // _n : number of input, output samples // _s : complex baseband signal s(t) [size: _n x 1] int FREQMOD(_modulate_block)(FREQMOD() _q, T * _m, unsigned int _n, TC * _s) { // TODO: implement more efficient method unsigned int i; for (i=0; i<_n; i++) FREQMOD(_modulate)(_q, _m[i], &_s[i]); return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/fskdem.c000066400000000000000000000232301474751757600177150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // M-ary frequency-shift keying demodulator #include #include #include #include #include "liquid.internal.h" #define DEBUG_FSKDEM 0 // fskdem struct fskdem_s { // common unsigned int m; // bits per symbol unsigned int k; // samples per symbol float bandwidth; // filter bandwidth parameter // derived values unsigned int M; // constellation size float M2; // (M-1)/2 unsigned int K; // FFT size float complex * buf_time; // FFT input buffer float complex * buf_freq; // FFT output buffer FFT_PLAN fft; // FFT object unsigned int * demod_map; // demodulation map // state variables unsigned int s_demod; // demodulated symbol (used for frequency error) }; // create fskdem object (frequency demodulator) // _m : bits per symbol, _m > 0 // _k : samples/symbol, _k >= 2^_m // _bandwidth : total signal bandwidth, (0,0.5) fskdem fskdem_create(unsigned int _m, unsigned int _k, float _bandwidth) { // validate input if (_m == 0) return liquid_error_config("fskdem_create(), bits/symbol must be greater than 0"); if (_k < 2 || _k > 2048) return liquid_error_config("fskdem_create(), samples/symbol must be in [2^_m, 2048]"); if (_bandwidth <= 0.0f || _bandwidth >= 0.5f) return liquid_error_config("fskdem_create(), bandwidth must be in (0,0.5)"); // create main object memory fskdem q = (fskdem) malloc(sizeof(struct fskdem_s)); // set basic internal properties q->m = _m; // bits per symbol q->k = _k; // samples per symbol q->bandwidth = _bandwidth; // signal bandwidth // derived values q->M = 1 << q->m; // constellation size q->M2 = 0.5f*(float)(q->M-1); // (M-1)/2 // compute demodulation FFT size such that FFT output bin frequencies are // as close to modulated frequencies as possible float df = q->bandwidth / q->M2; // frequency spacing float err_min = 1e9f; // minimum error value unsigned int K_min = q->k; // minimum FFT size unsigned int K_max = q->k*4 < 16 ? 16 : q->k*4; // maximum FFT size unsigned int K_hat; for (K_hat=K_min; K_hat<=K_max; K_hat++) { // compute candidate FFT size float v = 0.5f*df*(float)K_hat; // bin spacing float err = fabsf( roundf(v) - v ); // fractional bin spacing #if DEBUG_FSKDEM // print results printf(" K_hat = %4u : v = %12.8f, err=%12.8f %s\n", K_hat, v, err, err < err_min ? "*" : ""); #endif // save best result if (K_hat==K_min || err < err_min) { q->K = K_hat; err_min = err; } // perfect match; no need to continue searching if (err < 1e-6f) break; } // determine demodulation mapping between tones and frequency bins // TODO: use gray coding q->demod_map = (unsigned int *) malloc(q->M * sizeof(unsigned int)); unsigned int i; for (i=0; iM; i++) { // print frequency bins float freq = ((float)i - q->M2) * q->bandwidth / q->M2; float idx = freq * (float)(q->K); unsigned int index = (unsigned int) (idx < 0 ? roundf(idx + q->K) : roundf(idx)); q->demod_map[i] = index; #if DEBUG_FSKDEM printf(" s=%3u, f = %12.8f, index=%3u\n", i, freq, index); #endif } // check for uniqueness for (i=1; iM; i++) { if (q->demod_map[i] == q->demod_map[i-1]) { liquid_error(LIQUID_EICONFIG,"fskdem_create(), demod map is not unique; consider increasing bandwidth"); break; } } // allocate memory for transform q->buf_time = (float complex*) FFT_MALLOC(q->K * sizeof(float complex)); q->buf_freq = (float complex*) FFT_MALLOC(q->K * sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->K, q->buf_time, q->buf_freq, FFT_DIR_FORWARD, 0); // reset modem object fskdem_reset(q); // return main object return q; } // copy object fskdem fskdem_copy(fskdem q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("fskdem_copy(), object cannot be NULL"); // create object and copy base parameters fskdem q_copy = (fskdem) malloc(sizeof(struct fskdem_s)); memmove(q_copy, q_orig, sizeof(struct fskdem_s)); // allocate memory for transform q_copy->buf_time = (float complex*) FFT_MALLOC(q_copy->K * sizeof(float complex)); q_copy->buf_freq = (float complex*) FFT_MALLOC(q_copy->K * sizeof(float complex)); q_copy->fft = FFT_CREATE_PLAN(q_copy->K, q_copy->buf_time, q_copy->buf_freq, FFT_DIR_FORWARD, 0); // copy internal time and frequency buffers memmove(q_copy->buf_time, q_orig->buf_time, q_copy->K * sizeof(float complex)); memmove(q_copy->buf_freq, q_orig->buf_freq, q_copy->K * sizeof(float complex)); // copy demodulation map q_copy->demod_map = (unsigned int*)liquid_malloc_copy(q_orig->demod_map, q_copy->M, sizeof(unsigned int)); // return new object return q_copy; } // destroy fskdem object int fskdem_destroy(fskdem _q) { // free allocated arrays free(_q->demod_map); FFT_FREE(_q->buf_time); FFT_FREE(_q->buf_freq); FFT_DESTROY_PLAN(_q->fft); // free main object memory free(_q); return LIQUID_OK; } // print fskdem object internals int fskdem_print(fskdem _q) { printf("m); printf(", samples/symbol=%u", _q->k); printf(", bandwidth=%g", _q->bandwidth); printf(">\n"); return LIQUID_OK; } // reset state int fskdem_reset(fskdem _q) { // reset time and frequency buffers unsigned int i; for (i=0; i<_q->K; i++) { _q->buf_time[i] = 0.0f; _q->buf_freq[i] = 0.0f; } // clear state variables _q->s_demod = 0; return LIQUID_OK; } // demodulate symbol, assuming perfect symbol timing // _q : fskdem object // _y : input sample array [size: _k x 1] unsigned int fskdem_demodulate(fskdem _q, float complex * _y) { // copy input to internal time buffer memmove(_q->buf_time, _y, _q->k*sizeof(float complex)); // compute transform, storing result in 'buf_freq' FFT_EXECUTE(_q->fft); // find maximum by looking at particular bins float vmax = 0; unsigned int s = 0; // run search for (s=0; s<_q->M; s++) { float v = cabsf( _q->buf_freq[_q->demod_map[s]] ); if (s==0 || v > vmax) { // save optimal output symbol _q->s_demod = s; // save peak FFT bin value vmax = v; } } // save best result return _q->s_demod; } // get demodulator frequency error float fskdem_get_frequency_error(fskdem _q) { // get index of peak bin //unsigned int index = _q->buf_freq[ _q->s_demod ]; // extract peak value of previous, post FFT index float vm = cabsf(_q->buf_freq[(_q->s_demod+_q->K-1)%_q->K]); // previous float v0 = cabsf(_q->buf_freq[ _q->s_demod ]); // peak float vp = cabsf(_q->buf_freq[(_q->s_demod+ 1)%_q->K]); // post // compute derivative // TODO: compensate for bin spacing // TODO: just find peak using polynomial interpolation return (vp - vm) / v0; } // get energy for a particular symbol within a certain range float fskdem_get_symbol_energy(fskdem _q, unsigned int _s, unsigned int _range) { // validate input if (_s >= _q->M) { liquid_error(LIQUID_EICONFIG,"fskdem_get_symbol_energy(), input symbol (%u) exceeds maximum (%u)", _s, _q->M); _s = 0; } if (_range > _q->K) _range = _q->K; // map input symbol to FFT bin unsigned int index = _q->demod_map[_s]; // compute energy around FFT bin float complex v = _q->buf_freq[index]; float energy = crealf(v)*crealf(v) + cimagf(v)*cimagf(v); int i; for (i=0; i<_range; i++) { // positive negative indices unsigned int i0 = (index + i) % _q->K; unsigned int i1 = (index + _q->K - i) % _q->K; float complex v0 = _q->buf_freq[i0]; float complex v1 = _q->buf_freq[i1]; energy += crealf(v0)*crealf(v0) + cimagf(v0)*cimagf(v0); energy += crealf(v1)*crealf(v1) + cimagf(v1)*cimagf(v1); } return energy; } liquid-dsp-1.7.0/src/modem/src/fskmod.c000066400000000000000000000113741474751757600177350ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // M-ary frequency-shift keying modulator #include #include #include #include #include "liquid.internal.h" // fskmod struct fskmod_s { // common unsigned int m; // bits per symbol unsigned int k; // samples per symbol float bandwidth; // filter bandwidth parameter unsigned int M; // constellation size float M2; // (M-1)/2 nco_crcf oscillator; // nco }; // create fskmod object (frequency modulator) // _m : bits per symbol, _m > 0 // _k : samples/symbol, _k >= 2^_m // _bandwidth : total signal bandwidth, (0,0.5) fskmod fskmod_create(unsigned int _m, unsigned int _k, float _bandwidth) { // validate input if (_m == 0) return liquid_error_config("fskmod_create(), bits/symbol must be greater than 0"); if (_k < 2 || _k > 2048) return liquid_error_config("fskmod_create(), samples/symbol must be in [2^_m, 2048]"); if (_bandwidth <= 0.0f || _bandwidth >= 0.5f) return liquid_error_config("fskmod_create(), bandwidth must be in (0,0.5)"); // create main object memory fskmod q = (fskmod) malloc(sizeof(struct fskmod_s)); // set basic internal properties q->m = _m; // bits per symbol q->k = _k; // samples per symbol q->bandwidth = _bandwidth; // signal bandwidth // derived values q->M = 1 << q->m; // constellation size q->M2 = 0.5f*(float)(q->M-1); // (M-1)/2 q->oscillator = nco_crcf_create(LIQUID_VCO); // reset modem object fskmod_reset(q); // return main object return q; } // copy object fskmod fskmod_copy(fskmod q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("fskmod_copy(), object cannot be NULL"); // create object and copy base parameters fskmod q_copy = (fskmod) malloc(sizeof(struct fskmod_s)); memmove(q_copy, q_orig, sizeof(struct fskmod_s)); // copy oscillator object q_copy->oscillator = nco_crcf_copy(q_orig->oscillator); // return new object return q_copy; } // destroy fskmod object int fskmod_destroy(fskmod _q) { // destroy oscillator object nco_crcf_destroy(_q->oscillator); // free main object memory free(_q); return LIQUID_OK; } // print fskmod object internals int fskmod_print(fskmod _q) { printf("m); printf(", samples/symbol=%u", _q->k); printf(", bandwidth=%g", _q->bandwidth); printf(">\n"); return LIQUID_OK; } // reset state int fskmod_reset(fskmod _q) { // reset internal objects nco_crcf_reset(_q->oscillator); return LIQUID_OK; } // modulate sample // _q : frequency modulator object // _s : input symbol // _y : output sample array [size: _k x 1] int fskmod_modulate(fskmod _q, unsigned int _s, float complex * _y) { // validate input if (_s >= _q->M) return liquid_error(LIQUID_EIRANGE,"fskmod_modulate(), input symbol (%u) exceeds maximum (%u)",_s, _q->M); // compute appropriate frequency float dphi = ((float)_s - _q->M2) * 2 * M_PI * _q->bandwidth / _q->M2; // set frequency appropriately nco_crcf_set_frequency(_q->oscillator, dphi); // generate output tone unsigned int i; for (i=0; i<_q->k; i++) { // compute complex output nco_crcf_cexpf(_q->oscillator, &_y[i]); // step oscillator nco_crcf_step(_q->oscillator); } return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/gmskdem.c000066400000000000000000000236131474751757600201000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // Gauss minimum-shift keying modem #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_GMSKDEM 0 #define DEBUG_GMSKDEM_FILENAME "gmskdem_internal_debug.m" #define DEBUG_BUFFER_LEN (1000) #define GMSKDEM_USE_EQUALIZER 0 int gmskdem_debug_print(gmskdem _q, const char * _filename); struct gmskdem_s { unsigned int k; // samples/symbol unsigned int m; // symbol delay float BT; // bandwidth/time product unsigned int h_len; // filter length float * h; // pulse shaping filter // filter object #if GMSKDEM_USE_EQUALIZER eqlms_rrrf eq; // receiver matched filter/equalizer float k_inv; // 1 / k #else firfilt_rrrf filter; // receiver matched filter #endif float complex x_prime; // received signal state // demodulated symbols counter unsigned int num_symbols_demod; #if DEBUG_GMSKDEM windowf debug_mfout; #endif }; // create gmskdem object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskdem gmskdem_create(unsigned int _k, unsigned int _m, float _BT) { if (_k < 2) return liquid_error_config("gmskdem_create(), samples/symbol must be at least 2"); if (_m < 1) return liquid_error_config("gmskdem_create(), symbol delay must be at least 1"); if (_BT <= 0.0f || _BT >= 1.0f) return liquid_error_config("gmskdem_create(), bandwidth/time product must be in (0,1)"); // allocate memory for main object gmskdem q = (gmskdem)malloc(sizeof(struct gmskdem_s)); // set properties q->k = _k; q->m = _m; q->BT = _BT; // allocate memory for filter taps q->h_len = 2*(q->k)*(q->m)+1; q->h = (float*) malloc(q->h_len * sizeof(float)); // compute filter coefficients liquid_firdes_gmskrx(q->k, q->m, q->BT, 0.0f, q->h); #if GMSKDEM_USE_EQUALIZER // receiver matched filter/equalizer q->eq = eqlms_rrrf_create_rnyquist(LIQUID_FIRFILT_GMSKRX, q->k, q->m, q->BT, 0.0f); eqlms_rrrf_set_bw(q->eq, 0.01f); q->k_inv = 1.0f / (float)(q->k); #else // create filter object q->filter = firfilt_rrrf_create(q->h, q->h_len); #endif // reset modem state gmskdem_reset(q); #if DEBUG_GMSKDEM q->debug_mfout = windowf_create(DEBUG_BUFFER_LEN); #endif // return modem object return q; } // copy object gmskdem gmskdem_copy(gmskdem q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("gmskdem_copy(), object cannot be NULL"); // create object and copy base parameters gmskdem q_copy = (gmskdem) malloc(sizeof(struct gmskdem_s)); memmove(q_copy, q_orig, sizeof(struct gmskdem_s)); // copy filter coefficients q_copy->h = (float *) liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(float)); #if GMSKDEM_USE_EQUALIZER q_copy->eq = eqlms_rrrf_copy(q_orig->eq); #else // copy interpolator object q_copy->filter = firfilt_rrrf_copy(q_orig->filter); #endif #if DEBUG_GMSKDEM q_copy->debug_mfout = windowf_copy(q_orig->debug_mfout); #endif // return new object return q_copy; } int gmskdem_destroy(gmskdem _q) { #if DEBUG_GMSKDEM // print to external file gmskdem_debug_print(_q, DEBUG_GMSKDEM_FILENAME); // destroy debugging objects windowf_destroy(_q->debug_mfout); #endif // destroy filter object #if GMSKDEM_USE_EQUALIZER eqlms_rrrf_destroy(_q->eq); #else firfilt_rrrf_destroy(_q->filter); #endif // free filter array free(_q->h); // free main object memory free(_q); return LIQUID_OK; } int gmskdem_print(gmskdem _q) { printf("k, _q->m, _q->BT); #if GMSKDEM_USE_EQUALIZER printf(", eq_bw=%g", eqlms_rrrf_get_bw(_q->eq)); #endif //unsigned int i; //for (i=0; i<_q->h_len; i++) // printf(" hr(%4u) = %12.8f;\n", i+1, _q->h[i]); printf(">\n"); return LIQUID_OK; } int gmskdem_reset(gmskdem _q) { // reset phase state _q->x_prime = 0.0f; // set demod. counter to zero _q->num_symbols_demod = 0; // clear filter buffer #if GMSKDEM_USE_EQUALIZER eqlms_rrrf_reset(_q->eq); #else firfilt_rrrf_reset(_q->filter); #endif return LIQUID_OK; } // set equalizer bandwidth int gmskdem_set_eq_bw(gmskdem _q, float _bw) { // validate input if (_bw < 0.0f || _bw > 0.5f) return liquid_error(LIQUID_EICONFIG,"gmskdem_set_eq_bw(), bandwidth must be in [0,0.5]"); #if GMSKDEM_USE_EQUALIZER // set internal equalizer bandwidth eqlms_rrrf_set_bw(_q->eq, _bw); #else return liquid_error(LIQUID_ENOIMP,"gmskdem_set_eq_bw(), equalizer is disabled"); #endif return LIQUID_OK; } int gmskdem_demodulate(gmskdem _q, float complex * _x, unsigned int * _s) { // increment symbol counter _q->num_symbols_demod++; // run matched filter unsigned int i; float phi; float d_hat; for (i=0; i<_q->k; i++) { // compute phase difference phi = cargf( conjf(_q->x_prime)*_x[i] ); _q->x_prime = _x[i]; // run through matched filter #if GMSKDEM_USE_EQUALIZER eqlms_rrrf_push(_q->eq, phi); #else firfilt_rrrf_push(_q->filter, phi); #endif #if DEBUG_GMSKDEM // compute output float d_tmp; # if GMSKDEM_USE_EQUALIZER eqlms_rrrf_execute(_q->eq, &d_tmp); # else firfilt_rrrf_execute(_q->filter, &d_tmp); # endif windowf_push(_q->debug_mfout, d_tmp); #endif // decimate by k if ( i != 0 ) continue; #if GMSKDEM_USE_EQUALIZER // compute filter/equalizer output eqlms_rrrf_execute(_q->eq, &d_hat); #else // compute filter output firfilt_rrrf_execute(_q->filter, &d_hat); #endif } // make decision *_s = d_hat > 0.0f ? 1 : 0; #if GMSKDEM_USE_EQUALIZER // update equalizer, after appropriate delay if (_q->num_symbols_demod >= 2*_q->m) { // compute expected output, scaling by samples/symbol float d_prime = d_hat > 0 ? _q->k_inv : -_q->k_inv; eqlms_rrrf_step(_q->eq, d_prime, d_hat); } #endif return LIQUID_OK; } // // output debugging file // int gmskdem_debug_print(gmskdem _q, const char * _filename) { // open output filen for writing FILE * fid = fopen(_filename,"w"); if (!fid) return liquid_error(LIQUID_EIO,"gmskdem_debug_print(), could not open '%s' for writing", _filename); fprintf(fid,"%% %s : auto-generated file\n", _filename); fprintf(fid,"clear all\n"); fprintf(fid,"close all\n"); #if DEBUG_GMSKDEM // unsigned int i; float * r; fprintf(fid,"n = %u;\n", DEBUG_BUFFER_LEN); fprintf(fid,"k = %u;\n", _q->k); fprintf(fid,"m = %u;\n", _q->m); fprintf(fid,"t = [0:(n-1)]/k;\n"); // plot receive filter response fprintf(fid,"ht = zeros(1,2*k*m+1);\n"); float ht[_q->h_len]; liquid_firdes_gmsktx(_q->k, _q->m, _q->BT, 0.0f, ht); for (i=0; i<_q->h_len; i++) fprintf(fid,"ht(%4u) = %12.4e;\n", i+1, ht[i]); #if GMSKDEM_USE_EQUALIZER float hr[_q->h_len]; eqlms_rrrf_get_weights(_q->eq, hr); for (i=0; i<_q->h_len; i++) fprintf(fid,"hr(%4u) = %12.4e * %u;\n", i+1, hr[i], _q->k); #else for (i=0; i<_q->h_len; i++) fprintf(fid,"hr(%4u) = %12.4e;\n", i+1, _q->h[i]); #endif fprintf(fid,"hc = conv(ht,hr)/k;\n"); fprintf(fid,"nfft = 1024;\n"); fprintf(fid,"f = [0:(nfft-1)]/nfft - 0.5;\n"); fprintf(fid,"Ht = 20*log10(abs(fftshift(fft(ht/k, nfft))));\n"); fprintf(fid,"Hr = 20*log10(abs(fftshift(fft(hr/k, nfft))));\n"); fprintf(fid,"Hc = 20*log10(abs(fftshift(fft(hc/k, nfft))));\n"); fprintf(fid,"figure;\n"); fprintf(fid,"plot(f,Ht, f,Hr, f,Hc,'-k','LineWidth',2);\n"); fprintf(fid,"axis([-0.5 0.5 -50 10]);\n"); fprintf(fid,"xlabel('Normalized Frequency');\n"); fprintf(fid,"ylabel('Power Spectral Density [dB]');\n"); fprintf(fid,"legend('transmit','receive','composite',1);\n"); fprintf(fid,"grid on;\n"); fprintf(fid,"mfout = zeros(1,n);\n"); windowf_read(_q->debug_mfout, &r); for (i=0; i #include #include #include #include #include "liquid.internal.h" struct gmskmod_s { unsigned int k; // samples/symbol unsigned int m; // symbol delay float BT; // bandwidth/time product unsigned int h_len; // filter length float * h; // pulse shaping filter // interpolator firinterp_rrrf interp_tx; float theta; // phase state float k_inv; // 1/k }; // create gmskmod object // _k : samples/symbol // _m : filter delay (symbols) // _BT : excess bandwidth factor gmskmod gmskmod_create(unsigned int _k, unsigned int _m, float _BT) { if (_k < 2) return liquid_error_config("gmskmod_create(), samples/symbol must be at least 2"); if (_m < 1) return liquid_error_config("gmskmod_create(), symbol delay must be at least 1"); if (_BT <= 0.0f || _BT >= 1.0f) return liquid_error_config("gmskmod_create(), bandwidth/time product must be in (0,1)"); gmskmod q = (gmskmod)malloc(sizeof(struct gmskmod_s)); // set properties q->k = _k; q->m = _m; q->BT = _BT; // derived values q->k_inv = 1.0f / (float)(q->k); // allocate memory for filter taps q->h_len = 2*(q->k)*(q->m)+1; q->h = (float*) malloc(q->h_len * sizeof(float)); // compute filter coefficients liquid_firdes_gmsktx(q->k, q->m, q->BT, 0.0f, q->h); // create interpolator object q->interp_tx = firinterp_rrrf_create_prototype(LIQUID_FIRFILT_GMSKTX, q->k, q->m, q->BT, 0); // reset modem state gmskmod_reset(q); // return modem object return q; } // copy object gmskmod gmskmod_copy(gmskmod q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("gmskmod_copy(), object cannot be NULL"); // create object and copy base parameters gmskmod q_copy = (gmskmod) malloc(sizeof(struct gmskmod_s)); memmove(q_copy, q_orig, sizeof(struct gmskmod_s)); // copy filter coefficients q_copy->h = (float *) liquid_malloc_copy(q_orig->h, q_orig->h_len, sizeof(float)); // copy interpolator object q_copy->interp_tx = firinterp_rrrf_copy(q_orig->interp_tx); // return new object return q_copy; } int gmskmod_destroy(gmskmod _q) { // destroy interpolator firinterp_rrrf_destroy(_q->interp_tx); // free transmit filter array free(_q->h); // free main object memory free(_q); return LIQUID_OK; } int gmskmod_print(gmskmod _q) { printf("\n", _q->k, _q->m, _q->BT); #if 0 unsigned int i; for (i=0; i<_q->h_len; i++) printf(" ht(%4u) = %12.8f;\n", i+1, _q->h[i]); #endif return LIQUID_OK; } int gmskmod_reset(gmskmod _q) { // reset phase state _q->theta = 0.0f; // clear interpolator buffer firinterp_rrrf_reset(_q->interp_tx); return LIQUID_OK; } int gmskmod_modulate(gmskmod _q, unsigned int _s, float complex * _y) { // generate sample from symbol float x = _s==0 ? -_q->k_inv : _q->k_inv; // run interpolator float phi[_q->k]; firinterp_rrrf_execute(_q->interp_tx, x, phi); // integrate phase state unsigned int i; for (i=0; i<_q->k; i++) { // integrate phase state _q->theta += phi[i]; // ensure phase in [-pi, pi] if (_q->theta > M_PI) _q->theta -= 2*M_PI; if (_q->theta < -M_PI) _q->theta += 2*M_PI; // compute output _y[i] = liquid_cexpjf(_q->theta); } return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem.shim.c000066400000000000000000000053261474751757600205120ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // temporary shim to support backwards compatibility between "modemcf" and "modem" #include #include #include #include "liquid.internal.h" modem modem_create(modulation_scheme _scheme) { return modemcf_create(_scheme); } modem modem_create_arbitrary(float complex * _table, unsigned int _M) { return modemcf_create_arbitrary(_table, _M); } modem modem_recreate(modem _q, modulation_scheme _scheme) { return modemcf_recreate(_q, _scheme); } int modem_destroy(modem _q) { return modemcf_destroy(_q); } int modem_print(modem _q) { return modemcf_print(_q); } int modem_reset(modem _q) { return modemcf_reset(_q); } unsigned int modem_gen_rand_sym(modem _q) { return modemcf_gen_rand_sym(_q); } unsigned int modem_get_bps(modem _q) { return modemcf_get_bps(_q); } modulation_scheme modem_get_scheme(modem _q) { return modemcf_get_scheme(_q); } int modem_modulate(modem _q, unsigned int _s, float complex * _y) { return modemcf_modulate(_q, _s, _y); } int modem_demodulate(modem _q, float complex _x, unsigned int * _s) { return modemcf_demodulate(_q, _x, _s); } int modem_demodulate_soft(modem _q, float complex _x, unsigned int * _s, unsigned char * _soft_bits) { return modemcf_demodulate_soft(_q, _x, _s, _soft_bits); } int modem_get_demodulator_sample(modem _q, float complex * _x_hat) { return modemcf_get_demodulator_sample(_q, _x_hat); } float modem_get_demodulator_phase_error(modem _q) { return modemcf_get_demodulator_phase_error(_q); } float modem_get_demodulator_evm(modem _q) { return modemcf_get_demodulator_evm(_q); } liquid-dsp-1.7.0/src/modem/src/modem_apsk.proto.c000066400000000000000000000141761474751757600217360ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_apsk.c // // create an apsk (amplitude/phase-shift keying) modem object MODEM() MODEM(_create_apsk)(unsigned int _bits_per_symbol) { // pointer to APSK definition container struct liquid_apsk_s * apskdef = NULL; switch (_bits_per_symbol) { case 2: apskdef = &liquid_apsk4; break; case 3: apskdef = &liquid_apsk8; break; case 4: apskdef = &liquid_apsk16; break; case 5: apskdef = &liquid_apsk32; break; case 6: apskdef = &liquid_apsk64; break; case 7: apskdef = &liquid_apsk128; break; case 8: apskdef = &liquid_apsk256; break; default: return liquid_error_config("modem%s_create_apsk(), unsupported modulation level (%u)", EXTENSION, _bits_per_symbol); } MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = apskdef->scheme; MODEM(_init)(q, _bits_per_symbol); // set APSK internals unsigned int i; q->data.apsk.num_levels = apskdef->num_levels; for (i=0; idata.apsk.num_levels; i++) { q->data.apsk.p[i] = apskdef->p[i]; q->data.apsk.r[i] = apskdef->r[i]; q->data.apsk.phi[i] = apskdef->phi[i]; } // radius slicer for (i=0; idata.apsk.num_levels-1; i++) q->data.apsk.r_slicer[i] = apskdef->r_slicer[i]; // copy symbol map q->data.apsk.map = (unsigned char *) malloc(q->M*sizeof(unsigned char)); memmove(q->data.apsk.map, apskdef->map, q->M*sizeof(unsigned char)); // set modulation/demodulation function pointers q->modulate_func = &MODEM(_modulate_apsk); q->demodulate_func = &MODEM(_demodulate_apsk); // initialize soft-demodulation look-up table switch (q->m) { case 2: MODEM(_demodsoft_gentab)(q, 3); break; case 3: MODEM(_demodsoft_gentab)(q, 3); break; case 4: MODEM(_demodsoft_gentab)(q, 4); break; case 5: MODEM(_demodsoft_gentab)(q, 4); break; case 6: MODEM(_demodsoft_gentab)(q, 4); break; case 7: MODEM(_demodsoft_gentab)(q, 5); break; case 8: MODEM(_demodsoft_gentab)(q, 5); break; default:; } // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; // reset modem and return MODEM(_reset)(q); return q; } // modulate APSK int MODEM(_modulate_apsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { if (_sym_in >= _q->M) return liquid_error(LIQUID_EIRANGE,"modem%s_modulate_apsk(), input symbol exceeds maximum", EXTENSION); // map input symbol to constellation symbol unsigned int i; unsigned int s = _q->data.apsk.map[_sym_in]; // determine in which level the symbol is located unsigned int p=0; // level unsigned int t=0; // accumulated number of points per level for (i=0; i<_q->data.apsk.num_levels; i++) { if (s < t + _q->data.apsk.p[i]) { p = i; break; } t += _q->data.apsk.p[i]; } unsigned int s0 = s - t; unsigned int s1 = _q->data.apsk.p[p]; #if 0 printf(" s : %3u -> %3u in level %3u (t = %3u) [symbol %3u / %3u]\n", _sym_in, s, p, t, s0,s1); #endif // map symbol to constellation point (radius, angle) T r = _q->data.apsk.r[p]; T phi = _q->data.apsk.phi[p] + (T)(s0)*2.0f*M_PI / (T)(s1); // compute output symbol *_y = r * liquid_cexpjf(phi); return LIQUID_OK; } // demodulate APSK int MODEM(_demodulate_apsk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // compute amplitude T r = cabsf(_x); // determine which ring to demodulate with unsigned int i, p=0; for (i=0; i<_q->data.apsk.num_levels-1; i++) { if (r < _q->data.apsk.r_slicer[i]) { p = i; break; } else { p = _q->data.apsk.num_levels-1; } } // find closest point in ring T theta = cargf(_x); if (theta < 0.0f) theta += 2.0f*M_PI; T dphi = 2.0f*M_PI / (T) _q->data.apsk.p[p]; unsigned int s_hat=0; T i_hat = (theta - _q->data.apsk.phi[p]) / dphi; s_hat = roundf(i_hat); // compute symbol (closest angle) s_hat %= _q->data.apsk.p[p]; // ensure symbol is in range //printf(" i_hat : %12.8f (%3u)\n", i_hat, s_hat); // accumulate symbol points for (i=0; idata.apsk.p[i]; //assert(s_hat < _q->M); // reverse symbol mapping unsigned int s_prime=0; for (i=0; i<_q->M; i++) { if ( _q->data.apsk.map[i] == s_hat) { s_prime = i; break; } } #if 0 printf(" x : %12.8f + j*%12.8f\n", crealf(_x), cimagf(_x)); printf(" p : %3u\n", p); printf(" theta : %12.8f\n", theta); printf(" dmin : %12.8f\n", dmin); printf(" s : %3u > %3u\n", s_hat, s_prime); #endif *_sym_out = s_prime; // re-modulate symbol and store state MODEM(_modulate)(_q, s_prime, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_apsk_const.c000066400000000000000000000163721474751757600220020ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_apsk_const.c // // APSK modem constants // #include #include "liquid.internal.h" // APSK4(1,3) unsigned int apsk4_num_levels = 2; unsigned int apsk4_p[2] = {1,3}; float apsk4_r[2] = {0.0f, 1.15470052}; float apsk4_phi[2] = {0.0f, 0.0f}; float apsk4_r_slicer[1] = {0.57735026}; unsigned char apsk4_map[4] = {3,2,1,0}; struct liquid_apsk_s liquid_apsk4 = { LIQUID_MODEM_APSK4, 2, apsk4_p, apsk4_r, apsk4_phi, apsk4_r_slicer, apsk4_map}; // APSK8(1,7) unsigned int apsk8_num_levels = 2; unsigned int apsk8_p[2] = {1,7}; float apsk8_r[2] = {0.0, 1.06904495}; float apsk8_phi[2] = {0.0, 0.0}; float apsk8_r_slicer[1] = {0.53452247}; unsigned char apsk8_map[8] = { 0, 2, 4, 3, 1, 7, 5, 6}; struct liquid_apsk_s liquid_apsk8 = { LIQUID_MODEM_APSK8, 2, apsk8_p, apsk8_r, apsk8_phi, apsk8_r_slicer, apsk8_map}; // APSK16(4,12) unsigned int apsk16_num_levels = 2; unsigned int apsk16_p[2] = {4,12}; float apsk16_r[2] = {0.43246540f, 1.12738252f}; float apsk16_phi[2] = {0.0f, 0.0f}; float apsk16_r_slicer[1] = {0.77992396f}; unsigned char apsk16_map[16] = { 11, 10, 8, 9, 12, 2, 7, 1, 14, 15, 5, 4, 13, 3, 6, 0}; struct liquid_apsk_s liquid_apsk16 = { LIQUID_MODEM_APSK16, 2, apsk16_p, apsk16_r, apsk16_phi, apsk16_r_slicer, apsk16_map}; // APSK32(4,12,16) unsigned int apsk32_num_levels = 3; unsigned int apsk32_p[3] = {4,12,16}; float apsk32_r[3] = { 0.27952856f, 0.72980529f, 1.25737989f}; float apsk32_phi[3] = { 0.0f, 0.0f, 0.0f}; float apsk32_r_slicer[2] = { 0.504666925, 0.993592590}; unsigned char apsk32_map[32] = { 26, 25, 22, 23, 27, 11, 21, 9, 13, 3, 7, 1, 12, 10, 8, 24, 30, 31, 18, 17, 29, 15, 19, 5, 28, 0, 20, 2, 14, 16, 6, 4}; struct liquid_apsk_s liquid_apsk32 = { LIQUID_MODEM_APSK32, 3, apsk32_p, apsk32_r, apsk32_phi, apsk32_r_slicer, apsk32_map}; // APSK64(4,14,20,26) unsigned int apsk64_num_levels = 4; unsigned int apsk64_p[4] = {4, 14, 20, 26}; float apsk64_r[4] = { 0.18916586, 0.52466476, 0.88613129, 1.30529201}; float apsk64_phi[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float apsk64_r_slicer[3] = { 0.35691531, 0.70539802, 1.09571165}; unsigned char apsk64_map[64] = { 54, 53, 51, 52, 48, 49, 28, 50, 55, 30, 11, 29, 47, 25, 27, 26, 57, 32, 2, 14, 45, 23, 1, 8, 56, 31, 12, 13, 46, 24, 10, 9, 61, 62, 38, 63, 41, 40, 18, 39, 60, 35, 37, 36, 42, 20, 4, 19, 58, 33, 3, 15, 44, 22, 0, 7, 59, 34, 17, 16, 43, 21, 5, 6}; struct liquid_apsk_s liquid_apsk64 = { LIQUID_MODEM_APSK64, 4, apsk64_p, apsk64_r, apsk64_phi, apsk64_r_slicer, apsk64_map}; // APSK128(8,18,24,36,42) unsigned int apsk128_num_levels = 5; unsigned int apsk128_p[5] = {8,18,24,36,42}; float apsk128_r[5] = { 0.20241030, 0.46255755, 0.70972824, 0.99172282, 1.34806108}; float apsk128_phi[5] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; float apsk128_r_slicer[4] = { 0.33248392, 0.58614290, 0.85072553, 1.16989195}; unsigned char apsk128_map[128] = { 112, 111, 108, 109, 102, 103, 106, 105, 113, 110, 107, 71, 101, 104, 67, 66, 115, 73, 39, 41, 99, 63, 38, 36, 114, 72, 69, 70, 100, 64, 68, 65, 117, 77, 1, 21, 97, 59, 2, 13, 76, 43, 4, 20, 60, 33, 3, 14, 116, 74, 18, 40, 98, 62, 37, 35, 75, 42, 17, 19, 61, 34, 16, 15, 123, 124, 127, 126, 91, 90, 87, 88, 122, 125, 85, 84, 92, 89, 51, 53, 120, 81, 49, 48, 94, 55, 26, 29, 121, 82, 50, 83, 93, 54, 27, 52, 118, 44, 7, 5, 96, 32, 0, 10, 78, 45, 6, 22, 58, 30, 86, 12, 80, 79, 25, 47, 57, 56, 9, 28, 119, 46, 24, 23, 95, 31, 8, 11}; struct liquid_apsk_s liquid_apsk128 = { LIQUID_MODEM_APSK128, 5, apsk128_p, apsk128_r, apsk128_phi, apsk128_r_slicer, apsk128_map}; // APSK256(6,18,32,36,46,54,64) unsigned int apsk256_num_levels = 7; unsigned int apsk256_p[7] = {6,18,32,36,46,54,64}; float apsk256_r[7] = { 0.19219166, 0.41951191, 0.60772800, 0.77572918, 0.94819963, 1.12150347, 1.31012368}; float apsk256_phi[7] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; float apsk256_r_slicer[6] = { 0.30585179, 0.51361996, 0.69172859, 0.86196440, 1.03485155, 1.21581364}; unsigned char apsk256_map[256] = { 232, 231, 229, 230, 224, 225, 227, 226, 216, 217, 219, 218, 164, 223, 221, 222, 233, 228, 170, 171, 166, 167, 169, 168, 215, 220, 160, 159, 165, 163, 161, 162, 235, 173, 123, 121, 75, 76, 78, 77, 213, 157, 70, 109, 73, 115, 71, 72, 234, 172, 120, 174, 116, 117, 119, 118, 214, 158, 110, 156, 114, 113, 111, 112, 239, 178, 82, 126, 255, 19, 47, 5, 209, 152, 66, 105, 56, 12, 33, 13, 238, 177, 81, 125, 138, 193, 46, 4, 210, 153, 67, 106, 7, 1, 34, 2, 236, 175, 79, 122, 74, 42, 44, 43, 212, 155, 69, 108, 39, 38, 36, 37, 237, 176, 80, 124, 3, 40, 45, 41, 211, 154, 68, 107, 16, 15, 35, 14, 248, 249, 251, 250, 191, 190, 252, 253, 200, 199, 197, 198, 139, 140, 196, 195, 247, 185, 187, 186, 137, 136, 188, 189, 201, 145, 143, 144, 93, 94, 142, 141, 245, 183, 87, 131, 54, 53, 88, 89, 203, 147, 61, 99, 26, 27, 60, 59, 246, 184, 133, 132, 91, 90, 134, 135, 202, 146, 97, 98, 57, 58, 96, 95, 240, 179, 83, 127, 23, 192, 48, 17, 208, 151, 65, 104, 6, 11, 32, 206, 241, 180, 84, 128, 254, 242, 49, 18, 207, 150, 64, 102, 92, 194, 31, 10, 244, 182, 86, 130, 55, 21, 52, 51, 204, 148, 62, 100, 25, 8, 28, 29, 243, 181, 85, 129, 0, 22, 50, 20, 205, 149, 63, 101, 24, 9, 30, 103}; struct liquid_apsk_s liquid_apsk256 = { LIQUID_MODEM_APSK256, 7, apsk256_p, apsk256_r, apsk256_phi, apsk256_r_slicer, apsk256_map}; liquid-dsp-1.7.0/src/modem/src/modem_arb.proto.c000066400000000000000000000226121474751757600215360ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_arb.c // // create arbitrary digital modem object MODEM() MODEM(_create_arbitrary)(float complex * _table, unsigned int _M) { // strip out bits/symbol unsigned int m = liquid_nextpow2(_M); if ( (1<M); unsigned int i; for (i=0; iM; i++) printf(" %3u: %12.8f %12.8f\n", i, crealf(q->symbol_map[i]), cimagf(q->symbol_map[i])); // return object return q; } // create an arbitrary modem object MODEM() MODEM(_create_arb)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_ARB; MODEM(_init)(q, _bits_per_symbol); q->M = q->M; q->symbol_map = (TC*) calloc( q->M, sizeof(TC) ); q->modulate_func = &MODEM(_modulate_arb); q->demodulate_func = &MODEM(_demodulate_arb); return q; } // modulate arbitrary modem type int MODEM(_modulate_arb)(MODEM() _q, unsigned int _sym_in, TC * _y) { if (_sym_in >= _q->M) return liquid_error(LIQUID_EIRANGE,"modulate_arb(), input symbol exceeds maximum"); // map sample directly to output *_y = _q->symbol_map[_sym_in]; return LIQUID_OK; } // demodulate arbitrary modem type int MODEM(_demodulate_arb)(MODEM() _q, TC _x, unsigned int * _sym_out) { // search for symbol nearest to received sample unsigned int i; unsigned int s=0; T d; // distance T d_min = 0.0f; // minimum distance for (i=0; i<_q->M; i++) { // compute distance from received symbol to constellation point d = cabsf(_x - _q->symbol_map[i]); // retain symbol with minimum distance if ( i==0 || d < d_min ) { d_min = d; s = i; } } // set output symbol *_sym_out = s; // re-modulate symbol and store state MODEM(_modulate_arb)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } // create a V.29 modem object (4 bits/symbol) MODEM() MODEM(_create_V29)() { MODEM() q = MODEM(_create_arb)(4); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb_V29,16); #endif return q; } // create an arb16opt (optimal 16-qam) modem object MODEM() MODEM(_create_arb16opt)() { MODEM() q = MODEM(_create_arb)(4); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb16opt,16); #endif return q; } // create an arb32opt (optimal 32-qam) modem object MODEM() MODEM(_create_arb32opt)() { MODEM() q = MODEM(_create_arb)(5); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb32opt,32); #endif return q; } // create an arb64opt (optimal 64-qam) modem object MODEM() MODEM(_create_arb64opt)() { MODEM() q = MODEM(_create_arb)(6); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb64opt,64); #endif return q; } // create an arb128opt (optimal 128-qam) modem object MODEM() MODEM(_create_arb128opt)() { MODEM() q = MODEM(_create_arb)(7); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb128opt,128); #endif return q; } // create an arb256opt (optimal 256-qam) modem object MODEM() MODEM(_create_arb256opt)() { MODEM() q = MODEM(_create_arb)(8); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb256opt,256); #endif return q; } // create an arb64vt (64-qam vt logo) modem object MODEM() MODEM(_create_arb64vt)() { MODEM() q = MODEM(_create_arb)(6); #if T == float MODEM(_arb_init)(q,(TC*)modem_arb_vt64,64); #endif return q; } // initialize an arbitrary modem object // _mod : modem object // _symbol_map : arbitrary modem symbol map // _len : number of symbols in the map int MODEM(_arb_init)(MODEM() _q, float complex * _symbol_map, unsigned int _len) { #ifdef LIQUID_VALIDATE_INPUT if (_q->scheme != LIQUID_MODEM_ARB) return liquid_error(LIQUID_EICONFIG,"modem%s_arb_init(), modem is not of arbitrary type", EXTENSION); if (_len != _q->M) return liquid_error(LIQUID_EICONFIG,"modem%s_arb_init(), array sizes do not match", EXTENSION); #endif unsigned int i; for (i=0; i<_len; i++) _q->symbol_map[i] = _symbol_map[i]; // balance I/Q channels if (_q->scheme == LIQUID_MODEM_ARB) MODEM(_arb_balance_iq)(_q); // scale modem to have unity energy return MODEM(_arb_scale)(_q); } // initialize an arbitrary modem object on a file // _mod : modem object // _filename : name of the data file int MODEM(_arb_init_file)(MODEM() _q, char * _filename) { // try to open file FILE * fid = fopen(_filename, "r"); if (fid == NULL) return liquid_error(LIQUID_EIO,"modem%s_arb_init_file(), could not open file", EXTENSION); unsigned int i, results; T sym_i, sym_q; for (i=0; i<_q->M; i++) { if ( feof(fid) ) return liquid_error(LIQUID_EIO,"modem%s_arb_init_file(), premature EOF for '%s'", EXTENSION,_filename); results = fscanf(fid, "%f %f\n", &sym_i, &sym_q); _q->symbol_map[i] = sym_i + _Complex_I*sym_q; // ensure proper number of symbols were read if (results < 2) return liquid_error(LIQUID_EIO,"modem%s_arb_init_file(), unable to parse line", EXTENSION); } fclose(fid); // balance I/Q channels if (_q->scheme == LIQUID_MODEM_ARB) MODEM(_arb_balance_iq)(_q); // scale modem to have unity energy return MODEM(_arb_scale)(_q); } // scale arbitrary modem constellation points int MODEM(_arb_scale)(MODEM() _q) { unsigned int i; // calculate energy T mag, e = 0.0f; for (i=0; i<_q->M; i++) { mag = cabsf(_q->symbol_map[i]); e += mag*mag; } e = sqrtf( e / _q->M ); for (i=0; i<_q->M; i++) { _q->symbol_map[i] /= e; } return LIQUID_OK; } // balance an arbitrary modem's I/Q points int MODEM(_arb_balance_iq)(MODEM() _q) { TC mean=0.0f; unsigned int i; // accumulate average signal for (i=0; i<_q->M; i++) { mean += _q->symbol_map[i]; } mean /= (T) (_q->M); // subtract mean value from reference levels for (i=0; i<_q->M; i++) { _q->symbol_map[i] -= mean; } return LIQUID_OK; } // demodulate arbitrary modem type (soft) int MODEM(_demodulate_soft_arb)(MODEM() _q, TC _r, unsigned int * _s, unsigned char * _soft_bits) { unsigned int bps = _q->m; unsigned int M = _q->M; // gamma = 1/(2*sigma^2), approximate for constellation size T gamma = 1.2f*_q->M; unsigned int s=0; // hard decision output unsigned int k; // bit index unsigned int i; // symbol index T d; // distance for this symbol TC x_hat; // re-modulated symbol T dmin_0[bps]; T dmin_1[bps]; for (k=0; ksymbol_map[i]; d = crealf( (_r-x_hat)*conjf(_r-x_hat) ); // set hard-decision... if (d < dmin || i==0) { s = i; dmin = d; } for (k=0; k> (bps-k-1)) & 0x01 ) { if (d < dmin_1[k]) dmin_1[k] = d; } else { if (d < dmin_0[k]) dmin_0[k] = d; } } } // make assignments for (k=0; k 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; _soft_bits[k] = (unsigned char)soft_bit; } // hard decision // set hard output symbol *_s = s; // re-modulate symbol and store state MODEM(_modulate_arb)(_q, *_s, &_q->x_hat); _q->r = _r; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_arb_const.c000066400000000000000000000673101474751757600216060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_arb_const.c // // Constant arbitrary linear modems // #include #include "liquid.internal.h" // 'square' 32-QAM (first quadrant) const float complex modem_arb_sqam32[8] = { 0.22361000+ 0.22361000*_Complex_I, 0.67082000+ 0.22361000*_Complex_I, 0.67082000+ 1.11800000*_Complex_I, 1.11800000+ 0.22361000*_Complex_I, 0.22361000+ 0.67082000*_Complex_I, 0.67082000+ 0.67082000*_Complex_I, 0.22361000+ 1.11800000*_Complex_I, 1.11800000+ 0.67082000*_Complex_I }; // 'square' 128-QAM (first quadrant) const float complex modem_arb_sqam128[32] = { 0.11043000+ 0.11043000*_Complex_I, 0.33129000+ 0.11043000*_Complex_I, 0.11043000+ 0.33129000*_Complex_I, 0.33129000+ 0.33129000*_Complex_I, 0.77302000+ 0.11043000*_Complex_I, 0.55216000+ 0.11043000*_Complex_I, 0.77302000+ 0.33129000*_Complex_I, 0.55216000+ 0.33129000*_Complex_I, 0.77302000+ 0.99388000*_Complex_I, 0.55216000+ 0.99388000*_Complex_I, 0.77302000+ 1.21470000*_Complex_I, 0.55216000+ 1.21470000*_Complex_I, 0.99388000+ 0.11043000*_Complex_I, 1.21470000+ 0.11043000*_Complex_I, 0.99388000+ 0.33129000*_Complex_I, 1.21470000+ 0.33129000*_Complex_I, 0.11043000+ 0.77302000*_Complex_I, 0.33129000+ 0.77302000*_Complex_I, 0.11043000+ 0.55216000*_Complex_I, 0.33129000+ 0.55216000*_Complex_I, 0.77302000+ 0.77302000*_Complex_I, 0.55216000+ 0.77302000*_Complex_I, 0.77302000+ 0.55216000*_Complex_I, 0.55216000+ 0.55216000*_Complex_I, 0.11043000+ 0.99388000*_Complex_I, 0.33129000+ 0.99388000*_Complex_I, 0.11043000+ 1.21470000*_Complex_I, 0.33129000+ 1.21470000*_Complex_I, 0.99388000+ 0.77302000*_Complex_I, 1.21470000+ 0.77302000*_Complex_I, 0.99388000+ 0.55216000*_Complex_I, 1.21470000+ 0.55216000*_Complex_I }; // V.29 star constellation const float complex modem_arb_V29[16] = { 0.06804100+ 0.06804100*_Complex_I, 0.20412000+ 0.00000000*_Complex_I, 0.00000000+ 0.20412000*_Complex_I, -0.06804100+ 0.06804100*_Complex_I, 0.00000000+ -0.20412000*_Complex_I, 0.06804100+ -0.06804100*_Complex_I, -0.06804100+ -0.06804100*_Complex_I, -0.20412000+ 0.00000000*_Complex_I, 0.20412000+ 0.20412000*_Complex_I, 0.34021000+ 0.00000000*_Complex_I, 0.00000000+ 0.34021000*_Complex_I, -0.20412000+ 0.20412000*_Complex_I, 0.00000000+ -0.34021000*_Complex_I, 0.20412000+ -0.20412000*_Complex_I, -0.20412000+ -0.20412000*_Complex_I, -0.34021000+ 0.00000000*_Complex_I }; // Virginia Tech logo const float complex modem_arb_vt64[64] = { -1.5633e+00+ 5.5460e-01*_Complex_I, -1.3833e+00+ 5.5460e-01*_Complex_I, -1.0234e+00+ 5.5460e-01*_Complex_I, -1.2034e+00+ 5.5460e-01*_Complex_I, -7.3553e-01+ 5.0751e-02*_Complex_I, -8.0750e-01+ 1.7671e-01*_Complex_I, -9.5146e-01+ 4.2863e-01*_Complex_I, -8.7948e-01+ 3.0267e-01*_Complex_I, -3.3741e-02+ 5.5460e-01*_Complex_I, -2.1368e-01+ 5.5460e-01*_Complex_I, -4.4761e-01+ 4.2863e-01*_Complex_I, -3.9363e-01+ 5.5460e-01*_Complex_I, -6.6355e-01+ -7.5211e-02*_Complex_I, -6.0956e-01+ 5.0751e-02*_Complex_I, -5.0160e-01+ 3.0267e-01*_Complex_I, -5.5558e-01+ 1.7671e-01*_Complex_I, 9.5596e-01+ 1.0473e-01*_Complex_I, 1.1359e+00+ 1.0473e-01*_Complex_I, 1.4958e+00+ 1.0473e-01*_Complex_I, 1.3158e+00+ 1.0473e-01*_Complex_I, 1.5858e+00+ 5.5460e-01*_Complex_I, 1.7657e+00+ 5.5460e-01*_Complex_I, 1.5858e+00+ 2.5499e-01*_Complex_I, 1.6757e+00+ 4.0434e-01*_Complex_I, 1.4621e-01+ 5.5460e-01*_Complex_I, 3.2615e-01+ 5.5460e-01*_Complex_I, 6.8604e-01+ 5.5460e-01*_Complex_I, 5.0610e-01+ 5.5460e-01*_Complex_I, 1.4058e+00+ 5.5460e-01*_Complex_I, 1.2259e+00+ 5.5460e-01*_Complex_I, 8.6599e-01+ 5.5460e-01*_Complex_I, 1.0459e+00+ 5.5460e-01*_Complex_I, -1.4508e+00+ 3.6385e-01*_Complex_I, -1.3383e+00+ 1.7221e-01*_Complex_I, -1.1134e+00+ -2.1017e-01*_Complex_I, -1.2259e+00+ -1.8529e-02*_Complex_I, -6.6355e-01+ -9.7494e-01*_Complex_I, -7.7601e-01+ -7.8420e-01*_Complex_I, -1.0009e+00+ -4.0181e-01*_Complex_I, -8.8848e-01+ -5.9255e-01*_Complex_I, 1.4621e-01+ 1.0473e-01*_Complex_I, 1.1246e-02+ 1.0473e-01*_Complex_I, -2.1368e-01+ -7.5211e-02*_Complex_I, -1.2371e-01+ 1.0473e-01*_Complex_I, -5.7358e-01+ -7.9499e-01*_Complex_I, -4.8360e-01+ -6.1505e-01*_Complex_I, -3.0366e-01+ -2.5516e-01*_Complex_I, -3.9363e-01+ -4.3510e-01*_Complex_I, 8.5069e-01+ -7.5211e-02*_Complex_I, 7.4632e-01+ -2.5516e-01*_Complex_I, 5.3579e-01+ -6.1505e-01*_Complex_I, 6.4105e-01+ -4.3510e-01*_Complex_I, -3.3741e-02+ -9.7494e-01*_Complex_I, 1.4621e-01+ -9.7494e-01*_Complex_I, 4.3142e-01+ -7.9499e-01*_Complex_I, 3.2615e-01+ -9.7494e-01*_Complex_I, 2.8116e-01+ 1.0473e-01*_Complex_I, 4.1612e-01+ 1.0473e-01*_Complex_I, 2.0649e-01+ -2.5516e-01*_Complex_I, 3.1086e-01+ -7.5211e-02*_Complex_I, -2.1368e-01+ -9.7494e-01*_Complex_I, -1.0842e-01+ -7.9499e-01*_Complex_I, 1.0122e-01+ -4.3510e-01*_Complex_I, -4.0500e-03+ -6.1505e-01*_Complex_I }; // optimal 16-QAM const float complex modem_arb16opt[16] = { -0.87119000+ -0.87970000*_Complex_I, -1.15090000+ -0.26101000*_Complex_I, -1.10090000+ 0.87457000*_Complex_I, -0.81088000+ 0.29689000*_Complex_I, -0.21295000+ -0.91897000*_Complex_I, -0.46984000+ -0.29804000*_Complex_I, -0.43443000+ 0.91820000*_Complex_I, -0.16786000+ 0.30338000*_Complex_I, 1.10000000+ -0.87511000*_Complex_I, 0.81125000+ -0.29671000*_Complex_I, 0.87134000+ 0.87989000*_Complex_I, 1.15170000+ 0.26143000*_Complex_I, 0.43379000+ -0.91801000*_Complex_I, 0.16807000+ -0.30335000*_Complex_I, 0.21246000+ 0.91867000*_Complex_I, 0.47033000+ 0.29787000*_Complex_I }; // optimal 32-QAM const float complex modem_arb32opt[32] = { -1.04570000+ -0.72639000*_Complex_I, -1.26710000+ -0.00824020*_Complex_I, -0.99868000+ 0.92359000*_Complex_I, -1.13660000+ 0.45833000*_Complex_I, -0.67812000+ -1.07470000*_Complex_I, -0.88363000+ -0.25914000*_Complex_I, -0.64443000+ 0.62407000*_Complex_I, -0.76238000+ 0.18163000*_Complex_I, -0.20985000+ -0.91032000*_Complex_I, -0.08603100+ -0.45730000*_Complex_I, -0.18073000+ 0.75747000*_Complex_I, 0.02826900+ -0.01908400*_Complex_I, -0.55206000+ -0.61092000*_Complex_I, -0.42946000+ -0.16611000*_Complex_I, -0.51187000+ 1.09190000*_Complex_I, -0.30769000+ 0.27731000*_Complex_I, 1.20280000+ -0.58421000*_Complex_I, 1.29120000+ -0.09249800*_Complex_I, 1.10450000+ 0.69170000*_Complex_I, 0.96433000+ 0.24011000*_Complex_I, 0.60130000+ -1.16500000*_Complex_I, 0.83106000+ -0.23576000*_Complex_I, 0.73090000+ 1.01880000*_Complex_I, 0.62090000+ 0.54470000*_Complex_I, 0.23884000+ -0.81583000*_Complex_I, 0.36064000+ -0.36749000*_Complex_I, -0.02439300+ 1.23570000*_Complex_I, 0.15492000+ 0.41465000*_Complex_I, 0.11172000+ -1.28340000*_Complex_I, 0.70560000+ -0.68005000*_Complex_I, 0.28323000+ 0.89268000*_Complex_I, 0.48844000+ 0.10367000*_Complex_I }; // optimal 64-QAM const float complex modem_arb64opt[64] = { -9.6048e-01 + -1.0031e+00*_Complex_I, -1.1105e+00 + -6.8896e-01*_Complex_I, -1.1029e+00 + -9.5064e-02*_Complex_I, -1.2692e+00 + -3.8774e-01*_Complex_I, -7.9322e-01 + 1.1014e+00*_Complex_I, -9.5999e-01 + 7.9701e-01*_Complex_I, -1.2734e+00 + 1.9621e-01*_Complex_I, -1.1121e+00 + 4.9520e-01*_Complex_I, -6.2388e-01 + -9.8614e-01*_Complex_I, -7.7108e-01 + -6.8653e-01*_Complex_I, -7.6793e-01 + -1.0097e-01*_Complex_I, -9.1812e-01 + -3.9210e-01*_Complex_I, -4.5416e-01 + 1.0712e+00*_Complex_I, -6.1578e-01 + 7.7701e-01*_Complex_I, -9.1845e-01 + 1.9699e-01*_Complex_I, -7.7026e-01 + 4.8601e-01*_Complex_I, -1.1067e-01 + -1.2612e+00*_Complex_I, -2.6544e-01 + -9.6343e-01*_Complex_I, 1.3076e+00 + 4.5615e-01*_Complex_I, -2.5827e-01 + -3.9458e-01*_Complex_I, -1.0044e-01 + 1.0486e+00*_Complex_I, 3.9086e-02 + 7.4394e-01*_Complex_I, -2.6144e-01 + 1.7968e-01*_Complex_I, -1.1912e-01 + 4.5495e-01*_Complex_I, -4.5452e-01 + -1.2733e+00*_Complex_I, -4.3866e-01 + -6.8570e-01*_Complex_I, -4.3802e-01 + -1.0872e-01*_Complex_I, -5.8466e-01 + -3.9550e-01*_Complex_I, -2.6246e-01 + 1.3479e+00*_Complex_I, -2.8816e-01 + 7.5672e-01*_Complex_I, -5.8784e-01 + 1.8705e-01*_Complex_I, -4.4008e-01 + 4.7244e-01*_Complex_I, 7.9849e-01 + -1.0124e+00*_Complex_I, 9.5371e-01 + -7.1194e-01*_Complex_I, 1.2696e+00 + -1.1448e-01*_Complex_I, 1.1145e+00 + -4.2441e-01*_Complex_I, 9.0580e-01 + 1.0653e+00*_Complex_I, 1.0641e+00 + 7.6363e-01*_Complex_I, 1.0837e+00 + 1.7467e-01*_Complex_I, 9.1489e-01 + 4.6389e-01*_Complex_I, 5.8983e-01 + -1.2906e+00*_Complex_I, 6.0746e-01 + -7.0336e-01*_Complex_I, 9.1373e-01 + -1.3004e-01*_Complex_I, 7.4917e-01 + -4.1576e-01*_Complex_I, 5.6608e-01 + 1.0707e+00*_Complex_I, 7.1464e-01 + 7.5794e-01*_Complex_I, 7.4460e-01 + 1.6652e-01*_Complex_I, 5.7594e-01 + 4.5036e-01*_Complex_I, 7.6128e-02 + -9.7664e-01*_Complex_I, -9.2551e-02 + -6.8763e-01*_Complex_I, -9.4285e-02 + -1.0993e-01*_Complex_I, 6.5368e-02 + -4.0109e-01*_Complex_I, 1.0945e-01 + 1.3350e+00*_Complex_I, 2.2470e-01 + 4.7166e-01*_Complex_I, 5.5987e-01 + -1.1259e-01*_Complex_I, 7.0006e-02 + 1.9154e-01*_Complex_I, 2.4876e-01 + -1.2685e+00*_Complex_I, 4.2452e-01 + -9.8023e-01*_Complex_I, 2.5356e-01 + -6.8613e-01*_Complex_I, 4.0576e-01 + -4.1184e-01*_Complex_I, 2.4615e-01 + 1.0373e+00*_Complex_I, 3.9219e-01 + 7.4440e-01*_Complex_I, 2.4704e-01 + -1.0509e-01*_Complex_I, 3.9791e-01 + 1.8370e-01*_Complex_I, }; // optimal 128-QAM const float complex modem_arb128opt[128] = { -1.0682e+00 + -9.2598e-01*_Complex_I, -1.1831e+00 + -7.0704e-01*_Complex_I, -1.3029e+00 + -1.0555e-01*_Complex_I, -1.3061e+00 + -4.9292e-01*_Complex_I, -9.4032e-01 + 9.7928e-01*_Complex_I, -1.1807e+00 + 5.4821e-01*_Complex_I, -1.4078e+00 + 1.1265e-01*_Complex_I, -1.2954e+00 + 3.3623e-01*_Complex_I, -7.3838e-01 + -1.1381e+00*_Complex_I, -9.4161e-01 + -7.0518e-01*_Complex_I, -1.1625e+00 + -2.9080e-01*_Complex_I, -1.0477e+00 + -4.9556e-01*_Complex_I, -1.0664e+00 + 7.7185e-01*_Complex_I, -8.3123e-01 + 7.4171e-01*_Complex_I, -1.1636e+00 + 1.1831e-01*_Complex_I, -1.0506e+00 + 3.2582e-01*_Complex_I, -4.8913e-01 + -1.1074e+00*_Complex_I, -5.8148e-01 + -8.9486e-01*_Complex_I, -8.0747e-01 + -9.4398e-02*_Complex_I, -9.1178e-01 + -2.9590e-01*_Complex_I, -7.0503e-01 + 9.5290e-01*_Complex_I, -5.8794e-01 + 7.4046e-01*_Complex_I, -6.9655e-01 + 1.0350e-01*_Complex_I, -6.8968e-01 + 5.2969e-01*_Complex_I, -8.2001e-01 + -9.1531e-01*_Complex_I, -7.0810e-01 + -7.0021e-01*_Complex_I, -1.0403e+00 + -8.9321e-02*_Complex_I, -8.0893e-01 + -4.9762e-01*_Complex_I, -6.1299e-01 + 1.1733e+00*_Complex_I, -9.2994e-01 + 5.3436e-01*_Complex_I, -9.2384e-01 + 1.1851e-01*_Complex_I, -8.0873e-01 + 3.2535e-01*_Complex_I, 8.5789e-03 + -1.1069e+00*_Complex_I, 1.3354e-01 + -9.0426e-01*_Complex_I, 1.2277e+00 + -3.0336e-01*_Complex_I, -2.1578e-01 + -2.9289e-01*_Complex_I, 2.5555e-03 + 1.3535e+00*_Complex_I, -1.0737e-01 + 7.4055e-01*_Complex_I, 5.0972e-03 + 1.1376e-01*_Complex_I, -4.5018e-03 + 5.4428e-01*_Complex_I, -1.0895e-01 + -1.3162e+00*_Complex_I, -2.2365e-01 + -6.9809e-01*_Complex_I, 1.3461e+00 + -9.5212e-02*_Complex_I, -4.3183e-01 + -2.9421e-01*_Complex_I, -1.1598e-01 + 1.1402e+00*_Complex_I, -2.2730e-01 + 9.3180e-01*_Complex_I, -2.1915e-01 + 1.1528e-01*_Complex_I, -2.2953e-01 + 5.3517e-01*_Complex_I, -3.6962e-01 + -1.3195e+00*_Complex_I, -4.6545e-01 + -6.9766e-01*_Complex_I, -6.7387e-01 + -2.8466e-01*_Complex_I, -5.6923e-01 + -4.9130e-01*_Complex_I, -3.6828e-01 + 1.1445e+00*_Complex_I, -4.6503e-01 + 9.3615e-01*_Complex_I, -5.7039e-01 + -8.3381e-02*_Complex_I, -4.6304e-01 + 5.2568e-01*_Complex_I, -2.4438e-01 + -1.1062e+00*_Complex_I, -3.4724e-01 + -8.9072e-01*_Complex_I, -3.3719e-01 + -8.1507e-02*_Complex_I, -3.4116e-01 + -4.9075e-01*_Complex_I, -2.5467e-01 + 1.3510e+00*_Complex_I, -3.4640e-01 + 7.4004e-01*_Complex_I, -4.5303e-01 + 1.1207e-01*_Complex_I, -5.7498e-01 + 3.1560e-01*_Complex_I, 8.7471e-01 + -9.3403e-01*_Complex_I, 1.1932e+00 + -7.1750e-01*_Complex_I, 1.0817e+00 + -9.5165e-02*_Complex_I, 1.0850e+00 + -5.0487e-01*_Complex_I, 9.7521e-01 + 9.8123e-01*_Complex_I, 1.0879e+00 + 7.6120e-01*_Complex_I, 1.1902e+00 + 1.1187e-01*_Complex_I, 1.1983e+00 + 5.4100e-01*_Complex_I, 7.5089e-01 + -1.1405e+00*_Complex_I, 9.5031e-01 + -7.0315e-01*_Complex_I, 9.6679e-01 + -2.8997e-01*_Complex_I, 8.4619e-01 + -4.8958e-01*_Complex_I, 7.4379e-01 + 9.5772e-01*_Complex_I, 8.4793e-01 + 7.4658e-01*_Complex_I, 9.4820e-01 + 1.1332e-01*_Complex_I, 9.5910e-01 + 5.3750e-01*_Complex_I, 5.0524e-01 + -1.1045e+00*_Complex_I, 4.9092e-01 + -6.9263e-01*_Complex_I, 6.0143e-01 + -8.7696e-02*_Complex_I, 6.0078e-01 + -4.8901e-01*_Complex_I, 5.0450e-01 + 9.5208e-01*_Complex_I, 7.1207e-01 + 5.3740e-01*_Complex_I, 1.0790e+00 + 3.1868e-01*_Complex_I, 6.0339e-01 + 3.3768e-01*_Complex_I, 6.2518e-01 + -9.0613e-01*_Complex_I, 7.2199e-01 + -6.9979e-01*_Complex_I, 8.2756e-01 + -9.3837e-02*_Complex_I, 7.2238e-01 + -2.9345e-01*_Complex_I, 6.4006e-01 + 1.1740e+00*_Complex_I, 6.1312e-01 + 7.3911e-01*_Complex_I, 7.1908e-01 + 1.2320e-01*_Complex_I, 8.3253e-01 + 3.2769e-01*_Complex_I, -9.4871e-02 + -9.0259e-01*_Complex_I, -9.6676e-02 + -4.9277e-01*_Complex_I, 4.8818e-01 + -2.7584e-01*_Complex_I, -9.8973e-02 + -1.0402e-01*_Complex_I, 2.0955e-02 + 9.4046e-01*_Complex_I, 1.3132e-01 + 7.3484e-01*_Complex_I, 1.3357e+00 + 3.0715e-01*_Complex_I, -3.3806e-01 + 3.2795e-01*_Complex_I, 1.4149e-01 + -1.3293e+00*_Complex_I, 1.4162e-02 + -6.8874e-01*_Complex_I, 1.3376e-01 + -9.5389e-02*_Complex_I, 2.5367e-02 + -2.8878e-01*_Complex_I, 1.3413e-01 + 1.1437e+00*_Complex_I, 2.3299e-01 + 5.3149e-01*_Complex_I, 4.7428e-01 + 1.2730e-01*_Complex_I, 1.1767e-01 + 3.3670e-01*_Complex_I, 4.1070e-01 + -1.3283e+00*_Complex_I, 3.7197e-01 + -8.8947e-01*_Complex_I, 2.5771e-01 + -2.8158e-01*_Complex_I, 3.6892e-01 + -4.8660e-01*_Complex_I, 3.8837e-01 + 1.1516e+00*_Complex_I, 3.7013e-01 + 7.3189e-01*_Complex_I, 2.3982e-01 + 1.2673e-01*_Complex_I, 4.7588e-01 + 5.2723e-01*_Complex_I, 2.6342e-01 + -1.1217e+00*_Complex_I, 2.4743e-01 + -6.8820e-01*_Complex_I, 3.5855e-01 + -7.8191e-02*_Complex_I, 1.4393e-01 + -4.8365e-01*_Complex_I, 2.7111e-01 + 1.3506e+00*_Complex_I, 2.6368e-01 + 9.3477e-01*_Complex_I, 3.5476e-01 + 3.1767e-01*_Complex_I, -1.0269e-01 + 3.2880e-01*_Complex_I,}; // optimal 256-QAM const float complex modem_arb256opt[256] = { -9.3121e-01 + -1.0845e+00*_Complex_I, -1.0165e+00 + -9.3103e-01*_Complex_I, -1.1864e+00 + -6.3650e-01*_Complex_I, -1.1012e+00 + -7.8304e-01*_Complex_I, -1.3617e+00 + -4.3833e-02*_Complex_I, -1.2644e+00 + -1.9022e-01*_Complex_I, -1.2686e+00 + -4.8780e-01*_Complex_I, -1.3534e+00 + -3.3726e-01*_Complex_I, -8.4260e-01 + 1.1480e+00*_Complex_I, -9.2614e-01 + 9.9761e-01*_Complex_I, -1.1955e+00 + 5.5467e-01*_Complex_I, -1.1148e+00 + 6.9890e-01*_Complex_I, -1.1792e+00 + -3.7010e-02*_Complex_I, -1.2648e+00 + 1.1118e-01*_Complex_I, -1.2769e+00 + 4.0872e-01*_Complex_I, -1.3599e+00 + 2.5518e-01*_Complex_I, -6.7924e-01 + -1.2278e+00*_Complex_I, -8.4406e-01 + -9.1876e-01*_Complex_I, -1.0044e+00 + -6.2843e-01*_Complex_I, -9.2155e-01 + -7.7299e-01*_Complex_I, -1.0806e+00 + 1.0494e-01*_Complex_I, -1.0866e+00 + -1.9152e-01*_Complex_I, -1.0854e+00 + -4.8371e-01*_Complex_I, -1.1661e+00 + -3.3876e-01*_Complex_I, -1.0146e+00 + 8.4545e-01*_Complex_I, -7.5625e-01 + 9.8074e-01*_Complex_I, -9.2315e-01 + 6.9214e-01*_Complex_I, -8.3445e-01 + 8.3483e-01*_Complex_I, -1.0046e+00 + -3.8507e-02*_Complex_I, -1.1695e+00 + 2.5672e-01*_Complex_I, -1.0054e+00 + 5.4855e-01*_Complex_I, -1.0894e+00 + 4.0650e-01*_Complex_I, -4.9806e-01 + -1.2285e+00*_Complex_I, -6.6615e-01 + -9.1531e-01*_Complex_I, -6.6471e-01 + -6.1531e-01*_Complex_I, -5.0291e-01 + -9.1017e-01*_Complex_I, -6.6983e-01 + -4.8903e-02*_Complex_I, -7.4988e-01 + -1.8703e-01*_Complex_I, -7.4628e-01 + -4.7626e-01*_Complex_I, -8.2246e-01 + -3.3201e-01*_Complex_I, -6.7081e-01 + 1.1403e+00*_Complex_I, -5.0407e-01 + 1.1300e+00*_Complex_I, -6.6636e-01 + 5.3994e-01*_Complex_I, -4.9992e-01 + 8.2622e-01*_Complex_I, -8.3007e-01 + -3.4761e-02*_Complex_I, -7.3978e-01 + 1.0568e-01*_Complex_I, -7.4366e-01 + 3.9573e-01*_Complex_I, -6.6403e-01 + 2.4968e-01*_Complex_I, -7.5405e-01 + -1.0716e+00*_Complex_I, -5.8636e-01 + -1.0663e+00*_Complex_I, -8.3409e-01 + -6.2296e-01*_Complex_I, -7.5222e-01 + -7.6536e-01*_Complex_I, -9.1403e-01 + 1.0898e-01*_Complex_I, -9.1712e-01 + -1.8842e-01*_Complex_I, -9.1470e-01 + -4.7918e-01*_Complex_I, -9.8965e-01 + -3.3463e-01*_Complex_I, -5.9594e-01 + 1.2959e+00*_Complex_I, -5.8407e-01 + 9.7847e-01*_Complex_I, -7.5480e-01 + 6.8214e-01*_Complex_I, -6.6815e-01 + 8.2880e-01*_Complex_I, -8.3654e-01 + 2.4948e-01*_Complex_I, -9.9781e-01 + 2.5965e-01*_Complex_I, -8.3730e-01 + 5.3876e-01*_Complex_I, -9.1612e-01 + 3.9942e-01*_Complex_I, -1.6318e-01 + -1.2127e+00*_Complex_I, 3.3430e-03 + -1.2073e+00*_Complex_I, -1.5729e-01 + -6.1725e-01*_Complex_I, 4.1148e-03 + -9.0838e-01*_Complex_I, 1.7582e-01 + -3.3603e-01*_Complex_I, 9.8785e-03 + -3.7206e-02*_Complex_I, -8.5107e-02 + -4.7781e-01*_Complex_I, -1.5814e-01 + -4.2120e-02*_Complex_I, -7.2012e-02 + 1.2831e+00*_Complex_I, 9.0714e-04 + 1.1297e+00*_Complex_I, -7.8182e-02 + 6.8626e-01*_Complex_I, -1.5437e-01 + 8.2912e-01*_Complex_I, 5.1610e-01 + -3.3653e-02*_Complex_I, 1.2961e+00 + 4.0304e-01*_Complex_I, -5.9161e-03 + 5.4276e-01*_Complex_I, -1.6148e-01 + 2.5858e-01*_Complex_I, -8.4651e-02 + -1.3668e+00*_Complex_I, -3.2532e-01 + -9.1229e-01*_Complex_I, -3.2442e-01 + -6.1566e-01*_Complex_I, -1.6208e-01 + -9.0614e-01*_Complex_I, 1.8048e-01 + -3.7457e-02*_Complex_I, 1.3866e+00 + -3.3074e-01*_Complex_I, -2.4797e-01 + -4.7456e-01*_Complex_I, -2.4267e-01 + -1.8754e-01*_Complex_I, -1.6601e-01 + 1.4313e+00*_Complex_I, -1.6374e-01 + 1.1268e+00*_Complex_I, -2.4284e-01 + 6.8228e-01*_Complex_I, -3.1958e-01 + 8.2714e-01*_Complex_I, 1.4029e+00 + -4.1466e-02*_Complex_I, -2.4744e-01 + 1.0415e-01*_Complex_I, -1.7024e-01 + 5.3942e-01*_Complex_I, -2.4815e-01 + 3.9378e-01*_Complex_I, -3.3086e-01 + -1.2116e+00*_Complex_I, -4.1344e-01 + -1.0631e+00*_Complex_I, -4.9938e-01 + -6.1504e-01*_Complex_I, -5.7571e-01 + -7.6257e-01*_Complex_I, -4.9789e-01 + -3.2872e-01*_Complex_I, -5.7916e-01 + -1.9183e-01*_Complex_I, -5.7533e-01 + -4.6997e-01*_Complex_I, -6.6353e-01 + -3.3083e-01*_Complex_I, -4.1537e-01 + 1.2917e+00*_Complex_I, -3.3797e-01 + 1.1288e+00*_Complex_I, -4.1372e-01 + 6.7949e-01*_Complex_I, -5.7762e-01 + 6.8425e-01*_Complex_I, -5.0299e-01 + -3.9519e-02*_Complex_I, -5.7735e-01 + 1.0080e-01*_Complex_I, -5.7869e-01 + 3.9486e-01*_Complex_I, -4.1708e-01 + 3.8814e-01*_Complex_I, -2.6216e-01 + -1.3722e+00*_Complex_I, -2.4777e-01 + -1.0554e+00*_Complex_I, -2.4828e-01 + -7.5682e-01*_Complex_I, -4.1106e-01 + -7.6293e-01*_Complex_I, -3.3539e-01 + -4.5041e-02*_Complex_I, -4.1183e-01 + -1.8648e-01*_Complex_I, -4.0960e-01 + -4.6924e-01*_Complex_I, -3.2757e-01 + -3.2493e-01*_Complex_I, -2.4811e-01 + 1.2791e+00*_Complex_I, -4.1293e-01 + 9.7796e-01*_Complex_I, -4.9363e-01 + 5.4125e-01*_Complex_I, -2.4841e-01 + 9.7484e-01*_Complex_I, -3.3291e-01 + 2.4287e-01*_Complex_I, -4.1270e-01 + 1.0610e-01*_Complex_I, -3.3149e-01 + 5.3493e-01*_Complex_I, -4.9570e-01 + 2.4793e-01*_Complex_I, 1.0268e+00 + -9.4120e-01*_Complex_I, 1.1117e+00 + -7.9063e-01*_Complex_I, 1.0229e+00 + -6.2590e-01*_Complex_I, 1.1972e+00 + -6.4225e-01*_Complex_I, 1.1800e+00 + -3.7594e-02*_Complex_I, 1.0994e+00 + -1.8428e-01*_Complex_I, 1.1013e+00 + -4.8132e-01*_Complex_I, 1.1761e+00 + -3.3277e-01*_Complex_I, 9.5265e-01 + 9.9923e-01*_Complex_I, 1.0339e+00 + 8.4543e-01*_Complex_I, 1.1967e+00 + 5.5722e-01*_Complex_I, 1.1136e+00 + 7.0186e-01*_Complex_I, 1.1048e+00 + 1.1370e-01*_Complex_I, 1.1933e+00 + 2.5489e-01*_Complex_I, 1.0283e+00 + 5.4096e-01*_Complex_I, 1.1081e+00 + 3.9628e-01*_Complex_I, 7.8700e-01 + -1.0692e+00*_Complex_I, 8.5334e-01 + -9.1694e-01*_Complex_I, 8.5637e-01 + -6.2050e-01*_Complex_I, 9.3281e-01 + -7.7176e-01*_Complex_I, 1.0137e+00 + -3.3408e-02*_Complex_I, 9.3260e-01 + -1.7917e-01*_Complex_I, 9.3071e-01 + -4.7454e-01*_Complex_I, 1.0048e+00 + -3.2937e-01*_Complex_I, 8.6318e-01 + 1.1482e+00*_Complex_I, 7.7447e-01 + 9.8650e-01*_Complex_I, 8.5413e-01 + 5.5129e-01*_Complex_I, 9.3949e-01 + 6.9420e-01*_Complex_I, 8.5475e-01 + -2.3510e-02*_Complex_I, 9.3037e-01 + 1.2129e-01*_Complex_I, 9.3010e-01 + 4.0514e-01*_Complex_I, 1.0095e+00 + 2.6363e-01*_Complex_I, 5.2780e-01 + -1.2149e+00*_Complex_I, 5.9973e-01 + -1.0535e+00*_Complex_I, 5.9400e-01 + -7.5805e-01*_Complex_I, 5.2055e-01 + -9.0495e-01*_Complex_I, 1.2793e+00 + 9.5945e-02*_Complex_I, 6.0607e-01 + -1.8528e-01*_Complex_I, 6.0178e-01 + -4.7516e-01*_Complex_I, 6.7818e-01 + -3.2877e-01*_Complex_I, 6.0752e-01 + 1.2941e+00*_Complex_I, 6.0140e-01 + 9.9091e-01*_Complex_I, 5.9529e-01 + 6.9382e-01*_Complex_I, 5.2016e-01 + 8.4000e-01*_Complex_I, 6.0208e-01 + 1.1391e-01*_Complex_I, 6.7047e-01 + 2.5780e-01*_Complex_I, 5.2294e-01 + 5.4883e-01*_Complex_I, 5.9654e-01 + 4.0163e-01*_Complex_I, 7.0156e-01 + -1.2190e+00*_Complex_I, 6.9013e-01 + -9.1191e-01*_Complex_I, 6.9013e-01 + -6.2098e-01*_Complex_I, 7.6463e-01 + -7.6594e-01*_Complex_I, 6.9136e-01 + -3.6954e-02*_Complex_I, 7.6789e-01 + -1.7954e-01*_Complex_I, 7.6457e-01 + -4.7424e-01*_Complex_I, 8.3961e-01 + -3.2637e-01*_Complex_I, 6.8917e-01 + 1.1431e+00*_Complex_I, 8.5163e-01 + 8.4194e-01*_Complex_I, 7.6086e-01 + 6.8960e-01*_Complex_I, 6.8618e-01 + 8.3840e-01*_Complex_I, 7.6026e-01 + 1.0911e-01*_Complex_I, 8.3319e-01 + 2.5542e-01*_Complex_I, 6.8351e-01 + 5.4604e-01*_Complex_I, 7.5901e-01 + 4.0203e-01*_Complex_I, 9.6338e-02 + -1.3604e+00*_Complex_I, -7.0831e-02 + -1.0602e+00*_Complex_I, -9.4577e-04 + -6.3305e-01*_Complex_I, -6.9734e-02 + -7.6470e-01*_Complex_I, 4.2835e-01 + -4.6668e-01*_Complex_I, 3.4710e-01 + -3.3413e-01*_Complex_I, -1.5430e-01 + -3.3941e-01*_Complex_I, 8.0032e-02 + -1.7572e-01*_Complex_I, 2.5905e-02 + 1.4320e+00*_Complex_I, -6.9530e-02 + 9.7883e-01*_Complex_I, 1.7048e-01 + 8.2571e-01*_Complex_I, 1.0068e-02 + 8.3542e-01*_Complex_I, 3.4137e-01 + 2.5976e-01*_Complex_I, 9.5063e-02 + 1.1412e-01*_Complex_I, -7.6478e-02 + 4.0262e-01*_Complex_I, 1.3861e+00 + 2.4822e-01*_Complex_I, 1.8256e-01 + -1.2079e+00*_Complex_I, 9.5999e-02 + -1.0579e+00*_Complex_I, 1.7231e-01 + -6.3492e-01*_Complex_I, 9.5184e-02 + -7.6915e-01*_Complex_I, 4.2346e-01 + -1.8043e-01*_Complex_I, 3.4732e-01 + -3.9482e-02*_Complex_I, 6.7179e-03 + -3.3361e-01*_Complex_I, 1.2869e+00 + -4.7883e-01*_Complex_I, 1.0396e-01 + 1.2834e+00*_Complex_I, 1.7477e-01 + 1.1309e+00*_Complex_I, 9.3443e-02 + 6.8396e-01*_Complex_I, 1.0164e-01 + 9.8006e-01*_Complex_I, 2.6248e-01 + 4.0262e-01*_Complex_I, 1.4300e-02 + 2.5562e-01*_Complex_I, 1.7725e-01 + 5.4449e-01*_Complex_I, 1.7520e-01 + 2.5568e-01*_Complex_I, 3.5711e-01 + -1.2043e+00*_Complex_I, 4.3106e-01 + -1.0550e+00*_Complex_I, 4.3130e-01 + -7.5874e-01*_Complex_I, 3.5671e-01 + -9.0533e-01*_Complex_I, 1.2810e+00 + -1.8054e-01*_Complex_I, 2.5776e-01 + -4.7036e-01*_Complex_I, 5.1032e-01 + -6.1269e-01*_Complex_I, 5.1825e-01 + -3.2616e-01*_Complex_I, 4.3563e-01 + 1.2900e+00*_Complex_I, 5.0429e-01 + 1.1325e+00*_Complex_I, 4.3124e-01 + 6.9057e-01*_Complex_I, 4.2828e-01 + 9.7727e-01*_Complex_I, 2.6878e-01 + 1.1645e-01*_Complex_I, 5.1065e-01 + 2.5785e-01*_Complex_I, 3.5648e-01 + 5.4453e-01*_Complex_I, 4.3802e-01 + 4.0358e-01*_Complex_I, 2.8096e-01 + -1.3583e+00*_Complex_I, 2.6017e-01 + -1.0511e+00*_Complex_I, 2.6553e-01 + -7.5915e-01*_Complex_I, 1.8554e-01 + -9.0436e-01*_Complex_I, 2.7459e-01 + -1.6584e-01*_Complex_I, 9.6288e-02 + -4.7108e-01*_Complex_I, 3.4524e-01 + -6.2309e-01*_Complex_I, -7.6534e-02 + -1.8689e-01*_Complex_I, 2.6953e-01 + 1.2917e+00*_Complex_I, 3.3760e-01 + 1.1286e+00*_Complex_I, 3.3928e-01 + 8.2592e-01*_Complex_I, 2.6659e-01 + 9.7456e-01*_Complex_I, 4.2936e-01 + 1.1261e-01*_Complex_I, 9.1148e-02 + 4.0330e-01*_Complex_I, 2.6333e-01 + 6.7210e-01*_Complex_I, -7.8413e-02 + 1.1615e-01*_Complex_I, }; liquid-dsp-1.7.0/src/modem/src/modem_ask.proto.c000066400000000000000000000070631474751757600215530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_ask.c // // create an ask (amplitude-shift keying) modem object MODEM() MODEM(_create_ask)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); MODEM(_init)(q, _bits_per_symbol); switch (q->M) { case 2: q->data.ask.alpha = ASK2_ALPHA; q->scheme = LIQUID_MODEM_ASK2; break; case 4: q->data.ask.alpha = ASK4_ALPHA; q->scheme = LIQUID_MODEM_ASK4; break; case 8: q->data.ask.alpha = ASK8_ALPHA; q->scheme = LIQUID_MODEM_ASK8; break; case 16: q->data.ask.alpha = ASK16_ALPHA; q->scheme = LIQUID_MODEM_ASK16; break; case 32: q->data.ask.alpha = ASK32_ALPHA; q->scheme = LIQUID_MODEM_ASK32; break; case 64: q->data.ask.alpha = ASK64_ALPHA; q->scheme = LIQUID_MODEM_ASK64; break; case 128: q->data.ask.alpha = ASK128_ALPHA; q->scheme = LIQUID_MODEM_ASK128; break; case 256: q->data.ask.alpha = ASK256_ALPHA; q->scheme = LIQUID_MODEM_ASK256; break; default: #if 0 // calculate alpha dynamically q->data.ask.alpha = expf(-0.70735 + 0.63653*q->m); #else return liquid_error_config("modem%s_create_ask(), cannot support ASK with m > 8", EXTENSION); #endif } unsigned int k; for (k=0; k<(q->m); k++) q->ref[k] = (1<data.ask.alpha; q->modulate_func = &MODEM(_modulate_ask); q->demodulate_func = &MODEM(_demodulate_ask); // initialize soft-demodulation look-up table if (q->m >= 2 && q->m < 8) MODEM(_demodsoft_gentab)(q, 2); // reset modem and return MODEM(_reset)(q); return q; } // modulate ASK int MODEM(_modulate_ask)(MODEM() _q, unsigned int _sym_in, TC * _y) { // 'encode' input symbol (actually gray decoding) _sym_in = gray_decode(_sym_in); // modulate symbol *_y = (2*(int)_sym_in - (int)(_q->M) + 1) * _q->data.ask.alpha; return LIQUID_OK; } // demodulate ASK int MODEM(_demodulate_ask)(MODEM() _q, TC _x, unsigned int * _sym_out) { // demodulate on linearly-spaced array unsigned int s; T res_i; MODEM(_demodulate_linear_array_ref)(crealf(_x), _q->m, _q->ref, &s, &res_i); // 'decode' output symbol (actually gray encoding) *_sym_out = gray_encode(s); // re-modulate symbol and store state MODEM(_modulate_ask)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_bpsk.proto.c000066400000000000000000000060621474751757600217320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_bpsk.c : specific BPSK modem // #include #include #include #include #include #include "liquid.internal.h" // create a bpsk (binary phase-shift keying) modem object MODEM() MODEM(_create_bpsk)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_BPSK; MODEM(_init)(q, 1); q->modulate_func = &MODEM(_modulate_bpsk); q->demodulate_func = &MODEM(_demodulate_bpsk); // reset and return MODEM(_reset)(q); return q; } // modulate BPSK int MODEM(_modulate_bpsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { // compute output sample directly from input *_y = _sym_in ? -1.0f : 1.0f; return LIQUID_OK; } // demodulate BPSK int MODEM(_demodulate_bpsk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // slice directly to output symbol *_sym_out = (crealf(_x) > 0 ) ? 0 : 1; // re-modulate symbol and store state MODEM(_modulate_bpsk)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } // demodulate BPSK (soft) int MODEM(_demodulate_soft_bpsk)(MODEM() _q, TC _x, unsigned int * _s, unsigned char * _soft_bits) { // gamma = 1/(2*sigma^2), approximate for constellation size T gamma = 4.0f; // approximate log-likelihood ratio T LLR = -2.0f * crealf(_x) * gamma; int soft_bit = LLR*16 + 127; if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; _soft_bits[0] = (unsigned char) ( soft_bit ); // re-modulate symbol and store state unsigned int symbol_out = (crealf(_x) > 0 ) ? 0 : 1; MODEM(_modulate_bpsk)(_q, symbol_out, &_q->x_hat); _q->r = _x; *_s = symbol_out; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_common.proto.c000066400000000000000000000612441474751757600222660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // common utilities specific to precision #include #include #include #include "liquid.internal.h" #define DEBUG_DEMODULATE_SOFT 0 // modem structure used for both modulation and demodulation // // The modem structure implements a variety of common modulation schemes, // including (differential) phase-shift keying, and (quadrature) amplitude // modulation. // // While the same modem structure may be used for both modulation and // demodulation for most schemes, it is important to use separate objects // for differential-mode modems (e.g. LIQUID_MODEM_DPSK) as the internal state // will change after each symbol. It is usually good practice to keep // separate instances of modulators and demodulators. struct MODEM(_s) { // common data modulation_scheme scheme; // modulation scheme unsigned int m; // bits per symbol (modulation depth) unsigned int M; // constellation size, M=2^m // Reference vector for demodulating linear arrays // // By storing these values in an array they do not need to be // calculated during run-time. This speeds up the demodulation by // approximately 8%. T ref[MAX_MOD_BITS_PER_SYMBOL]; // modulation TC * symbol_map; // complete symbol map int modulate_using_map; // modulate using map (look-up table) flag // demodulation TC r; // received state vector TC x_hat; // estimated symbol (demodulator) // common data structure shared between specific modem types union { // PSK modem struct { T d_phi; // half of phase between symbols T alpha; // scaling factor for phase symbols } psk; // DPSK modem struct { T d_phi; // half of phase between symbols T phi; // angle state for differential PSK T alpha; // scaling factor for phase symbols } dpsk; // ASK modem struct { T alpha; // scaling factor to ensure unity energy } ask; // QAM modem struct { unsigned int m_i; // bits per symbol, in-phase unsigned int m_q; // bits per symbol, quadrature unsigned int M_i; // in-phase dimension, M_i=2^{m_i} unsigned int M_q; // quadrature dimension, M_q=2^{m_q} T alpha; // scaling factor to ensure unity energy } qam; // APSK modem struct { unsigned int num_levels; // number of levels unsigned int p[8]; // number of symbols per level T r[8]; // radii of levels T r_slicer[8]; // slicer radii of levels T phi[8]; // phase offset of levels unsigned char * map; // symbol mapping (allocated) } apsk; // 'square' 32-QAM struct { TC * map; // 8-sample sub-map (first quadrant) } sqam32; // 'square' 128-QAM struct { TC * map; // 32-sample sub-map (first quadrant) } sqam128; // pi/4 differential QPSK struct { T theta; // phase state } pi4dqpsk; } data; // modulate function pointer int (*modulate_func)(MODEM() _q, unsigned int _symbol_in, TC * _y); // demodulate function pointer int (*demodulate_func)(MODEM() _q, TC _x, unsigned int * _symbol_out); // soft demodulation //int demodulate_soft; // soft demodulation flag // neighbors array unsigned char * demod_soft_neighbors; // array of nearest neighbors unsigned int demod_soft_p; // number of neighbors in array }; // create digital modem of a specific scheme and bits/symbol MODEM() MODEM(_create)(modulation_scheme _scheme) { switch (_scheme) { // Phase-shift keying (PSK) case LIQUID_MODEM_PSK2: return MODEM(_create_psk)(1); case LIQUID_MODEM_PSK4: return MODEM(_create_psk)(2); case LIQUID_MODEM_PSK8: return MODEM(_create_psk)(3); case LIQUID_MODEM_PSK16: return MODEM(_create_psk)(4); case LIQUID_MODEM_PSK32: return MODEM(_create_psk)(5); case LIQUID_MODEM_PSK64: return MODEM(_create_psk)(6); case LIQUID_MODEM_PSK128: return MODEM(_create_psk)(7); case LIQUID_MODEM_PSK256: return MODEM(_create_psk)(8); // Differential phase-shift keying (DPSK) case LIQUID_MODEM_DPSK2: return MODEM(_create_dpsk)(1); case LIQUID_MODEM_DPSK4: return MODEM(_create_dpsk)(2); case LIQUID_MODEM_DPSK8: return MODEM(_create_dpsk)(3); case LIQUID_MODEM_DPSK16: return MODEM(_create_dpsk)(4); case LIQUID_MODEM_DPSK32: return MODEM(_create_dpsk)(5); case LIQUID_MODEM_DPSK64: return MODEM(_create_dpsk)(6); case LIQUID_MODEM_DPSK128: return MODEM(_create_dpsk)(7); case LIQUID_MODEM_DPSK256: return MODEM(_create_dpsk)(8); // amplitude-shift keying (ASK) case LIQUID_MODEM_ASK2: return MODEM(_create_ask)(1); case LIQUID_MODEM_ASK4: return MODEM(_create_ask)(2); case LIQUID_MODEM_ASK8: return MODEM(_create_ask)(3); case LIQUID_MODEM_ASK16: return MODEM(_create_ask)(4); case LIQUID_MODEM_ASK32: return MODEM(_create_ask)(5); case LIQUID_MODEM_ASK64: return MODEM(_create_ask)(6); case LIQUID_MODEM_ASK128: return MODEM(_create_ask)(7); case LIQUID_MODEM_ASK256: return MODEM(_create_ask)(8); // rectangular quadrature amplitude-shift keying (QAM) case LIQUID_MODEM_QAM4: return MODEM(_create_qam)(2); case LIQUID_MODEM_QAM8: return MODEM(_create_qam)(3); case LIQUID_MODEM_QAM16: return MODEM(_create_qam)(4); case LIQUID_MODEM_QAM32: return MODEM(_create_qam)(5); case LIQUID_MODEM_QAM64: return MODEM(_create_qam)(6); case LIQUID_MODEM_QAM128: return MODEM(_create_qam)(7); case LIQUID_MODEM_QAM256: return MODEM(_create_qam)(8); // amplitude phase-shift keying (APSK) case LIQUID_MODEM_APSK4: return MODEM(_create_apsk)(2); case LIQUID_MODEM_APSK8: return MODEM(_create_apsk)(3); case LIQUID_MODEM_APSK16: return MODEM(_create_apsk)(4); case LIQUID_MODEM_APSK32: return MODEM(_create_apsk)(5); case LIQUID_MODEM_APSK64: return MODEM(_create_apsk)(6); case LIQUID_MODEM_APSK128: return MODEM(_create_apsk)(7); case LIQUID_MODEM_APSK256: return MODEM(_create_apsk)(8); // specific modems case LIQUID_MODEM_BPSK: return MODEM(_create_bpsk)(); case LIQUID_MODEM_QPSK: return MODEM(_create_qpsk)(); case LIQUID_MODEM_OOK: return MODEM(_create_ook)(); case LIQUID_MODEM_SQAM32: return MODEM(_create_sqam32)(); case LIQUID_MODEM_SQAM128: return MODEM(_create_sqam128)(); case LIQUID_MODEM_V29: return MODEM(_create_V29)(); case LIQUID_MODEM_ARB16OPT: return MODEM(_create_arb16opt)(); case LIQUID_MODEM_ARB32OPT: return MODEM(_create_arb32opt)(); case LIQUID_MODEM_ARB64OPT: return MODEM(_create_arb64opt)(); case LIQUID_MODEM_ARB128OPT: return MODEM(_create_arb128opt)(); case LIQUID_MODEM_ARB256OPT: return MODEM(_create_arb256opt)(); case LIQUID_MODEM_ARB64VT: return MODEM(_create_arb64vt)(); case LIQUID_MODEM_PI4DQPSK: return MODEM(_create_pi4dqpsk)(); // arbitrary modem case LIQUID_MODEM_ARB: return liquid_error_config("modem%s_create(), cannot create arbitrary modem (LIQUID_MODEM_ARB) without specifying constellation", EXTENSION); // unknown modulation scheme default: return liquid_error_config("modem%s_create(), unknown/unsupported modulation scheme : %u",EXTENSION,_scheme); } return NULL; } // recreate modulation scheme, re-allocating memory as necessary MODEM() MODEM(_recreate)(MODEM() _q, modulation_scheme _scheme) { // TODO : regenerate modem only when truly necessary if (_q->scheme != _scheme) { // destroy and re-create modem MODEM(_destroy)(_q); _q = MODEM(_create)(_scheme); } // return object return _q; } // copy object MODEM() MODEM(_copy)(MODEM() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("modem%s_copy(), object cannot be NULL", EXTENSION); // handle special case for arbitrary modem types if (q_orig->scheme == LIQUID_MODEM_ARB) { // directly copy map to avoid resacling MODEM() q_copy = MODEM(_create_arb)(q_orig->m); memmove(q_copy->symbol_map, q_orig->symbol_map, q_copy->M*sizeof(TC)); return q_copy; } // create new object MODEM() q_copy = MODEM(_create)(q_orig->scheme); // copy state for specific types switch (q_copy->scheme) { // Differential phase-shift keying (DPSK) case LIQUID_MODEM_DPSK2: case LIQUID_MODEM_DPSK4: case LIQUID_MODEM_DPSK8: case LIQUID_MODEM_DPSK16: case LIQUID_MODEM_DPSK32: case LIQUID_MODEM_DPSK64: case LIQUID_MODEM_DPSK128: case LIQUID_MODEM_DPSK256: q_copy->data.dpsk.d_phi = q_orig->data.dpsk.d_phi; q_copy->data.dpsk.phi = q_orig->data.dpsk.phi; q_copy->data.dpsk.alpha = q_orig->data.dpsk.alpha; break; case LIQUID_MODEM_PI4DQPSK: q_copy->data.pi4dqpsk.theta = q_orig->data.pi4dqpsk.theta; break; default:; } return q_copy; } // destroy a modem object int MODEM(_destroy)(MODEM() _q) { // free symbol map if (_q->symbol_map != NULL) free(_q->symbol_map); // free soft-demodulation neighbors table if (_q->demod_soft_neighbors != NULL) free(_q->demod_soft_neighbors); // free memory in specific data types if (_q->scheme == LIQUID_MODEM_SQAM32) { free(_q->data.sqam32.map); } else if (_q->scheme == LIQUID_MODEM_SQAM128) { free(_q->data.sqam128.map); } else if (liquid_modem_is_apsk(_q->scheme)) { free(_q->data.apsk.map); } // free main object memory free(_q); return LIQUID_OK; } // print a modem object int MODEM(_print)(MODEM() _q) { printf("\n", EXTENSION, modulation_types[_q->scheme].name, 1 << (_q->m)); return LIQUID_OK; } // reset a modem object (only an issue with dpsk) int MODEM(_reset)(MODEM() _q) { _q->r = 1.0f; // received sample _q->x_hat = _q->r; // estimated symbol if ( liquid_modem_is_dpsk(_q->scheme) ) { _q->data.dpsk.phi = 0.0f; // reset differential PSK phase state } else if ( _q->scheme == LIQUID_MODEM_PI4DQPSK ) { _q->data.pi4dqpsk.theta = 0; // reset phase state } return LIQUID_OK; } // initialize a generic modem object int MODEM(_init)(MODEM() _q, unsigned int _bits_per_symbol) { if (_bits_per_symbol < 1 ) return liquid_error(LIQUID_EICONFIG,"modem%s_init(), modem must have at least 1 bit/symbol",EXTENSION); if (_bits_per_symbol > MAX_MOD_BITS_PER_SYMBOL) return liquid_error(LIQUID_EICONFIG,"modem%s_init(), maximum number of bits per symbol exceeded",EXTENSION); // initialize common elements _q->symbol_map = NULL; // symbol map (LIQUID_MODEM_ARB only) _q->modulate_using_map=0; // modulate using map flag // common data _q->m = _bits_per_symbol; // bits/symbol _q->M = 1 << (_q->m); // constellation size (2^m) // set function pointers initially to NULL _q->modulate_func = NULL; _q->demodulate_func = NULL; // soft demodulation _q->demod_soft_neighbors = NULL; _q->demod_soft_p = 0; return LIQUID_OK; } // initialize symbol map for fast modulation int MODEM(_init_map)(MODEM() _q) { // validate input if (_q->symbol_map == NULL) return liquid_error(LIQUID_EICONFIG,"modem%s_init_map(), symbol map array has not been allocated",EXTENSION); if (_q->M == 0 || _q->M > (1<modulate_func == NULL) return liquid_error(LIQUID_EICONFIG,"modem%s_init_map(), modulation function has not been initialized",EXTENSION); unsigned int i; for (i=0; i<_q->M; i++) _q->modulate_func(_q, i, &_q->symbol_map[i]); return LIQUID_OK; } // Generate random symbol unsigned int MODEM(_gen_rand_sym)(MODEM() _q) { return rand() % (_q->M); } // Get modem depth (bits/symbol) unsigned int MODEM(_get_bps)(MODEM() _q) { return _q->m; } // get modulation scheme modulation_scheme MODEM(_get_scheme)(MODEM() _q) { return _q->scheme; } // generic modulatio function // _q : modem object // _symbol_in : input symbol // _y : output sample int MODEM(_modulate)(MODEM() _q, unsigned int _symbol_in, TC * _y) { // validate input if (_symbol_in >= _q->M) return liquid_error(LIQUID_EICONFIG,"modem%s_modulate(), input symbol exceeds constellation size", EXTENSION); if (_q->modulate_using_map) { // modulate simply using map (look-up table) MODEM(_modulate_map)(_q, _symbol_in, _y); } else { // invoke method specific to scheme (calculate symbol on the fly) _q->modulate_func(_q, _symbol_in, _y); } return LIQUID_OK; } // modulate using symbol map (look-up table) int MODEM(_modulate_map)(MODEM() _q, unsigned int _symbol_in, TC * _y) { if (_symbol_in >= _q->M) return liquid_error(LIQUID_EICONFIG,"modem%s_modulate_table(), input symbol exceeds maximum", EXTENSION); if (_q->symbol_map == NULL) return liquid_error(LIQUID_EICONFIG,"modem%s_modulate_table(), symbol table not initialized", EXTENSION); // map sample directly to output *_y = _q->symbol_map[_symbol_in]; return LIQUID_OK; } // generic demodulation int MODEM(_demodulate)(MODEM() _q, TC x, unsigned int *symbol_out) { // invoke method specific to scheme (calculate symbol on the fly) return _q->demodulate_func(_q, x, symbol_out); } // generic soft demodulation int MODEM(_demodulate_soft)(MODEM() _q, TC _x, unsigned int * _s, unsigned char * _soft_bits) { // switch scheme switch (_q->scheme) { case LIQUID_MODEM_ARB: return MODEM(_demodulate_soft_arb)( _q,_x,_s,_soft_bits); case LIQUID_MODEM_BPSK: return MODEM(_demodulate_soft_bpsk)(_q,_x,_s,_soft_bits); case LIQUID_MODEM_QPSK: return MODEM(_demodulate_soft_qpsk)(_q,_x,_s,_soft_bits); case LIQUID_MODEM_PI4DQPSK: return MODEM(_demodulate_soft_pi4dqpsk)(_q,_x,_s,_soft_bits); default:; } // check if... if (_q->demod_soft_neighbors != NULL && _q->demod_soft_p != 0) { // demodulate using approximate log-likelihood method with // look-up table for nearest neighbors return MODEM(_demodulate_soft_table)(_q, _x, _s, _soft_bits); } // for now demodulate normally and simply copy the // hard-demodulated bits unsigned int symbol_out; _q->demodulate_func(_q, _x, &symbol_out); *_s = symbol_out; // unpack soft bits return liquid_unpack_soft_bits(symbol_out, _q->m, _soft_bits); } #if DEBUG_DEMODULATE_SOFT // print a string of bits to the standard output void print_bitstring_demod_soft(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); } #endif // generic soft demodulation using look-up table... // _q : demodulator object // _r : received sample // _s : hard demodulator output // _soft_bits : soft bit output (approximate log-likelihood ratio) int MODEM(_demodulate_soft_table)(MODEM() _q, TC _r, unsigned int * _s, unsigned char * _soft_bits) { // run hard demodulation; this will store re-modulated sample // as internal variable x_hat unsigned int s; MODEM(_demodulate)(_q, _r, &s); unsigned int bps = MODEM(_get_bps)(_q); // gamma = 1/(2*sigma^2), approximate for constellation size T gamma = 1.2f*_q->M; // set and initialize minimum bit values unsigned int i; unsigned int k; T dmin_0[bps]; T dmin_1[bps]; for (k=0; kdemod_soft_neighbors; unsigned int p = _q->demod_soft_p; // check hard demodulation d = crealf( (_r-_q->x_hat)*conjf(_r-_q->x_hat) ); for (k=0; k> (bps-k-1)) & 0x01; if (bit) dmin_1[k] = d; else dmin_0[k] = d; } // parse all 'nearest neighbors' and find minimum distance for each bit for (i=0; imodulate_using_map) x_hat = _q->symbol_map[ softab[s*p + i] ]; else MODEM(_modulate)(_q, softab[s*p+i], &x_hat); // compute magnitude squared of Euclidean distance //d = crealf( (_r-x_hat)*conjf(_r-x_hat) ); // (same as above, but faster) TC e = _r - x_hat; d = crealf(e)*crealf(e) + cimagf(e)*cimagf(e); // look at each bit in 'nearest neighbor' and update minimum for (k=0; k> (bps-k-1)) & 0x01; if ( bit ) { if (d < dmin_1[k]) dmin_1[k] = d; } else { if (d < dmin_0[k]) dmin_0[k] = d; } } } // make soft bit assignments for (k=0; k 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; _soft_bits[k] = (unsigned char)soft_bit; } // set hard output symbol *_s = s; return LIQUID_OK; } // get demodulator's estimated transmit sample int MODEM(_get_demodulator_sample)(MODEM() _q, TC * _x_hat) { *_x_hat = _q->x_hat; return LIQUID_OK; } // get demodulator phase error T MODEM(_get_demodulator_phase_error)(MODEM() _q) { return cimagf(_q->r*conjf(_q->x_hat)); } // get error vector magnitude T MODEM(_get_demodulator_evm)(MODEM() _q) { return cabsf(_q->x_hat - _q->r); } #if 0 // Demodulate a linear symbol constellation using dynamic threshold calculation // _v : input value // _m : bits per symbol // _alpha : scaling factor // _s : demodulated symbol // _res : residual int MODEM(_demodulate_linear_array)(T _v, unsigned int _m, T _alpha, unsigned int * _s, T * _res) { unsigned int s=0; unsigned int i, k = _m; T ref=0.0f; for (i=0; i<_m; i++) { s <<= 1; s |= (_v > 0) ? 1 : 0; ref = _alpha * (1<<(k-1)); _v += (_v < 0) ? ref : -ref; k--; } *_s = s; *_res = _v; return LIQUID_OK; } #endif // Demodulate a linear symbol constellation using referenced lookup table // _v : input value // _m : bits per symbol // _ref : array of thresholds // _s : demodulated symbol // _res : residual int MODEM(_demodulate_linear_array_ref)(T _v, unsigned int _m, T * _ref, unsigned int * _s, T * _res) { // initialize loop counter register unsigned int i; // initialize demodulated symbol register unsigned int s=0; for (i=0; i<_m; i++) { // prepare symbol for next demodulated bit s <<= 1; // compare received value to zero if ( _v > 0 ) { // shift '1' into symbol, subtract reference s |= 1; _v -= _ref[_m-i-1]; } else { // shift '0' into symbol, add reference s |= 0; _v += _ref[_m-i-1]; } } // return demodulated symbol *_s = s; // return residual *_res = _v; return LIQUID_OK; } // generate soft demodulation look-up table int MODEM(_demodsoft_gentab)(MODEM() _q, unsigned int _p) { // validate input: ensure number of nearest symbols is not too large if (_p > (_q->M-1)) return liquid_error(LIQUID_EICONFIG,"modem%s_demodsoft_gentab(), requesting too many neighbors", EXTENSION); // allocate internal memory _q->demod_soft_p = _p; _q->demod_soft_neighbors = (unsigned char*)malloc(_q->M*_p*sizeof(unsigned char)); unsigned int i; unsigned int j; unsigned int k; // generate constellation // TODO : enforce full constellation for modulation unsigned int M = _q->M; // constellation size TC c[M]; // constellation for (i=0; idemod_soft_neighbors[i*_p + k] = M; } int symbol_valid; for (i=0; idemod_soft_neighbors[i*_p + l] == j ) symbol_valid = 0; } // compute distance T d = cabsf( c[i] - c[j] ); if ( d < dmin && symbol_valid ) { dmin = d; _q->demod_soft_neighbors[i*_p + k] = j; } } } } #if DEBUG_DEMODULATE_SOFT // // print results // unsigned int bps = _q->m; for (i=0; idemod_soft_neighbors[i*_p + k],bps); if (_q->demod_soft_neighbors[i*_p + k] < M) printf("(%6.4f)", cabsf( c[i]-c[_q->demod_soft_neighbors[i*_p+k]] )); else printf(" "); } printf("\n"); } // print c-type array printf("\n"); printf("// %s%u soft demodulation nearest neighbors (p=%u)\n", modulation_types[_q->scheme].name, M, _p); printf("const unsigned char %s%u_demod_soft_neighbors[%u] = {\n", modulation_types[_q->scheme].name, M, _p*M); printf(" "); for (i=0; idemod_soft_neighbors[i*_p+k]); if (k != _p-1) printf(","); } if (i != M-1) { printf(", // "); print_bitstring_demod_soft(i,bps); printf("\n "); } else { printf("}; // "); print_bitstring_demod_soft(i,bps); printf("\n\n"); } } #endif return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_dpsk.proto.c000066400000000000000000000076071474751757600217420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_dpsk.c // // create a dpsk (differential phase-shift keying) modem object MODEM() MODEM(_create_dpsk)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); switch (_bits_per_symbol) { case 1: q->scheme = LIQUID_MODEM_DPSK2; break; case 2: q->scheme = LIQUID_MODEM_DPSK4; break; case 3: q->scheme = LIQUID_MODEM_DPSK8; break; case 4: q->scheme = LIQUID_MODEM_DPSK16; break; case 5: q->scheme = LIQUID_MODEM_DPSK32; break; case 6: q->scheme = LIQUID_MODEM_DPSK64; break; case 7: q->scheme = LIQUID_MODEM_DPSK128; break; case 8: q->scheme = LIQUID_MODEM_DPSK256; break; default: return liquid_error_config("modem%s_create_dpsk(), cannot support DPSK with m > 8",EXTENSION); } MODEM(_init)(q, _bits_per_symbol); q->data.dpsk.alpha = M_PI/(T)(q->M); q->data.dpsk.phi = 0.0f; unsigned int k; for (k=0; k<(q->m); k++) q->ref[k] = (1<data.dpsk.alpha; q->data.dpsk.d_phi = M_PI*(1.0f - 1.0f/(T)(q->M)); q->modulate_func = &MODEM(_modulate_dpsk); q->demodulate_func = &MODEM(_demodulate_dpsk); // reset and return MODEM(_reset)(q); return q; } // modulate DPSK int MODEM(_modulate_dpsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { // 'encode' input symbol (actually gray decoding) _sym_in = gray_decode(_sym_in); // compute phase difference between this symbol and the previous _q->data.dpsk.phi += _sym_in * 2 * _q->data.dpsk.alpha; // limit phase _q->data.dpsk.phi -= (_q->data.dpsk.phi > 2*M_PI) ? 2*M_PI : 0.0f; // compute output sample *_y = liquid_cexpjf(_q->data.dpsk.phi); // save symbol state _q->r = *_y; return LIQUID_OK; } int MODEM(_demodulate_dpsk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // compute angle difference T theta = cargf(_x); T d_theta = cargf(_x) - _q->data.dpsk.phi; _q->data.dpsk.phi = theta; // subtract phase offset, ensuring phase is in [-pi,pi) d_theta -= _q->data.dpsk.d_phi; if (d_theta > M_PI) d_theta -= 2*M_PI; else if (d_theta < -M_PI) d_theta += 2*M_PI; // demodulate on linearly-spaced array unsigned int s; // demodulated symbol T demod_phase_error; // demodulation phase error MODEM(_demodulate_linear_array_ref)(d_theta, _q->m, _q->ref, &s, &demod_phase_error); // 'decode' output symbol (actually gray encoding) *_sym_out = gray_encode(s); // re-modulate symbol (accounting for differential rotation) // and store state _q->x_hat = liquid_cexpjf(theta - demod_phase_error); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_ook.proto.c000066400000000000000000000044211474751757600215600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_ook.c // #include #include #include #include #include #include "liquid.internal.h" // create an ook (on/off keying) modem object MODEM() MODEM(_create_ook)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_OOK; MODEM(_init)(q, 1); q->modulate_func = &MODEM(_modulate_ook); q->demodulate_func = &MODEM(_demodulate_ook); // reset and return MODEM(_reset)(q); return q; } // modulate symbol using on/off keying int MODEM(_modulate_ook)(MODEM() _q, unsigned int _sym_in, float complex * _y) { // compute output sample directly from input *_y = _sym_in ? 0.0f : M_SQRT2; return LIQUID_OK; } // demodulate OOK int MODEM(_demodulate_ook)(MODEM() _q, float complex _x, unsigned int * _sym_out) { // slice directly to output symbol *_sym_out = (crealf(_x) > M_SQRT1_2 ) ? 0 : 1; // re-modulate symbol and store state MODEM(_modulate_ook)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_pi4dqpsk.proto.c000066400000000000000000000077441474751757600225420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_pi4dqpsk.c // #include #include #include #include #include #include "liquid.internal.h" // create a pi/4-DQPSK (pi/4 differential quaternary phase-shift keying) modem object MODEM() MODEM(_create_pi4dqpsk)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_PI4DQPSK; MODEM(_init)(q, 2); q->modulate_func = &MODEM(_modulate_pi4dqpsk); q->demodulate_func = &MODEM(_demodulate_pi4dqpsk); // reset and return MODEM(_reset)(q); return q; } // modulate PI4DQPSK int MODEM(_modulate_pi4dqpsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { float d_theta = 0.0f; switch (_sym_in) { case 0: d_theta = +1*0.25*M_PI; break; case 1: d_theta = +3*0.25*M_PI; break; case 2: d_theta = -1*0.25*M_PI; break; case 3: d_theta = -3*0.25*M_PI; break; default:; } // accumulate phase _q->data.pi4dqpsk.theta += d_theta; // constrain phase if (_q->data.pi4dqpsk.theta > M_PI) _q->data.pi4dqpsk.theta -= 2*M_PI; if (_q->data.pi4dqpsk.theta < -M_PI) _q->data.pi4dqpsk.theta += 2*M_PI; // compute output symbol and return *_y = liquid_cexpjf(_q->data.pi4dqpsk.theta); return LIQUID_OK; } // demodulate PI4DQPSK int MODEM(_demodulate_pi4dqpsk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // compute input phase T theta = cargf(_x); // compute differential phase T d_theta = theta - _q->data.pi4dqpsk.theta; while (d_theta > M_PI) d_theta -= 2*M_PI; while (d_theta < -M_PI) d_theta += 2*M_PI; // slice directly to output symbol if (d_theta > 0.5f*M_PI) *_sym_out = 1; else if (d_theta > 0) *_sym_out = 0; else if (d_theta < -0.5f*M_PI) *_sym_out = 3; else *_sym_out = 2; // re-modulate symbol and store state T d_theta_ideal = 0.0f; switch (*_sym_out) { case 0: d_theta_ideal = +1*0.25*M_PI; break; case 1: d_theta_ideal = +3*0.25*M_PI; break; case 2: d_theta_ideal = -1*0.25*M_PI; break; case 3: d_theta_ideal = -3*0.25*M_PI; break; default:; } _q->x_hat = liquid_cexpjf(_q->data.pi4dqpsk.theta + d_theta_ideal); _q->r = _x; _q->data.pi4dqpsk.theta = theta; return LIQUID_OK; } // demodulate pi/4 differential QPSK (soft) int MODEM(_demodulate_soft_pi4dqpsk)(MODEM() _q, TC _x, unsigned int * _s, unsigned char * _soft_bits) { // hard demod MODEM(_demodulate_pi4dqpsk)(_q, _x, _s); // convert to soft values _soft_bits[0] = *_s & 2 ? 255 : 0; _soft_bits[1] = *_s & 1 ? 255 : 0; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_psk.proto.c000066400000000000000000000075311474751757600215720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_psk.c // // create a psk (phase-shift keying) modem object MODEM() MODEM(_create_psk)(unsigned int _bits_per_symbol) { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); switch (_bits_per_symbol) { case 1: q->scheme = LIQUID_MODEM_PSK2; break; case 2: q->scheme = LIQUID_MODEM_PSK4; break; case 3: q->scheme = LIQUID_MODEM_PSK8; break; case 4: q->scheme = LIQUID_MODEM_PSK16; break; case 5: q->scheme = LIQUID_MODEM_PSK32; break; case 6: q->scheme = LIQUID_MODEM_PSK64; break; case 7: q->scheme = LIQUID_MODEM_PSK128; break; case 8: q->scheme = LIQUID_MODEM_PSK256; break; default: return liquid_error_config("modem%s_create_psk(), cannot support PSK with m > 8",EXTENSION); } // initialize basic modem structure MODEM(_init)(q, _bits_per_symbol); // compute alpha q->data.psk.alpha = M_PI/(T)(q->M); // initialize demodulation array reference unsigned int k; for (k=0; k<(q->m); k++) q->ref[k] = (1<data.psk.alpha; // compute phase offset (half of phase difference between symbols) q->data.psk.d_phi = M_PI*(1.0f - 1.0f/(T)(q->M)); // set modulation/demodulation functions q->modulate_func = &MODEM(_modulate_psk); q->demodulate_func = &MODEM(_demodulate_psk); // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; // initialize soft-demodulation look-up table if (q->m >= 3) MODEM(_demodsoft_gentab)(q, 2); // reset and return MODEM(_reset)(q); return q; } // modulate PSK int MODEM(_modulate_psk)(MODEM() _q, unsigned int _sym_in, TC * _y) { // 'encode' input symbol (actually gray decoding) _sym_in = gray_decode(_sym_in); // compute output sample *_y = liquid_cexpjf(_sym_in * 2 * _q->data.psk.alpha ); return LIQUID_OK; } // demodulate PSK int MODEM(_demodulate_psk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // compute angle and subtract phase offset, ensuring phase is in [-pi,pi) T theta = cargf(_x); theta -= _q->data.psk.d_phi; if (theta < -M_PI) theta += 2*M_PI; // demodulate on linearly-spaced array unsigned int s; // demodulated symbol T demod_phase_error; // demodulation phase error MODEM(_demodulate_linear_array_ref)(theta, _q->m, _q->ref, &s, &demod_phase_error); // 'decode' output symbol (actually gray encoding) *_sym_out = gray_encode(s); // re-modulate symbol and store state MODEM(_modulate_psk)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_qam.proto.c000066400000000000000000000123621474751757600215510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_qam.c // #include // create a qam (quaternary amplitude-shift keying) modem object MODEM() MODEM(_create_qam)(unsigned int _bits_per_symbol) { if (_bits_per_symbol < 1 ) return liquid_error_config("modem%s_create_qam(), modem must have at least 2 bits/symbol",EXTENSION); MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); MODEM(_init)(q, _bits_per_symbol); if (q->m % 2) { // rectangular qam q->data.qam.m_i = (q->m + 1) >> 1; q->data.qam.m_q = (q->m - 1) >> 1; } else { // square qam q->data.qam.m_i = q->m >> 1; q->data.qam.m_q = q->m >> 1; } q->data.qam.M_i = 1 << (q->data.qam.m_i); q->data.qam.M_q = 1 << (q->data.qam.m_q); assert(q->data.qam.m_i + q->data.qam.m_q == q->m); assert(q->data.qam.M_i * q->data.qam.M_q == q->M); switch (q->M) { case 4: q->data.qam.alpha = RQAM4_ALPHA; q->scheme = LIQUID_MODEM_QAM4; break; case 8: q->data.qam.alpha = RQAM8_ALPHA; q->scheme = LIQUID_MODEM_QAM8; break; case 16: q->data.qam.alpha = RQAM16_ALPHA; q->scheme = LIQUID_MODEM_QAM16; break; case 32: q->data.qam.alpha = RQAM32_ALPHA; q->scheme = LIQUID_MODEM_QAM32; break; case 64: q->data.qam.alpha = RQAM64_ALPHA; q->scheme = LIQUID_MODEM_QAM64; break; case 128: q->data.qam.alpha = RQAM128_ALPHA; q->scheme = LIQUID_MODEM_QAM128; break; case 256: q->data.qam.alpha = RQAM256_ALPHA; q->scheme = LIQUID_MODEM_QAM256; break; #if 0 case 512: q->data.qam.alpha = RQAM512_ALPHA; break; case 1024: q->data.qam.alpha = RQAM1024_ALPHA; break; case 2048: q->data.qam.alpha = RQAM2048_ALPHA; break; case 4096: q->data.qam.alpha = RQAM4096_ALPHA; break; default: // calculate alpha dynamically // NOTE: this is only an approximation q->data.qam.alpha = sqrtf(2.0f / (T)(q->M) ); #else default: return liquid_error_config("modem%s_create_qam(), cannot support QAM with m > 8",EXTENSION); #endif } unsigned int k; for (k=0; k<(q->m); k++) q->ref[k] = (1<data.qam.alpha; q->modulate_func = &MODEM(_modulate_qam); q->demodulate_func = &MODEM(_demodulate_qam); // initialize symbol map q->symbol_map = (TC*)malloc(q->M*sizeof(TC)); MODEM(_init_map)(q); q->modulate_using_map = 1; // initialize soft-demodulation look-up table if (q->m == 3) MODEM(_demodsoft_gentab)(q, 3); else if (q->m >= 4) MODEM(_demodsoft_gentab)(q, 4); // reset and return MODEM(_reset)(q); return q; } // modulate QAM int MODEM(_modulate_qam)(MODEM() _q, unsigned int _sym_in, TC * _y) { unsigned int s_i; // in-phase symbol unsigned int s_q; // quadrature symbol s_i = _sym_in >> _q->data.qam.m_q; s_q = _sym_in & ( (1<<_q->data.qam.m_q)-1 ); // 'encode' symbols (actually gray decoding) s_i = gray_decode(s_i); s_q = gray_decode(s_q); // compute output sample *_y = (2*(int)s_i - (int)(_q->data.qam.M_i) + 1) * _q->data.qam.alpha + (2*(int)s_q - (int)(_q->data.qam.M_q) + 1) * _q->data.qam.alpha * _Complex_I; return LIQUID_OK; } // demodulate QAM int MODEM(_demodulate_qam)(MODEM() _q, TC _x, unsigned int * _sym_out) { // demodulate in-phase component on linearly-spaced array unsigned int s_i; // in-phase symbol T res_i; // in-phase residual MODEM(_demodulate_linear_array_ref)(crealf(_x), _q->data.qam.m_i, _q->ref, &s_i, &res_i); // demodulate quadrature component on linearly-spaced array unsigned int s_q; // quadrature symbol T res_q; // quadrature residual MODEM(_demodulate_linear_array_ref)(cimagf(_x), _q->data.qam.m_q, _q->ref, &s_q, &res_q); // 'decode' output symbol (actually gray encoding) s_i = gray_encode(s_i); s_q = gray_encode(s_q); *_sym_out = ( s_i << _q->data.qam.m_q ) + s_q; // re-modulate symbol (subtract residual) and store state _q->x_hat = _x - (res_i + _Complex_I*res_q); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_qpsk.proto.c000066400000000000000000000066711474751757600217570ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_qpsk.c // #include #include #include #include #include #include "liquid.internal.h" // create a qpsk (quaternary phase-shift keying) modem object MODEM() MODEM(_create_qpsk)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_QPSK; MODEM(_init)(q, 2); q->modulate_func = &MODEM(_modulate_qpsk); q->demodulate_func = &MODEM(_demodulate_qpsk); // reset and return MODEM(_reset)(q); return q; } // modulate QPSK int MODEM(_modulate_qpsk)(MODEM() _q, unsigned int _sym_in, TC * _y) { // compute output sample directly from input *_y = (_sym_in & 0x01 ? -M_SQRT1_2 : M_SQRT1_2) + (_sym_in & 0x02 ? -M_SQRT1_2 : M_SQRT1_2)*_Complex_I; return LIQUID_OK; } // demodulate QPSK int MODEM(_demodulate_qpsk)(MODEM() _q, TC _x, unsigned int * _sym_out) { // slice directly to output symbol *_sym_out = (crealf(_x) > 0 ? 0 : 1) + (cimagf(_x) > 0 ? 0 : 2); // re-modulate symbol and store state MODEM(_modulate_qpsk)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } // demodulate QPSK (soft) int MODEM(_demodulate_soft_qpsk)(MODEM() _q, TC _x, unsigned int * _s, unsigned char * _soft_bits) { // gamma = 1/(2*sigma^2), approximate for constellation size T gamma = 5.8f; // approximate log-likelihood ratios T LLR; int soft_bit; // compute soft value for first bit LLR = -2.0f * cimagf(_x) * gamma; soft_bit = LLR*16 + 127; if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; _soft_bits[0] = (unsigned char) ( soft_bit ); // compute soft value for first bit LLR = -2.0f * crealf(_x) * gamma; soft_bit = LLR*16 + 127; if (soft_bit > 255) soft_bit = 255; if (soft_bit < 0) soft_bit = 0; _soft_bits[1] = (unsigned char) ( soft_bit ); // re-modulate symbol and store state *_s = (crealf(_x) > 0 ? 0 : 1) + (cimagf(_x) > 0 ? 0 : 2); MODEM(_modulate_qpsk)(_q, *_s, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_sqam128.proto.c000066400000000000000000000075611474751757600221740ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_sqam128.c // // create a 'square' 128-QAM modem object MODEM() MODEM(_create_sqam128)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_SQAM128; MODEM(_init)(q, 7); // allocate memory for 32-point symbol map q->data.sqam128.map = (TC*) malloc( 32*sizeof(TC) ); #if T == float memmove(q->data.sqam128.map, modem_arb_sqam128, 32*sizeof(TC)); #endif // set modulation, demodulation functions q->modulate_func = &MODEM(_modulate_sqam128); q->demodulate_func = &MODEM(_demodulate_sqam128); // reset and return MODEM(_reset)(q); return q; } // modulate symbol with 'square' 128-QAM int MODEM(_modulate_sqam128)(MODEM() _q, unsigned int _sym_in, TC * _y) { // strip off most-significant two bits (quadrant) unsigned int quad = (_sym_in >> 5) & 0x03; // strip off least-significant 5 bits unsigned int s = _sym_in & 0x1f; TC p = _q->data.sqam128.map[s]; switch (quad) { case 0: *_y = p; break; case 1: *_y = conjf(p); break; case 2: *_y = -conjf(p); break; case 3: *_y = -p; break; default: // should never get to this point return liquid_error(LIQUID_EINT,"modem%s_modulate_sqam128(), logic error",EXTENSION); } return LIQUID_OK; } // demodulate 'square' 128-QAM int MODEM(_demodulate_sqam128)(MODEM() _q, TC _x, unsigned int * _sym_out) { // determine quadrant and de-rotate to first quadrant // 10 | 00 // ---+--- // 11 | 01 unsigned int quad = 2*(crealf(_x) < 0.0f) + (cimagf(_x) < 0.0f); TC x_prime = _x; switch (quad) { case 0: x_prime = _x; break; case 1: x_prime = conjf(_x); break; case 2: x_prime = -conjf(_x); break; case 3: x_prime = -_x; break; default: // should never get to this point return liquid_error(LIQUID_EINT,"modem%s_demodulate_sqam128(), logic error",EXTENSION); } //printf(" x = %12.8f +j*%12.8f, quad = %1u, r = %12.8f + j*%12.8f\n", // crealf(_x), cimagf(_x), quad, crealf(r), cimagf(r)); assert(crealf(x_prime) >= 0.0f); assert(cimagf(x_prime) >= 0.0f); // find symbol in map closest to x_prime T dmin = 0.0f; T d = 0.0f; unsigned int i; for (i=0; i<32; i++) { d = cabsf(x_prime - _q->data.sqam128.map[i]); if (i==0 || d < dmin) { dmin = d; *_sym_out = i; } } // add quadrant bits *_sym_out |= (quad << 5); // re-modulate symbol and store state MODEM(_modulate_sqam128)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_sqam32.proto.c000066400000000000000000000075261474751757600221070ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_sqam32.c // // create a 'square' 32-QAM modem object MODEM() MODEM(_create_sqam32)() { MODEM() q = (MODEM()) malloc( sizeof(struct MODEM(_s)) ); q->scheme = LIQUID_MODEM_SQAM32; MODEM(_init)(q, 5); // allocate memory for 8-point symbol map q->data.sqam32.map = (TC*) malloc( 8*sizeof(TC) ); #if T == float memmove(q->data.sqam32.map, modem_arb_sqam32, 8*sizeof(TC)); #endif // set modulation, demodulation functions q->modulate_func = &MODEM(_modulate_sqam32); q->demodulate_func = &MODEM(_demodulate_sqam32); // reset and return MODEM(_reset)(q); return q; } // modulate symbol with 'square' 32-QAM int MODEM(_modulate_sqam32)(MODEM() _q, unsigned int _sym_in, TC * _y) { // strip off most-significant two bits (quadrant) unsigned int quad = (_sym_in >> 3) & 0x03; // strip off least-significant 3 bits unsigned int s = _sym_in & 0x07; TC p = _q->data.sqam32.map[s]; switch (quad) { case 0: *_y = p; break; case 1: *_y = conjf(p); break; case 2: *_y = -conjf(p); break; case 3: *_y = -p; break; default: // should never get to this point return liquid_error(LIQUID_EINT,"modem%s_modulate_sqam32(), logic error",EXTENSION); } return LIQUID_OK; } // demodulate 'square' 32-QAM int MODEM(_demodulate_sqam32)(MODEM() _q, TC _x, unsigned int * _sym_out) { // determine quadrant and de-rotate to first quadrant // 10 | 00 // ---+--- // 11 | 01 unsigned int quad = 2*(crealf(_x) < 0.0f) + (cimagf(_x) < 0.0f); TC x_prime = _x; switch (quad) { case 0: x_prime = _x; break; case 1: x_prime = conjf(_x); break; case 2: x_prime = -conjf(_x); break; case 3: x_prime = -_x; break; default: // should never get to this point return liquid_error(LIQUID_EINT,"modem%s_demodulate_sqam32(), logic error",EXTENSION); } //printf(" x = %12.8f +j*%12.8f, quad = %1u, r = %12.8f + j*%12.8f\n", // crealf(_x), cimagf(_x), quad, crealf(r), cimagf(r)); assert(crealf(x_prime) >= 0.0f); assert(cimagf(x_prime) >= 0.0f); // find symbol in map closest to x_prime T dmin = 0.0f; T d = 0.0f; unsigned int i; for (i=0; i<8; i++) { d = cabsf(x_prime - _q->data.sqam32.map[i]); if (i==0 || d < dmin) { dmin = d; *_sym_out = i; } } // add quadrant bits *_sym_out |= (quad << 3); // re-modulate symbol and store state MODEM(_modulate_sqam32)(_q, *_sym_out, &_q->x_hat); _q->r = _x; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modem_utilities.c000066400000000000000000000254761474751757600216560ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // modem_utilities.c : common utilities not specific to precision // #include #include #include #include "liquid.internal.h" // full modulation type descriptor const struct modulation_type_s modulation_types[LIQUID_MODEM_NUM_SCHEMES] = { // name fullname scheme bps // unknown {"unknown", "unknown", LIQUID_MODEM_UNKNOWN, 0}, // phase-shift keying {"psk2", "phase-shift keying (2)", LIQUID_MODEM_PSK2, 1}, {"psk4", "phase-shift keying (4)", LIQUID_MODEM_PSK4, 2}, {"psk8", "phase-shift keying (8)", LIQUID_MODEM_PSK8, 3}, {"psk16", "phase-shift keying (16)", LIQUID_MODEM_PSK16, 4}, {"psk32", "phase-shift keying (32)", LIQUID_MODEM_PSK32, 5}, {"psk64", "phase-shift keying (64)", LIQUID_MODEM_PSK64, 6}, {"psk128", "phase-shift keying (128)", LIQUID_MODEM_PSK128, 7}, {"psk256", "phase-shift keying (256)", LIQUID_MODEM_PSK256, 8}, // differential phase-shift keying {"dpsk2", "differential phase-shift keying (2)", LIQUID_MODEM_DPSK2, 1}, {"dpsk4", "differential phase-shift keying (4)", LIQUID_MODEM_DPSK4, 2}, {"dpsk8", "differential phase-shift keying (8)", LIQUID_MODEM_DPSK8, 3}, {"dpsk16", "differential phase-shift keying (16)", LIQUID_MODEM_DPSK16, 4}, {"dpsk32", "differential phase-shift keying (32)", LIQUID_MODEM_DPSK32, 5}, {"dpsk64", "differential phase-shift keying (64)", LIQUID_MODEM_DPSK64, 6}, {"dpsk128", "differential phase-shift keying (128)", LIQUID_MODEM_DPSK128, 7}, {"dpsk256", "differential phase-shift keying (256)", LIQUID_MODEM_DPSK256, 8}, // amplitude-shift keying {"ask2", "amplitude-shift keying (2)", LIQUID_MODEM_ASK2, 1}, {"ask4", "amplitude-shift keying (4)", LIQUID_MODEM_ASK4, 2}, {"ask8", "amplitude-shift keying (8)", LIQUID_MODEM_ASK8, 3}, {"ask16", "amplitude-shift keying (16)", LIQUID_MODEM_ASK16, 4}, {"ask32", "amplitude-shift keying (32)", LIQUID_MODEM_ASK32, 5}, {"ask64", "amplitude-shift keying (64)", LIQUID_MODEM_ASK64, 6}, {"ask128", "amplitude-shift keying (128)", LIQUID_MODEM_ASK128, 7}, {"ask256", "amplitude-shift keying (256)", LIQUID_MODEM_ASK256, 8}, // quadrature amplitude-shift keying {"qam4", "quadrature amplitude-shift keying (4)", LIQUID_MODEM_QAM4, 2}, {"qam8", "quadrature amplitude-shift keying (8)", LIQUID_MODEM_QAM8, 3}, {"qam16", "quadrature amplitude-shift keying (16)", LIQUID_MODEM_QAM16, 4}, {"qam32", "quadrature amplitude-shift keying (32)", LIQUID_MODEM_QAM32, 5}, {"qam64", "quadrature amplitude-shift keying (64)", LIQUID_MODEM_QAM64, 6}, {"qam128", "quadrature amplitude-shift keying (128)", LIQUID_MODEM_QAM128, 7}, {"qam256", "quadrature amplitude-shift keying (256)", LIQUID_MODEM_QAM256, 8}, // amplitude/phase-shift keying {"apsk4", "amplitude/phase-shift keying (4)", LIQUID_MODEM_APSK4, 2}, {"apsk8", "amplitude/phase-shift keying (8)", LIQUID_MODEM_APSK8, 3}, {"apsk16", "amplitude/phase-shift keying (16)", LIQUID_MODEM_APSK16, 4}, {"apsk32", "amplitude/phase-shift keying (32)", LIQUID_MODEM_APSK32, 5}, {"apsk64", "amplitude/phase-shift keying (64)", LIQUID_MODEM_APSK64, 6}, {"apsk128", "amplitude/phase-shift keying (128)", LIQUID_MODEM_APSK128, 7}, {"apsk256", "amplitude/phase-shift keying (256)", LIQUID_MODEM_APSK256, 8}, // specific modem types {"bpsk", "binary phase-shift keying", LIQUID_MODEM_BPSK, 1}, {"qpsk", "quaternary phase-shift keying", LIQUID_MODEM_QPSK, 2}, {"ook", "ook (on/off keying)", LIQUID_MODEM_OOK, 1}, {"sqam32", "'square' 32-QAM", LIQUID_MODEM_SQAM32, 5}, {"sqam128", "'square' 128-QAM", LIQUID_MODEM_SQAM128, 7}, {"V29", "V.29", LIQUID_MODEM_V29, 4}, {"arb16opt", "arb16opt (optimal 16-qam)", LIQUID_MODEM_ARB16OPT, 4}, {"arb32opt", "arb32opt (optimal 32-qam)", LIQUID_MODEM_ARB32OPT, 5}, {"arb64opt", "arb64opt (optimal 64-qam)", LIQUID_MODEM_ARB64OPT, 6}, {"arb128opt", "arb128opt (optimal 128-qam)", LIQUID_MODEM_ARB128OPT, 7}, {"arb256opt", "arb256opt (optimal 256-qam)", LIQUID_MODEM_ARB256OPT, 8}, {"arb64vt", "arb64vt (64-qam vt logo)", LIQUID_MODEM_ARB64VT, 6}, {"pi4dqpsk", "pi/4 differential QPSK", LIQUID_MODEM_PI4DQPSK, 2}, // arbitrary modem type {"arb", "arbitrary constellation", LIQUID_MODEM_ARB, 0}, }; modulation_scheme liquid_getopt_str2mod(const char * _str) { // compare each string to short name unsigned int i; for (i=0; i 48 && i != LIQUID_MODEM_NUM_SCHEMES-1) { len = 10; printf("\n "); } } printf("\n"); return LIQUID_OK; } // query basic modulation types int liquid_modem_is_psk(modulation_scheme _ms) { switch (_ms) { // Phase-shift keying (PSK) case LIQUID_MODEM_PSK2: case LIQUID_MODEM_PSK4: case LIQUID_MODEM_PSK8: case LIQUID_MODEM_PSK16: case LIQUID_MODEM_PSK32: case LIQUID_MODEM_PSK64: case LIQUID_MODEM_PSK128: case LIQUID_MODEM_PSK256: return 1; default: return 0; } return 0; } int liquid_modem_is_dpsk(modulation_scheme _ms) { switch (_ms) { // Differential phase-shift keying (DPSK) case LIQUID_MODEM_DPSK2: case LIQUID_MODEM_DPSK4: case LIQUID_MODEM_DPSK8: case LIQUID_MODEM_DPSK16: case LIQUID_MODEM_DPSK32: case LIQUID_MODEM_DPSK64: case LIQUID_MODEM_DPSK128: case LIQUID_MODEM_DPSK256: return 1; default: return 0; } return 0; } int liquid_modem_is_ask(modulation_scheme _ms) { switch (_ms) { // amplitude-shift keying (ASK) case LIQUID_MODEM_ASK2: case LIQUID_MODEM_ASK4: case LIQUID_MODEM_ASK8: case LIQUID_MODEM_ASK16: case LIQUID_MODEM_ASK32: case LIQUID_MODEM_ASK64: case LIQUID_MODEM_ASK128: case LIQUID_MODEM_ASK256: return 1; default: return 0; } return 0; } int liquid_modem_is_qam(modulation_scheme _ms) { switch (_ms) { // rectangular quadrature amplitude-shift keying (QAM) case LIQUID_MODEM_QAM4: case LIQUID_MODEM_QAM8: case LIQUID_MODEM_QAM16: case LIQUID_MODEM_QAM32: case LIQUID_MODEM_QAM64: case LIQUID_MODEM_QAM128: case LIQUID_MODEM_QAM256: return 1; default: return 0; } return 0; } int liquid_modem_is_apsk(modulation_scheme _ms) { switch (_ms) { // amplitude phase-shift keying (APSK) case LIQUID_MODEM_APSK4: case LIQUID_MODEM_APSK8: case LIQUID_MODEM_APSK16: case LIQUID_MODEM_APSK32: case LIQUID_MODEM_APSK64: case LIQUID_MODEM_APSK128: case LIQUID_MODEM_APSK256: return 1; default: return 0; } return 0; } // gray encoding unsigned int gray_encode(unsigned int symbol_in) { return symbol_in ^ (symbol_in >> 1); } // gray decoding unsigned int gray_decode(unsigned int symbol_in) { unsigned int mask = symbol_in; unsigned int symbol_out = symbol_in; unsigned int i; // Run loop in blocks of 4 to reduce number of comparisons. Running // loop more times than MAX_MOD_BITS_PER_SYMBOL will not result in // decoding errors. for (i=0; i> 1); symbol_out ^= (mask >> 2); symbol_out ^= (mask >> 3); symbol_out ^= (mask >> 4); mask >>= 4; } return symbol_out; } // pack soft bits into symbol // _soft_bits : soft input bits [size: _bps x 1] // _bps : bits per symbol // _sym_out : output symbol, value in [0,2^_bps) int liquid_pack_soft_bits(unsigned char * _soft_bits, unsigned int _bps, unsigned int * _sym_out) { // validate input if (_bps > MAX_MOD_BITS_PER_SYMBOL) return liquid_error(LIQUID_EIRANGE,"liquid_unpack_soft_bits(), bits/symbol exceeds maximum (%u)", MAX_MOD_BITS_PER_SYMBOL); unsigned int i; unsigned int s=0; for (i=0; i<_bps; i++) { s <<= 1; s |= _soft_bits[i] > LIQUID_SOFTBIT_ERASURE ? 1 : 0; } *_sym_out = s; return LIQUID_OK; } // unpack soft bits into symbol // _sym_in : input symbol, value in [0,2^_bps) // _bps : bits per symbol // _soft_bits : soft output bits [size: _bps x 1] int liquid_unpack_soft_bits(unsigned int _sym_in, unsigned int _bps, unsigned char * _soft_bits) { // validate input if (_bps > MAX_MOD_BITS_PER_SYMBOL) return liquid_error(LIQUID_EIRANGE,"liquid_unpack_soft_bits(), bits/symbol exceeds maximum (%u)", MAX_MOD_BITS_PER_SYMBOL); unsigned int i; for (i=0; i<_bps; i++) _soft_bits[i] = ((_sym_in >> (_bps-i-1)) & 0x0001) ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0; return LIQUID_OK; } liquid-dsp-1.7.0/src/modem/src/modemcf.c000066400000000000000000000047711474751757600200670ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // linear modem API, floating-point (single precision) #include #include #include "liquid.internal.h" // Macro definitions #define CPFSKDEM(name) LIQUID_CONCAT(cpfskdem,name) #define CPFSKMOD(name) LIQUID_CONCAT(cpfskmod,name) #define MODEM(name) LIQUID_CONCAT(modemcf,name) #define FREQMOD(name) LIQUID_CONCAT(freqmod,name) #define FREQDEM(name) LIQUID_CONCAT(freqdem,name) #define T float /* primitive type */ #define TC float complex /* primitive type (complex) */ #define PRINTVAL_T(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) // naming extension (useful for print statements) #define EXTENSION "cf" // common source must come first (object definition) #include "modem_common.proto.c" // generic modem specifications #include "modem_psk.proto.c" #include "modem_dpsk.proto.c" #include "modem_ask.proto.c" #include "modem_qam.proto.c" #include "modem_apsk.proto.c" // specific modems #include "modem_bpsk.proto.c" #include "modem_qpsk.proto.c" #include "modem_ook.proto.c" #include "modem_pi4dqpsk.proto.c" #include "modem_sqam32.proto.c" #include "modem_sqam128.proto.c" // arbitrary modems #include "modem_arb.proto.c" // non-linear modems #include "cpfskdem.proto.c" #include "cpfskmod.proto.c" // analog modems #include "freqmod.proto.c" #include "freqdem.proto.c" liquid-dsp-1.7.0/src/modem/tests/000077500000000000000000000000001474751757600166535ustar00rootroot00000000000000liquid-dsp-1.7.0/src/modem/tests/ampmodem_autotest.c000066400000000000000000000124321474751757600225500ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2019 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small void ampmodem_test_harness(float _mod_index, liquid_ampmodem_type _type, int _suppressed_carrier, float _dphi, float _phi) { // options float SNRdB = 40.0f; // signal-to-noise ratio (set very high for testing) int debug = 0; // enable debugging const char * filename_debug = "ampmodem_autotest_debug.dat"; // derived values float nstd = powf(10.0f,-SNRdB/20.0f); // create mod/demod objects ampmodem mod = ampmodem_create(_mod_index, _type, _suppressed_carrier); ampmodem demod = ampmodem_create(_mod_index, _type, _suppressed_carrier); if (liquid_autotest_verbose) ampmodem_print(mod); // compute end-to-end delay unsigned int delay = ampmodem_get_delay_mod(mod) + ampmodem_get_delay_demod(demod); wdelayf message_delay = wdelayf_create(delay); // run trials unsigned int i=0; unsigned int skip = 2400; // wait for PLL and filters to settle unsigned int num_samples_compare = 0; // number of samples compared float rmse_0 = 0, rmse_1 = 0; // RMS error in phase and 180 out of phase float f0 = 1.0f / sqrtf(1031.0f), f1 = 1.0f / sqrtf(1723.0f); FILE * fid = debug ? fopen(filename_debug,"w") : NULL; if (debug) { fprintf(fid,"# %12s %12s %12s %12s %12s %12s\n", "msg in", "x (real)", "x (imag)", "y (real)", "y (imag)", "msg out"); } while (num_samples_compare < 8000) { // generate original message signal float msg_in = 0.6f*cos(2*M_PI*f0*i) + 0.4f*cos(2*M_PI*f1*i); wdelayf_push(message_delay, msg_in); // modulate float complex x; ampmodem_modulate(mod, msg_in, &x); // add channel impairments float complex y = x*cexpf(_Complex_I*_phi) + nstd*(randnf() + _Complex_I*randnf())*M_SQRT1_2; // update phase _phi += _dphi; while (_phi > M_PI) _phi -= 2*M_PI; while (_phi < -M_PI) _phi += 2*M_PI; // demodulate signal float msg_out; ampmodem_demodulate(demod, y, &msg_out); // compute error wdelayf_read(message_delay, &msg_in); if (debug) { fprintf(fid," %12.4e %12.4e %12.4e %12.4e %12.4e %12.4e\n", msg_in, crealf(x), cimagf(x), crealf(y), cimagf(y), msg_out); } if (i >= skip) { float e0 = msg_in - msg_out; float e1 = msg_in + msg_out; rmse_0 += e0*e0; rmse_1 += e1*e1; num_samples_compare++; } i++; } if (debug) fclose(fid); // destroy objects ampmodem_destroy(mod); ampmodem_destroy(demod); wdelayf_destroy (message_delay); // finally, check if test passed based on modulation type; for // double side-band suppressed carrier, we can have a 180 degree phase offset rmse_0 = 10*log10f( rmse_0 / (float)num_samples_compare ); // in-phase rmse_1 = 10*log10f( rmse_1 / (float)num_samples_compare ); // 180-degree out of phase float rmse = (_type == LIQUID_AMPMODEM_DSB && _suppressed_carrier ) ? (rmse_0 < rmse_1 ? rmse_0 : rmse_1) : rmse_0; if (liquid_autotest_verbose) printf("rms error : %.3f (in-phase: %.3f, 180 phase: %.3f) dB\n", rmse, rmse_0, rmse_1); CONTEND_LESS_THAN( rmse, -18.0f ); } // AUTOTESTS: basic properties: M=2^m, k = 2*M, bandwidth = 0.25 void autotest_ampmodem_dsb_carrier_on () { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_DSB,0,0.02,0.0); } void autotest_ampmodem_usb_carrier_on () { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_USB,0,0.02,0.0); } void autotest_ampmodem_lsb_carrier_on () { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_LSB,0,0.02,0.0); } void autotest_ampmodem_dsb_carrier_off() { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_DSB,1,0.02,0.0); } void autotest_ampmodem_usb_carrier_off() { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_USB,1,0.00,0.0); } void autotest_ampmodem_lsb_carrier_off() { ampmodem_test_harness(0.8f,LIQUID_AMPMODEM_LSB,1,0.00,0.0); } liquid-dsp-1.7.0/src/modem/tests/cpfskmodem_autotest.c000066400000000000000000000262011474751757600231000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small void cpfskmodem_test_mod_demod(cpfskmod mod, cpfskdem dem) { // derived values unsigned int delay = cpfskmod_get_delay(mod) + cpfskdem_get_delay(dem); unsigned int k = cpfskmod_get_samples_per_symbol(mod); unsigned int bps = cpfskmod_get_bits_per_symbol(mod); unsigned int num_symbols = 180 + delay; // number of symbols to test float complex buf[k]; // sample buffer unsigned int sym_in [num_symbols]; // symbol buffer unsigned int sym_out[num_symbols]; // symbol buffer // modulate, demodulate, count errors msequence ms = msequence_create_default(7); unsigned int i; for (i=0; i= delay) { // print results if (liquid_autotest_verbose) { printf(" %3u : input = %2u, output = %2u %s\n", i, sym_in[i-delay], sym_out[i], (sym_in[i-delay] == sym_out[i]) ? "" : "*"); } // check result CONTEND_EQUALITY(sym_in[i-delay], sym_out[i]); } } } // Help function to keep code base small void cpfskmodem_test_harness(unsigned int _bps, float _h, unsigned int _k, unsigned int _m, float _beta, int _filter_type) { // create modulator/demodulator pair cpfskmod mod = cpfskmod_create(_bps, _h, _k, _m, _beta, _filter_type); cpfskdem dem = cpfskdem_create(_bps, _h, _k, _m, _beta, _filter_type); // ensure values match CONTEND_EQUALITY( cpfskmod_get_samples_per_symbol(mod), _k ); CONTEND_EQUALITY( cpfskdem_get_samples_per_symbol(dem), _k ); // run modulation/demodulation tests cpfskmodem_test_mod_demod(mod, dem); // clean it up cpfskmod_destroy(mod); cpfskdem_destroy(dem); } // // AUTOTESTS: check different modulation indices // // square pulse shape void autotest_cpfskmodem_bps1_h0p5000_k4_m3_square() { cpfskmodem_test_harness( 1, 0.5000f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps1_h0p0250_k4_m3_square() { cpfskmodem_test_harness( 1, 0.2500f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps1_h0p1250_k4_m3_square() { cpfskmodem_test_harness( 1, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps1_h0p0625_k4_m3_square() { cpfskmodem_test_harness( 1, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } // raised-cosine pulse shape (full) void autotest_cpfskmodem_bps1_h0p5000_k4_m3_rcosfull() { cpfskmodem_test_harness( 1, 0.5000f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_FULL ); } void autotest_cpfskmodem_bps1_h0p0250_k4_m3_rcosfull() { cpfskmodem_test_harness( 1, 0.2500f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_FULL ); } void autotest_cpfskmodem_bps1_h0p1250_k4_m3_rcosfull() { cpfskmodem_test_harness( 1, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_FULL ); } void autotest_cpfskmodem_bps1_h0p0625_k4_m3_rcosfull() { cpfskmodem_test_harness( 1, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_FULL ); } // raised-cosine pulse shape (partial) void autotest_cpfskmodem_bps1_h0p5000_k4_m3_rcospart() { cpfskmodem_test_harness( 1, 0.5000f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_PARTIAL ); } void autotest_cpfskmodem_bps1_h0p0250_k4_m3_rcospart() { cpfskmodem_test_harness( 1, 0.2500f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_PARTIAL ); } void autotest_cpfskmodem_bps1_h0p1250_k4_m3_rcospart() { cpfskmodem_test_harness( 1, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_PARTIAL ); } void autotest_cpfskmodem_bps1_h0p0625_k4_m3_rcospart() { cpfskmodem_test_harness( 1, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_RCOS_PARTIAL ); } // Gauss minimum-shift keying void autotest_cpfskmodem_bps1_h0p5000_k4_m3_gmsk() { cpfskmodem_test_harness( 1, 0.5000f, 4, 3, 0.25f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p0250_k4_m3_gmsk() { cpfskmodem_test_harness( 1, 0.2500f, 4, 3, 0.25f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p1250_k4_m3_gmsk() { cpfskmodem_test_harness( 1, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p0625_k4_m3_gmsk() { cpfskmodem_test_harness( 1, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_GMSK ); } // // AUTOTESTS: check different bits per symbol // // square pulse shape void autotest_cpfskmodem_bps2_h0p0250_k4_m3_square() { cpfskmodem_test_harness( 2, 0.2500f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps3_h0p1250_k4_m3_square() { cpfskmodem_test_harness( 3, 0.1250f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } void autotest_cpfskmodem_bps4_h0p0625_k4_m3_square() { cpfskmodem_test_harness( 4, 0.0625f, 4, 3, 0.25f, LIQUID_CPFSK_SQUARE ); } // // AUTOTESTS: check different samples per symbol // // GMSK // TODO: allow samples per symbol to be odd void autotest_cpfskmodem_bps1_h0p5_k2_m7_gmsk() { cpfskmodem_test_harness( 1, 0.5f, 2, 7, 0.30f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p5_k4_m7_gmsk() { cpfskmodem_test_harness( 1, 0.5f, 4, 7, 0.30f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p5_k6_m7_gmsk() { cpfskmodem_test_harness( 1, 0.5f, 6, 7, 0.30f, LIQUID_CPFSK_GMSK ); } void autotest_cpfskmodem_bps1_h0p5_k8_m7_gmsk() { cpfskmodem_test_harness( 1, 0.5f, 8, 7, 0.30f, LIQUID_CPFSK_GMSK ); } // test spectral response void autotest_cpfskmodem_spectrum() { // create modulator unsigned int bps = 1; float h = 0.5f; unsigned int k = 4; unsigned int m = 3; float beta = 0.35f; int type = LIQUID_CPFSK_RCOS_PARTIAL; cpfskmod mod = cpfskmod_create(bps, h, k, m, beta, type); // spectral periodogram options unsigned int nfft = 2400; // spectral periodogram FFT size unsigned int num_symbols = 192000; // number of symbols to generate float complex buf[k]; unsigned int i; // modulate many, many symbols for (i=0; i<(1U<<24U); i++) cpfskmod_modulate(mod, 0, buf); // modulate several symbols and run result through spectral estimate spgramcf periodogram = spgramcf_create_default(nfft); for (i=0; i= delay) { #if 0 // print results if (liquid_autotest_verbose) { printf(" %3u : input = %2u, output = %2u %s\n", i, sym_in[i-delay], sym_out[i], (sym_in[i-delay] == sym_out[i]) ? "" : "*"); } #endif // check result CONTEND_EQUALITY(sym_in[i-delay], sym_out[i]); } } // clean it up msequence_destroy(ms); gmskmod_destroy(mod); gmskdem_destroy(dem); } // base configuration void autotest_gmskmodem_k4_m3_b025() { gmskmodem_test_mod_demod( 4, 3, 0.25f); } // test different samples/symbol void autotest_gmskmodem_k2_m3_b025() { gmskmodem_test_mod_demod( 2, 3, 0.25f); } void autotest_gmskmodem_k3_m3_b025() { gmskmodem_test_mod_demod( 3, 3, 0.25f); } void autotest_gmskmodem_k5_m3_b025() { gmskmodem_test_mod_demod( 5, 3, 0.25f); } void autotest_gmskmodem_k8_m3_b033() { gmskmodem_test_mod_demod( 8, 3, 0.25f); } // test different filter semi-lengths void autotest_gmskmodem_k4_m1_b025() { gmskmodem_test_mod_demod( 4, 1, 0.25f); } void autotest_gmskmodem_k4_m2_b025() { gmskmodem_test_mod_demod( 4, 2, 0.25f); } void autotest_gmskmodem_k4_m8_b025() { gmskmodem_test_mod_demod( 4, 8, 0.25f); } // test different filter bandwidth factors void autotest_gmskmodem_k4_m3_b020() { gmskmodem_test_mod_demod( 4, 3, 0.20f); } void autotest_gmskmodem_k4_m3_b033() { gmskmodem_test_mod_demod( 4, 3, 0.25f); } void autotest_gmskmodem_k4_m3_b050() { gmskmodem_test_mod_demod( 4, 3, 0.25f); } // test modulator copy void autotest_gmskmod_copy() { // options unsigned int k = 5; unsigned int m = 3; float bt = 0.2345f; // create modulator/demodulator pair gmskmod mod_orig = gmskmod_create(k, m, bt); unsigned int num_symbols = 16; float complex buf_orig[k]; float complex buf_copy[k]; msequence ms = msequence_create_default(7); // run original object unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.internal.h" // Helper function to keep code base small void modemcf_test_copy(modulation_scheme _ms) { // create modem and randomize internal state modemcf modem_0 = modemcf_create(_ms); unsigned int i, s0, s1, M = 1 << modemcf_get_bps(modem_0); float complex x0, x1; for (i=0; i<10; i++) { // modulate random symbol modemcf_modulate(modem_0, rand() % M, &x0); // demodulate random sample modemcf_demodulate(modem_0, randnf() + _Complex_I*randnf(), &s0); } // copy modem modemcf modem_1 = modemcf_copy(modem_0); if (liquid_autotest_verbose) { printf("input: %20s, 0: %20s, 1:%20s\n", modulation_types[_ms ].name, modulation_types[modemcf_get_scheme(modem_0)].name, modulation_types[modemcf_get_scheme(modem_1)].name); } // ... for (i=0; i<10; i++) { // modulate random symbol unsigned int s = rand() % M; modemcf_modulate(modem_0, s, &x0); modemcf_modulate(modem_1, s, &x1); CONTEND_EQUALITY(x0, x1); // demodulate random sample float complex x = randnf() + _Complex_I*randnf(); modemcf_demodulate(modem_0, x, &s0); modemcf_demodulate(modem_1, x, &s1); CONTEND_EQUALITY(s0, s1) } // clean it up modemcf_destroy(modem_0); modemcf_destroy(modem_1); } // AUTOTESTS: generic PSK void autotest_modem_copy_psk2() { modemcf_test_copy(LIQUID_MODEM_PSK2); } void autotest_modem_copy_psk4() { modemcf_test_copy(LIQUID_MODEM_PSK4); } void autotest_modem_copy_psk8() { modemcf_test_copy(LIQUID_MODEM_PSK8); } void autotest_modem_copy_psk16() { modemcf_test_copy(LIQUID_MODEM_PSK16); } void autotest_modem_copy_psk32() { modemcf_test_copy(LIQUID_MODEM_PSK32); } void autotest_modem_copy_psk64() { modemcf_test_copy(LIQUID_MODEM_PSK64); } void autotest_modem_copy_psk128() { modemcf_test_copy(LIQUID_MODEM_PSK128); } void autotest_modem_copy_psk256() { modemcf_test_copy(LIQUID_MODEM_PSK256); } // AUTOTESTS: generic DPSK void autotest_modem_copy_dpsk2() { modemcf_test_copy(LIQUID_MODEM_DPSK2); } void autotest_modem_copy_dpsk4() { modemcf_test_copy(LIQUID_MODEM_DPSK4); } void autotest_modem_copy_dpsk8() { modemcf_test_copy(LIQUID_MODEM_DPSK8); } void autotest_modem_copy_dpsk16() { modemcf_test_copy(LIQUID_MODEM_DPSK16); } void autotest_modem_copy_dpsk32() { modemcf_test_copy(LIQUID_MODEM_DPSK32); } void autotest_modem_copy_dpsk64() { modemcf_test_copy(LIQUID_MODEM_DPSK64); } void autotest_modem_copy_dpsk128() { modemcf_test_copy(LIQUID_MODEM_DPSK128); } void autotest_modem_copy_dpsk256() { modemcf_test_copy(LIQUID_MODEM_DPSK256); } // AUTOTESTS: generic ASK void autotest_modem_copy_ask2() { modemcf_test_copy(LIQUID_MODEM_ASK2); } void autotest_modem_copy_ask4() { modemcf_test_copy(LIQUID_MODEM_ASK4); } void autotest_modem_copy_ask8() { modemcf_test_copy(LIQUID_MODEM_ASK8); } void autotest_modem_copy_ask16() { modemcf_test_copy(LIQUID_MODEM_ASK16); } void autotest_modem_copy_ask32() { modemcf_test_copy(LIQUID_MODEM_ASK32); } void autotest_modem_copy_ask64() { modemcf_test_copy(LIQUID_MODEM_ASK64); } void autotest_modem_copy_ask128() { modemcf_test_copy(LIQUID_MODEM_ASK128); } void autotest_modem_copy_ask256() { modemcf_test_copy(LIQUID_MODEM_ASK256); } // AUTOTESTS: generic QAM void autotest_modem_copy_qam4() { modemcf_test_copy(LIQUID_MODEM_QAM4); } void autotest_modem_copy_qam8() { modemcf_test_copy(LIQUID_MODEM_QAM8); } void autotest_modem_copy_qam16() { modemcf_test_copy(LIQUID_MODEM_QAM16); } void autotest_modem_copy_qam32() { modemcf_test_copy(LIQUID_MODEM_QAM32); } void autotest_modem_copy_qam64() { modemcf_test_copy(LIQUID_MODEM_QAM64); } void autotest_modem_copy_qam128() { modemcf_test_copy(LIQUID_MODEM_QAM128); } void autotest_modem_copy_qam256() { modemcf_test_copy(LIQUID_MODEM_QAM256); } // AUTOTESTS: generic APSK (maps to specific APSK modems internally) void autotest_modem_copy_apsk4() { modemcf_test_copy(LIQUID_MODEM_APSK4); } void autotest_modem_copy_apsk8() { modemcf_test_copy(LIQUID_MODEM_APSK8); } void autotest_modem_copy_apsk16() { modemcf_test_copy(LIQUID_MODEM_APSK16); } void autotest_modem_copy_apsk32() { modemcf_test_copy(LIQUID_MODEM_APSK32); } void autotest_modem_copy_apsk64() { modemcf_test_copy(LIQUID_MODEM_APSK64); } void autotest_modem_copy_apsk128() { modemcf_test_copy(LIQUID_MODEM_APSK128); } void autotest_modem_copy_apsk256() { modemcf_test_copy(LIQUID_MODEM_APSK256); } // AUTOTESTS: Specific modems void autotest_modem_copy_bpsk() { modemcf_test_copy(LIQUID_MODEM_BPSK); } void autotest_modem_copy_qpsk() { modemcf_test_copy(LIQUID_MODEM_QPSK); } void autotest_modem_copy_ook() { modemcf_test_copy(LIQUID_MODEM_OOK); } void autotest_modem_copy_sqam32() { modemcf_test_copy(LIQUID_MODEM_SQAM32); } void autotest_modem_copy_sqam128() { modemcf_test_copy(LIQUID_MODEM_SQAM128); } void autotest_modem_copy_V29() { modemcf_test_copy(LIQUID_MODEM_V29); } void autotest_modem_copy_arb16opt() { modemcf_test_copy(LIQUID_MODEM_ARB16OPT); } void autotest_modem_copy_arb32opt() { modemcf_test_copy(LIQUID_MODEM_ARB32OPT); } void autotest_modem_copy_arb64opt() { modemcf_test_copy(LIQUID_MODEM_ARB64OPT); } void autotest_modem_copy_arb128opt() { modemcf_test_copy(LIQUID_MODEM_ARB128OPT); } void autotest_modem_copy_arb256opt() { modemcf_test_copy(LIQUID_MODEM_ARB256OPT); } void autotest_modem_copy_arb64vt() { modemcf_test_copy(LIQUID_MODEM_ARB64VT); } void autotest_modem_copy_pi4dqpsk() { modemcf_test_copy(LIQUID_MODEM_PI4DQPSK); } // test errors and invalid configuration void autotest_modem_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping modem config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // test copying/creating invalid objects CONTEND_ISNULL( modemcf_copy(NULL) ); CONTEND_ISNULL( modemcf_create(LIQUID_MODEM_ARB) ); CONTEND_ISNULL( modemcf_create(-1) ); // create object and check configuration modemcf q = modemcf_create(LIQUID_MODEM_QAM64); CONTEND_EQUALITY( LIQUID_OK, modemcf_print(q) ); // internal: try to initialize using invalid configuration CONTEND_INEQUALITY( LIQUID_OK, modemcf_init(q,0) ); CONTEND_INEQUALITY( LIQUID_OK, modemcf_init(q,77) ); // internal: try to modulate using invalid inputs float complex sym; CONTEND_INEQUALITY( LIQUID_OK, modemcf_modulate (q,8193,&sym) ); CONTEND_INEQUALITY( LIQUID_OK, modemcf_modulate_map(q,8193,&sym) ); CONTEND_INEQUALITY( LIQUID_OK, modemcf_demodsoft_gentab(q,227) ); modemcf_destroy(q); } liquid-dsp-1.7.0/src/modem/tests/modem_demodsoft_autotest.c000066400000000000000000000155041474751757600241210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // soft demodulation tests // #include "autotest/autotest.h" #include "liquid.h" // Help function to keep code base small void modemcf_test_demodsoft(modulation_scheme _ms) { // generate mod/demod modemcf mod = modemcf_create(_ms); modemcf demod = modemcf_create(_ms); // unsigned int bps = modemcf_get_bps(demod); // run the test unsigned int i, s, M=1< #include "autotest/autotest.h" #include "liquid.h" // Helper function to keep code base small void modemcf_test_demodstats(modulation_scheme _ms) { // generate mod/demod modemcf mod = modemcf_create(_ms); modemcf demod = modemcf_create(_ms); // run the test unsigned int i, s, M = 1 << modemcf_get_bps(mod); float complex x; float complex x_hat; // rotated symbol float demodstats; float phi = 0.01f; for (i=0; i 0.0f); } // repeat with negative phase error for (i=0; i #include "liquid.h" #define FIRPFBCH2_EXECUTE_BENCH_API(NUM_CHANNELS,M,TYPE) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firpfbch2_crcf_execute_bench(_start, _finish, _num_iterations, NUM_CHANNELS, M, TYPE); } // Helper function to keep code base small void firpfbch2_crcf_execute_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _num_channels, unsigned int _m, int _type) { // initialize channelizer float As = 60.0f; firpfbch2_crcf q = firpfbch2_crcf_create_kaiser(_type,_num_channels,_m,As); unsigned long int i; float complex x[_num_channels]; float complex y[_num_channels]; for (i=0; i<_num_channels; i++) x[i] = 1.0f + _Complex_I*1.0f; // scale number of iterations to keep execution time // relatively linear *_num_iterations /= _num_channels; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { firpfbch2_crcf_execute(q, x, y); firpfbch2_crcf_execute(q, x, y); firpfbch2_crcf_execute(q, x, y); firpfbch2_crcf_execute(q, x, y); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firpfbch2_crcf_destroy(q); } // analysis void benchmark_firpfbch2_crcf_a4 FIRPFBCH2_EXECUTE_BENCH_API(4, 2, LIQUID_ANALYZER) void benchmark_firpfbch2_crcf_a16 FIRPFBCH2_EXECUTE_BENCH_API(16, 2, LIQUID_ANALYZER) void benchmark_firpfbch2_crcf_a64 FIRPFBCH2_EXECUTE_BENCH_API(64, 2, LIQUID_ANALYZER) void benchmark_firpfbch2_crcf_a256 FIRPFBCH2_EXECUTE_BENCH_API(256, 2, LIQUID_ANALYZER) void benchmark_firpfbch2_crcf_a512 FIRPFBCH2_EXECUTE_BENCH_API(512, 2, LIQUID_ANALYZER) void benchmark_firpfbch2_crcf_a1024 FIRPFBCH2_EXECUTE_BENCH_API(1024, 2, LIQUID_ANALYZER) // synthesis void benchmark_firpfbch2_crcf_s4 FIRPFBCH2_EXECUTE_BENCH_API(4, 2, LIQUID_SYNTHESIZER) void benchmark_firpfbch2_crcf_s16 FIRPFBCH2_EXECUTE_BENCH_API(16, 2, LIQUID_SYNTHESIZER) void benchmark_firpfbch2_crcf_s64 FIRPFBCH2_EXECUTE_BENCH_API(64, 2, LIQUID_SYNTHESIZER) void benchmark_firpfbch2_crcf_s256 FIRPFBCH2_EXECUTE_BENCH_API(256, 2, LIQUID_SYNTHESIZER) void benchmark_firpfbch2_crcf_s512 FIRPFBCH2_EXECUTE_BENCH_API(512, 2, LIQUID_SYNTHESIZER) void benchmark_firpfbch2_crcf_s1024 FIRPFBCH2_EXECUTE_BENCH_API(1024, 2, LIQUID_SYNTHESIZER) liquid-dsp-1.7.0/src/multichannel/bench/firpfbch_crcf_benchmark.c000066400000000000000000000066141474751757600251170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" #define FIRPFBCH_EXECUTE_BENCH_API(NUM_CHANNELS,M,TYPE) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { firpfbch_crcf_execute_bench(_start, _finish, _num_iterations, NUM_CHANNELS, M, TYPE); } // Helper function to keep code base small void firpfbch_crcf_execute_bench( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _num_channels, unsigned int _m, int _type) { // initialize channelizer float As = 60.0f; firpfbch_crcf c = firpfbch_crcf_create_kaiser(_type,_num_channels,_m,As); unsigned long int i; float complex x[_num_channels]; float complex y[_num_channels]; for (i=0; i<_num_channels; i++) x[i] = 1.0f + _Complex_I*1.0f; // scale number of iterations to keep execution time // relatively linear *_num_iterations /= _num_channels; // start trials getrusage(RUSAGE_SELF, _start); if (_type == LIQUID_SYNTHESIZER) { for (i=0; i<(*_num_iterations); i++) { firpfbch_crcf_synthesizer_execute(c,x,y); firpfbch_crcf_synthesizer_execute(c,x,y); firpfbch_crcf_synthesizer_execute(c,x,y); firpfbch_crcf_synthesizer_execute(c,x,y); } } else { for (i=0; i<(*_num_iterations); i++) { firpfbch_crcf_analyzer_execute(c,x,y); firpfbch_crcf_analyzer_execute(c,x,y); firpfbch_crcf_analyzer_execute(c,x,y); firpfbch_crcf_analyzer_execute(c,x,y); } } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; firpfbch_crcf_destroy(c); } // void benchmark_firpfbch_crcf_a4 FIRPFBCH_EXECUTE_BENCH_API(4, 2, LIQUID_ANALYZER) void benchmark_firpfbch_crcf_a16 FIRPFBCH_EXECUTE_BENCH_API(16, 2, LIQUID_ANALYZER) void benchmark_firpfbch_crcf_a64 FIRPFBCH_EXECUTE_BENCH_API(64, 2, LIQUID_ANALYZER) void benchmark_firpfbch_crcf_a256 FIRPFBCH_EXECUTE_BENCH_API(256, 2, LIQUID_ANALYZER) void benchmark_firpfbch_crcf_a512 FIRPFBCH_EXECUTE_BENCH_API(512, 2, LIQUID_ANALYZER) void benchmark_firpfbch_crcf_a1024 FIRPFBCH_EXECUTE_BENCH_API(1024, 2, LIQUID_ANALYZER) liquid-dsp-1.7.0/src/multichannel/bench/firpfbchr_crcf_benchmark.c000066400000000000000000000067171474751757600253050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" #define FIRPFBCHR_EXECUTE_BENCH_API(M,P,m) \ ( struct rusage * _start, \ struct rusage * _finish, \ unsigned long int * _num_iterations) \ { firpfbchr_crcf_execute_bench(_start, _finish, _num_iterations, M, P, m); } // Helper function to keep code base small void firpfbchr_crcf_execute_bench(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations, unsigned int _M, unsigned int _P, unsigned int _m) { // scale trials appropriately *_num_iterations = *_num_iterations * 4 / _M; if (*_num_iterations < 1) *_num_iterations = 1; // initialize channelizer float As = 60.0f; firpfbchr_crcf q = firpfbchr_crcf_create_kaiser(_M,_P,_m,As); unsigned long int i; float complex x[_P]; float complex y[_M]; for (i=0; i<_P; i++) x[i] = randnf() + _Complex_I*randnf(); // scale number of iterations to keep execution time // relatively linear unsigned long int n = (*_num_iterations * 20) / _M; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i #include #include #include #include #include #include "liquid.h" #define OFDMFRAMESYNC_ACQUIRE_BENCH_API(M,CP_LEN) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { ofdmframesync_acquire_bench(_start, _finish, _num_iterations, M, CP_LEN); } // Helper function to keep code base small void ofdmframesync_acquire_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _num_subcarriers, unsigned int _cp_len) { // options unsigned int M = _num_subcarriers; unsigned int cp_len = _cp_len; unsigned int taper_len = 0; // derived values unsigned int num_samples = 3*(M + cp_len); // create synthesizer/analyzer objects ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, NULL); //ofdmframegen_print(fg); ofdmframesync fs = ofdmframesync_create(M,cp_len,taper_len,NULL,NULL,NULL); unsigned int i; float complex y[num_samples]; // frame samples // assemble full frame unsigned int n=0; // write first S0 symbol ofdmframegen_write_S0a(fg, &y[n]); n += M + cp_len; // write second S0 symbol ofdmframegen_write_S0b(fg, &y[n]); n += M + cp_len; // write S1 symbol ofdmframegen_write_S1( fg, &y[n]); n += M + cp_len; assert(n == num_samples); // add noise for (i=0; i #include #include #include #include #include #include "liquid.h" #define OFDMFRAMESYNC_RXSYMBOL_BENCH_API(M,CP_LEN) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { ofdmframesync_rxsymbol_bench(_start, _finish, _num_iterations, M, CP_LEN); } // Helper function to keep code base small void ofdmframesync_rxsymbol_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _num_subcarriers, unsigned int _cp_len) { // options modulation_scheme ms = LIQUID_MODEM_QPSK; unsigned int M = _num_subcarriers; unsigned int cp_len = _cp_len; unsigned int taper_len = 0; // create synthesizer/analyzer objects ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, NULL); //ofdmframegen_print(fg); modemcf mod = modemcf_create(ms); ofdmframesync fs = ofdmframesync_create(M,cp_len,taper_len,NULL,NULL,NULL); unsigned int i; float complex X[M]; // channelized symbol float complex x[M+cp_len]; // time-domain symbol // synchronize short sequence (first) ofdmframegen_write_S0a(fg, x); ofdmframesync_execute(fs, x, M+cp_len); // synchronize short sequence (second) ofdmframegen_write_S0b(fg, x); ofdmframesync_execute(fs, x, M+cp_len); // synchronize long sequence ofdmframegen_write_S1(fg, x); ofdmframesync_execute(fs, x, M+cp_len); // modulate data symbols (use same symbol, ignore pilot phase) unsigned int s; for (i=0; i #include #include #include #include "liquid.internal.h" // firpfbch object structure definition struct FIRPFBCH(_s) { int type; // synthesis/analysis unsigned int num_channels; // number of channels unsigned int p; // filter length (symbols) // filter unsigned int h_len; // filter length TC * h; // filter coefficients // create separate bank of dotprod and window objects DOTPROD() * dp; // dot product object array WINDOW() * w; // window buffer object array unsigned int filter_index; // running filter index (analysis) // fft plan FFT_PLAN fft; // fft|ifft object TO * x; // fft|ifft transform input array TO * X; // fft|ifft transform output array }; // // forward declaration of internal methods // int FIRPFBCH(_analyzer_push)(FIRPFBCH() _q, TI _x); int FIRPFBCH(_analyzer_run)(FIRPFBCH() _q, unsigned int _k, TO * _X); // create FIR polyphase filterbank channelizer object // _type : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) // _M : number of channels // _p : filter length (symbols) // _h : filter coefficients, [size: _M*_p x 1] FIRPFBCH() FIRPFBCH(_create)(int _type, unsigned int _M, unsigned int _p, TC * _h) { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) return liquid_error_config("firpfbch_%s_create(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create(), number of channels must be greater than 0", EXTENSION_FULL); if (_p == 0) return liquid_error_config("firpfbch_%s_create(), invalid filter size (must be greater than 0)", EXTENSION_FULL); // create main object FIRPFBCH() q = (FIRPFBCH()) malloc(sizeof(struct FIRPFBCH(_s))); // set user-defined properties q->type = _type; q->num_channels = _M; q->p = _p; // derived values q->h_len = q->num_channels * q->p; // create bank of filters q->dp = (DOTPROD()*) malloc((q->num_channels)*sizeof(DOTPROD())); q->w = (WINDOW()*) malloc((q->num_channels)*sizeof(WINDOW())); // copy filter coefficients q->h = (TC*) malloc((q->h_len)*sizeof(TC)); unsigned int i; for (i=0; ih_len; i++) q->h[i] = _h[i]; // generate bank of sub-samped filters unsigned int n; unsigned int h_sub_len = q->p; TC h_sub[h_sub_len]; for (i=0; inum_channels; i++) { // sub-sample prototype filter, loading coefficients in reverse order for (n=0; nh[i + n*(q->num_channels)]; } // create window buffer and dotprod object (coefficients // loaded in reverse order) q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); q->w[i] = WINDOW(_create)(h_sub_len); } // allocate memory for buffers q->x = (T*) FFT_MALLOC((q->num_channels)*sizeof(T)); q->X = (T*) FFT_MALLOC((q->num_channels)*sizeof(T)); // create fft plan if (q->type == LIQUID_ANALYZER) q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_FORWARD, FFT_METHOD); else q->fft = FFT_CREATE_PLAN(q->num_channels, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // reset filterbank object FIRPFBCH(_reset)(q); // return filterbank object return q; } // create FIR polyphase filterbank channelizer object with // prototype filter based on windowed Kaiser design // _type : channelizer type (LIQUID_ANALYZER | LIQUID_SYNTHESIZER) // _M : number of channels // _m : filter delay (symbols) // _as : stop-band attenuation [dB] FIRPFBCH() FIRPFBCH(_create_kaiser)(int _type, unsigned int _M, unsigned int _m, float _as) { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) return liquid_error_config("firpfbch_%s_create_kaiser(), invalid type: %d", EXTENSION_FULL, _type); if (_M == 0) return liquid_error_config("firpfbch_%s_create_kaiser(), number of channels must be greater than 0", EXTENSION_FULL); if (_m == 0) return liquid_error_config("firpfbch_%s_create_kaiser(), invalid filter size (must be greater than 0)", EXTENSION_FULL); _as = fabsf(_as); // design filter unsigned int h_len = 2*_M*_m + 1; float h[h_len]; float fc = 0.5f / (float)_M; // TODO : check this value liquid_firdes_kaiser(h_len, fc, _as, 0.0f, h); // copy coefficients to type-specfic array TC hc[h_len]; unsigned int i; for (i=0; inum_channels; i++) { DOTPROD(_destroy)(_q->dp[i]); WINDOW(_destroy)(_q->w[i]); } free(_q->dp); free(_q->w); // free transform object FFT_DESTROY_PLAN(_q->fft); // free additional arrays free(_q->h); FFT_FREE(_q->x); FFT_FREE(_q->X); // free main object memory free(_q); return LIQUID_OK; } // clear/reset firpfbch object internals int FIRPFBCH(_reset)(FIRPFBCH() _q) { unsigned int i; for (i=0; i<_q->num_channels; i++) { WINDOW(_reset)(_q->w[i]); _q->x[i] = 0; _q->X[i] = 0; } _q->filter_index = _q->num_channels-1; return LIQUID_OK; } // print firpfbch object int FIRPFBCH(_print)(FIRPFBCH() _q) { printf("\n", _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", _q->num_channels, _q->p); return LIQUID_OK; } // // SYNTHESIZER // // execute filterbank as synthesizer on block of samples // _q : filterbank channelizer object // _x : channelized input, [size: num_channels x 1] // _y : output time series, [size: num_channels x 1] int FIRPFBCH(_synthesizer_execute)(FIRPFBCH() _q, TI * _x, TO * _y) { unsigned int i; // copy channelized symbols to transform input memmove(_q->X, _x, _q->num_channels*sizeof(TI)); // execute inverse DFT, store result in buffer 'x' FFT_EXECUTE(_q->fft); // push samples into filter bank and execute T * r; // read pointer for (i=0; i<_q->num_channels; i++) { WINDOW(_push)(_q->w[i], _q->x[i]); WINDOW(_read)(_q->w[i], &r); DOTPROD(_execute)(_q->dp[i], r, &_y[i]); // normalize by DFT scaling factor //_y[i] /= (float) (_q->num_channels); } return LIQUID_OK; } // // ANALYZER // // execute filterbank as analyzer on block of samples // _q : filterbank channelizer object // _x : input time series, [size: num_channels x 1] // _y : channelized output, [size: num_channels x 1] int FIRPFBCH(_analyzer_execute)(FIRPFBCH() _q, TI * _x, TO * _y) { unsigned int i; // push samples into buffers for (i=0; i<_q->num_channels; i++) FIRPFBCH(_analyzer_push)(_q, _x[i]); // execute analysis filters on the given input starting // with filterbank at index zero return FIRPFBCH(_analyzer_run)(_q, 0, _y); } // // internal methods // // push single sample into analysis filterbank, updating index // counter appropriately // _q : filterbank channelizer object // _x : input sample int FIRPFBCH(_analyzer_push)(FIRPFBCH() _q, TI _x) { // push sample into filter WINDOW(_push)(_q->w[_q->filter_index], _x); // decrement filter index _q->filter_index = (_q->filter_index + _q->num_channels - 1) % _q->num_channels; return LIQUID_OK; } // run filterbank analyzer dot products, DFT // _q : filterbank channelizer object // _k : filterbank alignment index // _y : output array, [size: num_channels x 1] int FIRPFBCH(_analyzer_run)(FIRPFBCH() _q, unsigned int _k, TO * _y) { unsigned int i; // execute filter outputs, reversing order of output (not // sure why this is necessary) T * r; // read pointer unsigned int index; for (i=0; i<_q->num_channels; i++) { // compute appropriate index index = (i+_k) % _q->num_channels; // read buffer at specified index WINDOW(_read)(_q->w[index], &r); // compute dot product DOTPROD(_execute)(_q->dp[i], r, &_q->X[_q->num_channels-i-1]); } // execute DFT, store result in buffer 'x' FFT_EXECUTE(_q->fft); // move to output array memmove(_y, _q->x, _q->num_channels*sizeof(TO)); return LIQUID_OK; } liquid-dsp-1.7.0/src/multichannel/src/firpfbch2.proto.c000066400000000000000000000315071474751757600230430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // firpfbch2.c // // finite impulse response polyphase filterbank channelizer with output // rate 2 Fs / M // #include #include #include #include #include "liquid.internal.h" // firpfbch2 object structure definition struct FIRPFBCH2(_s) { int type; // synthesis/analysis unsigned int M; // number of channels unsigned int M2; // number of channels/2 unsigned int m; // filter semi-length // filter unsigned int h_len; // prototype filter length: 2*M*m // create separate bank of dotprod and window objects DOTPROD() * dp; // dot product object array // inverse FFT plan FFT_PLAN ifft; // inverse FFT object TO * X; // IFFT input array [size: M x 1] TO * x; // IFFT output array [size: M x 1] // common data structures shared between analysis and // synthesis algorithms WINDOW() * w0; // window buffer object array WINDOW() * w1; // window buffer object array (synthesizer only) int flag; // flag indicating filter/buffer alignment }; // create firpfbch2 object // _type : channelizer type (e.g. LIQUID_ANALYZER) // _M : number of channels (must be even) // _m : prototype filter semi-lenth, length=2*M*m // _h : prototype filter coefficient array // _h_len : number of coefficients FIRPFBCH2() FIRPFBCH2(_create)(int _type, unsigned int _M, unsigned int _m, TC * _h) { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) return liquid_error_config("firpfbch2_%s_create(), invalid type %d", EXTENSION_FULL, _type); if (_M < 2 || _M % 2) return liquid_error_config("firpfbch2_%s_create(), number of channels must be greater than 2 and even", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbch2_%s_create(), filter semi-length must be at least 1", EXTENSION_FULL); // create object FIRPFBCH2() q = (FIRPFBCH2()) malloc(sizeof(struct FIRPFBCH2(_s))); // set input parameters q->type = _type; // channelizer type (e.g. LIQUID_ANALYZER) q->M = _M; // number of channels q->m = _m; // prototype filter semi-length // compute derived values q->h_len = 2*q->M*q->m; // prototype filter length q->M2 = q->M / 2; // number of channels / 2 // generate bank of sub-samped filters q->dp = (DOTPROD()*) malloc((q->M)*sizeof(DOTPROD())); unsigned int i; unsigned int n; unsigned int h_sub_len = 2 * q->m; TC h_sub[h_sub_len]; for (i=0; iM; i++) { // sub-sample prototype filter, loading coefficients // in reverse order for (n=0; nM)]; // create dotprod object q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); } // create FFT plan (inverse transform) q->X = (T*) FFT_MALLOC((q->M)*sizeof(T)); // IFFT input q->x = (T*) FFT_MALLOC((q->M)*sizeof(T)); // IFFT output q->ifft = FFT_CREATE_PLAN(q->M, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // create buffer objects q->w0 = (WINDOW()*) malloc((q->M)*sizeof(WINDOW())); q->w1 = (WINDOW()*) malloc((q->M)*sizeof(WINDOW())); for (i=0; iM; i++) { q->w0[i] = WINDOW(_create)(h_sub_len); q->w1[i] = WINDOW(_create)(h_sub_len); } // reset filterbank object and return FIRPFBCH2(_reset)(q); return q; } // create firpfbch2 object using Kaiser window prototype // _type : channelizer type (e.g. LIQUID_ANALYZER) // _M : number of channels (must be even) // _m : prototype filter semi-lenth, length=2*M*m+1 // _as : filter stop-band attenuation [dB] FIRPFBCH2() FIRPFBCH2(_create_kaiser)(int _type, unsigned int _M, unsigned int _m, float _as) { // validate input if (_type != LIQUID_ANALYZER && _type != LIQUID_SYNTHESIZER) return liquid_error_config("firpfbch2_%s_create_kaiser(), invalid type %d", EXTENSION_FULL, _type); if (_M < 2 || _M % 2) return liquid_error_config("firpfbch2_%s_create_kaiser(), number of channels must be greater than 2 and even", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbch2_%s_create_kaiser(), filter semi-length must be at least 1", EXTENSION_FULL); // design prototype filter unsigned int h_len = 2*_M*_m+1; float * hf = (float*)malloc(h_len*sizeof(float)); // filter cut-off frequency (analyzer has twice the // bandwidth of the synthesizer) float fc = (_type == LIQUID_ANALYZER) ? 1.0f/(float)_M : 0.5f/(float)_M; // compute filter coefficients (floating point precision) liquid_firdes_kaiser(h_len, fc, _as, 0.0f, hf); // normalize to unit average and scale by number of channels float hf_sum = 0.0f; unsigned int i; for (i=0; idp = (DOTPROD()*) malloc((q_copy->M)*sizeof(DOTPROD())); for (i=0; iM; i++) q_copy->dp[i] = DOTPROD(_copy)(q_orig->dp[i]); // create FFT plan (inverse transform) q_copy->X = (T*) FFT_MALLOC((q_copy->M)*sizeof(T)); // IFFT input q_copy->x = (T*) FFT_MALLOC((q_copy->M)*sizeof(T)); // IFFT output q_copy->ifft = FFT_CREATE_PLAN(q_copy->M, q_copy->X, q_copy->x, FFT_DIR_BACKWARD, FFT_METHOD); // create and copy buffer objects q_copy->w0 = (WINDOW()*) malloc((q_copy->M)*sizeof(WINDOW())); q_copy->w1 = (WINDOW()*) malloc((q_copy->M)*sizeof(WINDOW())); for (i=0; iM; i++) { q_copy->w0[i] = WINDOW(_copy)(q_orig->w0[i]); q_copy->w1[i] = WINDOW(_copy)(q_orig->w1[i]); } return q_copy; } // destroy firpfbch2 object, freeing internal memory int FIRPFBCH2(_destroy)(FIRPFBCH2() _q) { unsigned int i; // free dotprod objects for (i=0; i<_q->M; i++) DOTPROD(_destroy)(_q->dp[i]); free(_q->dp); // free transform object and arrays FFT_DESTROY_PLAN(_q->ifft); FFT_FREE(_q->X); FFT_FREE(_q->x); // free window objects (buffers) for (i=0; i<_q->M; i++) { WINDOW(_destroy)(_q->w0[i]); WINDOW(_destroy)(_q->w1[i]); } free(_q->w0); free(_q->w1); // free main object memory free(_q); return LIQUID_OK; } // reset firpfbch2 object internals int FIRPFBCH2(_reset)(FIRPFBCH2() _q) { unsigned int i; // clear window buffers for (i=0; i<_q->M; i++) { WINDOW(_reset)(_q->w0[i]); WINDOW(_reset)(_q->w1[i]); } // reset filter/buffer alignment flag _q->flag = 0; return LIQUID_OK; } // print firpfbch2 object internals int FIRPFBCH2(_print)(FIRPFBCH2() _q) { printf("\n", _q->type == LIQUID_ANALYZER ? "analyzer" : "synthesizer", _q->M, _q->m); return LIQUID_OK; } // get type, either LIQUID_ANALYZER or LIQUID_SYNTHESIZER int FIRPFBCH2(_get_type)(FIRPFBCH2() _q) { return _q->type; } // get number of channels, M unsigned int FIRPFBCH2(_get_M)(FIRPFBCH2() _q) { return _q->M; } // get prototype filter sem-length, m unsigned int FIRPFBCH2(_get_m)(FIRPFBCH2() _q) { return _q->m; } // execute filterbank channelizer (analyzer) // _x : channelizer input, [size: M/2 x 1] // _y : channelizer output, [size: M x 1] int FIRPFBCH2(_execute_analyzer)(FIRPFBCH2() _q, TI * _x, TO * _y) { unsigned int i; // load buffers in blocks of num_channels/2 starting // in the middle of the filter bank and moving in the // negative direction unsigned int base_index = _q->flag ? _q->M : _q->M2; for (i=0; i<_q->M2; i++) { // push sample into buffer at filter index WINDOW(_push)(_q->w0[base_index-i-1], _x[i]); } // execute filter outputs unsigned int offset = _q->flag ? _q->M2 : 0; TI * r; // buffer read pointer for (i=0; i<_q->M; i++) { // read buffer at index WINDOW(_read)(_q->w0[i], &r); // run dot product storing result in IFFT input buffer DOTPROD(_execute)(_q->dp[(offset+i)%_q->M], r, &_q->X[i]); } // execute IFFT, store result in buffer 'x' FFT_EXECUTE(_q->ifft); // scale result by 1/num_channels (C transform) for (i=0; i<_q->M; i++) _y[i] = _q->x[i] / (float)(_q->M); // update flag _q->flag = 1 - _q->flag; return LIQUID_OK; } // execute filterbank channelizer (synthesizer) // _x : channelizer input, [size: M x 1] // _y : channelizer output, [size: M/2 x 1] int FIRPFBCH2(_execute_synthesizer)(FIRPFBCH2() _q, TI * _x, TO * _y) { unsigned int i; // copy input array to internal IFFT input buffer memmove(_q->X, _x, _q->M * sizeof(TI)); // execute IFFT, store result in buffer 'x' FFT_EXECUTE(_q->ifft); // TODO: ignore this scaling // scale result by 1/num_channels (C transform) for (i=0; i<_q->M; i++) _q->x[i] *= 1.0f / (float)(_q->M); // scale result by num_channels/2 for (i=0; i<_q->M; i++) _q->x[i] *= (float)(_q->M2); // push samples into appropriate buffer WINDOW() * buffer = (_q->flag == 0 ? _q->w1 : _q->w0); for (i=0; i<_q->M; i++) WINDOW(_push)(buffer[i], _q->x[i]); // compute filter outputs TO * r0, * r1; // buffer read pointers TO y0, y1; // dotprod outputs for (i=0; i<_q->M2; i++) { // buffer index unsigned int b = (_q->flag == 0) ? i : i+_q->M2; // read buffer with index offset WINDOW(_read)(_q->w0[b], &r0); WINDOW(_read)(_q->w1[b], &r1); // swap buffer outputs on alternating runs TO * p0 = _q->flag ? r0 : r1; TO * p1 = _q->flag ? r1 : r0; // run dot products DOTPROD(_execute)(_q->dp[i], p0, &y0); DOTPROD(_execute)(_q->dp[i+_q->M2], p1, &y1); // save output _y[i] = y0 + y1; } _q->flag = 1 - _q->flag; return LIQUID_OK; } // execute filterbank channelizer // LIQUID_ANALYZER: input: M/2, output: M // LIQUID_SYNTHESIZER: input: M, output: M/2 // _x : channelizer input // _y : channelizer output int FIRPFBCH2(_execute)(FIRPFBCH2() _q, TI * _x, TO * _y) { switch (_q->type) { case LIQUID_ANALYZER: return FIRPFBCH2(_execute_analyzer)(_q, _x, _y); case LIQUID_SYNTHESIZER: return FIRPFBCH2(_execute_synthesizer)(_q, _x, _y); default:; } return liquid_error(LIQUID_EINT,"firpfbch2_%s_execute(), invalid internal type", EXTENSION_FULL); } liquid-dsp-1.7.0/src/multichannel/src/firpfbch_cccf.c000066400000000000000000000037421474751757600225750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // multichannel API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "cccf" // #define FIRPFBCH(name) LIQUID_CONCAT(firpfbch_cccf,name) #define T float complex // general #define TO float complex // output #define TC float complex // coefficients #define TI float complex // input #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_cccf,name) #define TO_COMPLEX 1 #define TC_COMPLEX 1 #define TI_COMPLEX 1 #define PRINTVAL_TO(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_CFLOAT(X,F) // prototypes #include "firpfbch.proto.c" liquid-dsp-1.7.0/src/multichannel/src/firpfbch_crcf.c000066400000000000000000000044571474751757600226200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // multichannel API: complex floating-point // #include "liquid.internal.h" // naming extensions (useful for print statements) #define EXTENSION_SHORT "f" #define EXTENSION_FULL "crcf" // #define FIRPFBCH(name) LIQUID_CONCAT(firpfbch_crcf,name) #define FIRPFBCH2(name) LIQUID_CONCAT(firpfbch2_crcf,name) #define FIRPFBCHR(name) LIQUID_CONCAT(firpfbchr_crcf,name) #define T float complex // general #define TO float complex // output #define TC float // coefficients #define TI float complex // input #define WINDOW(name) LIQUID_CONCAT(windowcf,name) #define DOTPROD(name) LIQUID_CONCAT(dotprod_crcf,name) #define TO_COMPLEX 1 #define TC_COMPLEX 0 #define TI_COMPLEX 1 #define PRINTVAL_TO(X,F) PRINTVAL_CFLOAT(X,F) #define PRINTVAL_TC(X,F) PRINTVAL_FLOAT(X,F) #define PRINTVAL_TI(X,F) PRINTVAL_CFLOAT(X,F) // prototypes #include "firpfbch.proto.c" // maximally-decimated polyphase filterbank #include "firpfbch2.proto.c" // polyphase filterbank w/ output rate 2 Fs / M #include "firpfbchr.proto.c" // polyphase filterbank w/ output rate P Fs / M liquid-dsp-1.7.0/src/multichannel/src/firpfbchr.proto.c000066400000000000000000000227471474751757600231510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // finite impulse response polyphase filterbank channelizer with output // rate Fs / P #include #include #include #include #include "liquid.internal.h" // firpfbchr object structure definition struct FIRPFBCHR(_s) { unsigned int M; // number of channels unsigned int P; // decimation factor unsigned int m; // filter semi-length // filter unsigned int h_len; // prototype filter length: 2*M*m // create separate bank of dotprod and window objects DOTPROD() * dp; // dot product object array // inverse FFT plan FFT_PLAN ifft; // inverse FFT object TO * X; // IFFT input array [size: M x 1] TO * x; // IFFT output array [size: M x 1] // common data structures shared between analysis and // synthesis algorithms WINDOW() * w; // window buffer object array unsigned int base_index; }; // create rational rate resampling channelizer (firpfbchr) object by // specifying filter coefficients directly // _chans : number of output channels in chanelizer // _decim : output decimation factor (output rate is 1/P the input) // _m : prototype filter semi-length, length=2*M*m // _h : prototype filter coefficient array, [size: 2*M*m x 1] FIRPFBCHR() FIRPFBCHR(_create)(unsigned int _chans, unsigned int _decim, unsigned int _m, TC * _h) { // validate input if (_chans < 2) return liquid_error_config("firpfbchr_%s_create(), number of channels must be at least 2", EXTENSION_FULL); if (_decim < 1) return liquid_error_config("firpfbchr_%s_create(), decimation rate must be at least 1", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbchr_%s_create(), filter semi-length must be at least 1", EXTENSION_FULL); if (_h == NULL) return liquid_error_config("firpfbchr_%s_create(), filter coefficients cannot be null", EXTENSION_FULL); // create object FIRPFBCHR() q = (FIRPFBCHR()) malloc(sizeof(struct FIRPFBCHR(_s))); // set input parameters q->M = _chans; // number of channels q->P = _decim; // q->m = _m; // prototype filter semi-length // compute derived values q->h_len = 2*q->M*q->m; // prototype filter length // generate bank of sub-samped filters q->dp = (DOTPROD()*) malloc((q->M)*sizeof(DOTPROD())); unsigned int i; unsigned int n; unsigned int h_sub_len = 2 * q->m; TC h_sub[h_sub_len]; for (i=0; iM; i++) { // sub-sample prototype filter, loading coefficients // in reverse order for (n=0; nM)]; // create dotprod object q->dp[i] = DOTPROD(_create)(h_sub,h_sub_len); } // create FFT plan (inverse transform) q->X = (T*) FFT_MALLOC((q->M)*sizeof(T)); // IFFT input q->x = (T*) FFT_MALLOC((q->M)*sizeof(T)); // IFFT output q->ifft = FFT_CREATE_PLAN(q->M, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // create buffer objects q->w = (WINDOW()*) malloc((q->M)*sizeof(WINDOW())); for (i=0; iM; i++) q->w[i] = WINDOW(_create)(h_sub_len); // reset filterbank object and return FIRPFBCHR(_reset)(q); return q; } // create rational rate resampling channelizer (firpfbchr) object by // specifying filter design parameters for Kaiser prototype // _chans : number of output channels in chanelizer // _decim : output decimation factor (output rate is 1/P the input) // _m : prototype filter semi-length, length=2*M*m // _as : filter stop-band attenuation [dB] FIRPFBCHR() FIRPFBCHR(_create_kaiser)(unsigned int _chans, unsigned int _decim, unsigned int _m, float _as) { // validate input if (_chans < 2) return liquid_error_config("firpfbchr_%s_create_kaiser(), number of channels must be at least 2", EXTENSION_FULL); if (_decim < 1) return liquid_error_config("firpfbchr_%s_create_kaiser(), decimation rate must be at least 1", EXTENSION_FULL); if (_m < 1) return liquid_error_config("firpfbchr_%s_create_kaiser(), filter semi-length must be at least 1", EXTENSION_FULL); if (_as <= 0.0f) return liquid_error_config("firpfbchr_%s_create_kaiser(), stop-band suppression out of range", EXTENSION_FULL); // design prototype filter unsigned int h_len = 2*_chans*_m+1; float * hf = (float*)malloc(h_len*sizeof(float)); // filter cut-off frequency float fc = 0.5f/(float)_decim; // compute filter coefficients (floating point precision) liquid_firdes_kaiser(h_len, fc, _as, 0.0f, hf); // normalize to unit average and scale by number of channels float hf_sum = 0.0f; unsigned int i; for (i=0; iM; i++) DOTPROD(_destroy)(_q->dp[i]); free(_q->dp); // free transform object and arrays FFT_DESTROY_PLAN(_q->ifft); FFT_FREE(_q->X); FFT_FREE(_q->x); // free window objects (buffers) for (i=0; i<_q->M; i++) WINDOW(_destroy)(_q->w[i]); free(_q->w); // free main object memory free(_q); return LIQUID_OK; } // reset firpfbchr object internals int FIRPFBCHR(_reset)(FIRPFBCHR() _q) { unsigned int i; // clear window buffers for (i=0; i<_q->M; i++) WINDOW(_reset)(_q->w[i]); // reset filter/buffer alignment flag _q->base_index = _q->M - 1; return LIQUID_OK; } // print firpfbchr object internals int FIRPFBCHR(_print)(FIRPFBCHR() _q) { printf("\n", _q->M, _q->P, _q->m); return LIQUID_OK; } // DEPRECATED: get number of output channels to channelizer unsigned int FIRPFBCHR(_get_M)(FIRPFBCHR() _q) { return FIRPFBCHR(_get_num_channels)(_q); } // get number of output channels to channelizer unsigned int FIRPFBCHR(_get_num_channels)(FIRPFBCHR() _q) { return _q->M; } // DEPRECATED: get decimation rate unsigned int FIRPFBCHR(_get_P)(FIRPFBCHR() _q) { return FIRPFBCHR(_get_decim_rate)(_q); } // get decimation rate unsigned int FIRPFBCHR(_get_decim_rate)(FIRPFBCHR() _q) { return _q->P; } // get semi-length to channelizer filter prototype unsigned int FIRPFBCHR(_get_m)(FIRPFBCHR() _q) { return _q->m; } // push samples into filter bank // _q : channelizer object // _x : channelizer input, [size: decim x 1] int FIRPFBCHR(_push)(FIRPFBCHR() _q, TI * _x) { // load buffers in blocks of P in the reverse direction unsigned int i; for (i=0; i<_q->P; i++) { // push sample into buffer at filter index WINDOW(_push)(_q->w[_q->base_index], _x[i]); // decrement base index, wrapping around _q->base_index = _q->base_index == 0 ? _q->M-1 : _q->base_index-1; } return LIQUID_OK; } // execute filterbank channelizer (synthesizer) // _q : channelizer object // _y : channelizer output, [size: M x 1] int FIRPFBCHR(_execute)(FIRPFBCHR() _q, TO * _y) { unsigned int i; // execute filter outputs TO * r; // buffer read pointer for (i=0; i<_q->M; i++) { // buffer index unsigned int buffer_index = (_q->base_index+i+1) % _q->M; // read buffer at index WINDOW(_read)(_q->w[buffer_index], &r); // run dot products DOTPROD(_execute)(_q->dp[i], r, &_q->X[buffer_index]); } // execute IFFT, store result in buffer 'x' FFT_EXECUTE(_q->ifft); // copy result to output, scale result by 1/num_channels (C transform) float g = 1.0f / (float)(_q->M); for (i=0; i<_q->M; i++) _y[i] = _q->x[i] * g; return LIQUID_OK; } liquid-dsp-1.7.0/src/multichannel/src/ofdmframe.common.c000066400000000000000000000250121474751757600232550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // ofdmframe data, methods common to both generator/synchronizer // objects // - physical layer convergence procedure (PLCP) // #include #include #include #include "liquid.internal.h" // generate short sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S0 : output symbol (freq) // _s0 : output symbol (time) // _M_S0 : total number of enabled subcarriers in S0 int ofdmframe_init_S0(unsigned char * _p, unsigned int _M, float complex * _S0, float complex * _s0, unsigned int * _M_S0) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_M); if (m < 4) m = 4; else if (m > 8) m = 8; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S0 = 0; // short sequence for (i=0; i<_M; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMFRAME_SCTYPE_NULL) { // NULL subcarrier _S0[i] = 0.0f; } else { if ( (i%2) == 0 ) { // even subcarrer _S0[i] = s ? 1.0f : -1.0f; M_S0++; } else { // odd subcarrer (ignore) _S0[i] = 0.0f; } } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S0 == 0) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_S0(), no subcarriers enabled; check allocation"); // set return value(s) *_M_S0 = M_S0; // run inverse fft to get time-domain sequence fft_run(_M, _S0, _s0, LIQUID_FFT_BACKWARD, 0); // normalize time-domain sequence level float g = 1.0f / sqrtf(M_S0); for (i=0; i<_M; i++) _s0[i] *= g; return LIQUID_OK; } // generate long sequence symbols // _p : subcarrier allocation array // _M : total number of subcarriers // _S1 : output symbol (freq) // _s1 : output symbol (time) // _M_S1 : total number of enabled subcarriers in S1 int ofdmframe_init_S1(unsigned char * _p, unsigned int _M, float complex * _S1, float complex * _s1, unsigned int * _M_S1) { unsigned int i; // compute m-sequence length unsigned int m = liquid_nextpow2(_M); if (m < 4) m = 4; else if (m > 8) m = 8; // increase m such that the resulting S1 sequence will // differ significantly from S0 with the same subcarrier // allocation array m++; // generate m-sequence generator object msequence ms = msequence_create_default(m); unsigned int s; unsigned int M_S1 = 0; // long sequence for (i=0; i<_M; i++) { // generate symbol //s = msequence_generate_symbol(ms,1); s = msequence_generate_symbol(ms,3) & 0x01; if (_p[i] == OFDMFRAME_SCTYPE_NULL) { // NULL subcarrier _S1[i] = 0.0f; } else { _S1[i] = s ? 1.0f : -1.0f; M_S1++; } } // destroy objects msequence_destroy(ms); // ensure at least one subcarrier was enabled if (M_S1 == 0) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_S1(), no subcarriers enabled; check allocation"); // set return value(s) *_M_S1 = M_S1; // run inverse fft to get time-domain sequence fft_run(_M, _S1, _s1, LIQUID_FFT_BACKWARD, 0); // normalize time-domain sequence level float g = 1.0f / sqrtf(M_S1); for (i=0; i<_M; i++) _s1[i] *= g; return LIQUID_OK; } // initialize default subcarrier allocation // _M : number of subcarriers // _p : output subcarrier allocation array, [size: _M x 1] // // key: '.' (null), 'P' (pilot), '+' (data) // .+++P+++++++P.........P+++++++P+++ // int ofdmframe_init_default_sctype(unsigned int _M, unsigned char * _p) { // validate input if (_M < 6) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_default_sctype(), less than 6 subcarriers"); unsigned int i; unsigned int M2 = _M/2; // compute guard band unsigned int G = _M / 10; if (G < 2) G = 2; // designate pilot spacing unsigned int P = (_M > 34) ? 8 : 4; unsigned int P2 = P/2; // initialize as NULL for (i=0; i<_M; i++) _p[i] = OFDMFRAME_SCTYPE_NULL; // upper band for (i=1; i 0.5f) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_sctype_range(), lower frequency edge must be in [-0.5,0.5]"); if (_f1 < -0.5f || _f1 > 0.5f) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_sctype_range(), upper frequency edge must be in [-0.5,0.5]"); if (_f0 >= _f1) return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_sctype_range(), lower frequency edge must be below upper edge"); // get relative edges int M0 = (int)((_f0 + 0.5f) * _M); // lower subcarrier index int M1 = (int)((_f1 + 0.5f) * _M); // upper subcarrier index int Mp = M1 - M0; if (Mp > (int)_M) { Mp = (int)_M; } else if (Mp < 6) { return liquid_error(LIQUID_EICONFIG,"ofdmframe_init_sctype_range(), less than 6 subcarriers (effectively)"); } // designate pilot spacing unsigned int P = (Mp > 34) ? 8 : 4; // upper band int i; for (i=0; i<(int)_M; i++) { // shift unsigned int k = ((unsigned int)i + _M/2) % _M; if (i < M0 || i > M1) { // guard band _p[k] = OFDMFRAME_SCTYPE_NULL; } else if ( (k%P)==0 ) { _p[k] = OFDMFRAME_SCTYPE_PILOT; } else { _p[k] = OFDMFRAME_SCTYPE_DATA; } } return LIQUID_OK; } // validate subcarrier type (count number of null, pilot, and data // subcarriers in the allocation) // _p : subcarrier allocation array, [size: _M x 1] // _M : number of subcarriers // _M_null : output number of null subcarriers // _M_pilot : output number of pilot subcarriers // _M_data : output number of data subcarriers int ofdmframe_validate_sctype(unsigned char * _p, unsigned int _M, unsigned int * _M_null, unsigned int * _M_pilot, unsigned int * _M_data) { // clear counters unsigned int M_null = 0; unsigned int M_pilot = 0; unsigned int M_data = 0; unsigned int i; for (i=0; i<_M; i++) { // update appropriate counters if (_p[i] == OFDMFRAME_SCTYPE_NULL) M_null++; else if (_p[i] == OFDMFRAME_SCTYPE_PILOT) M_pilot++; else if (_p[i] == OFDMFRAME_SCTYPE_DATA) M_data++; else { return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), invalid subcarrier type (%u)", _p[i]); } } // validate subcarrier allocation if ( (M_pilot + M_data) == 0) return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one enabled subcarrier"); if (M_data == 0) return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least one data subcarrier"); if (M_pilot < 2) return liquid_error(LIQUID_EICONFIG,"ofdmframe_validate_sctype(), must have at least two pilot subcarriers"); // set outputs if requested if (_M_null != NULL) *_M_null = M_null; if (_M_pilot != NULL) *_M_pilot = M_pilot; if (_M_data != NULL) *_M_data = M_data; return LIQUID_OK; } // print subcarrier allocation to screen // // key: '.' (null), 'P' (pilot), '+' (data) // .+++P+++++++P.........P+++++++P+++ // int ofdmframe_print_sctype(unsigned char * _p, unsigned int _M) { unsigned int i; printf("["); for (i=0; i<_M; i++) { unsigned int k = (i + _M/2) % _M; switch (_p[k]) { case OFDMFRAME_SCTYPE_NULL: printf("."); break; case OFDMFRAME_SCTYPE_PILOT: printf("|"); break; case OFDMFRAME_SCTYPE_DATA: printf("+"); break; default: return liquid_error(LIQUID_EICONFIG,"ofdmframe_print_default_sctype(), invalid subcarrier type"); } } printf("]\n"); return LIQUID_OK; } liquid-dsp-1.7.0/src/multichannel/src/ofdmframegen.c000066400000000000000000000272411474751757600224660ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // ofdmframegen.c // // OFDM frame generator // #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_OFDMFRAMEGEN 1 // generate symbol (add cyclic prefix/postfix, overlap) int ofdmframegen_gensymbol(ofdmframegen _q, float complex * _buffer); struct ofdmframegen_s { unsigned int M; // number of subcarriers unsigned int cp_len; // cyclic prefix length unsigned char * p; // subcarrier allocation (null, pilot, data) // tapering/trasition unsigned int taper_len; // number of samples in tapering window/overlap float * taper; // tapering window float complex *postfix; // overlapping symbol buffer // constants unsigned int M_null; // number of null subcarriers unsigned int M_pilot; // number of pilot subcarriers unsigned int M_data; // number of data subcarriers unsigned int M_S0; // number of enabled subcarriers in S0 unsigned int M_S1; // number of enabled subcarriers in S1 // scaling factors float g_data; // // transform object FFT_PLAN ifft; // ifft object float complex * X; // frequency-domain buffer float complex * x; // time-domain buffer // PLCP short float complex * S0; // short sequence (frequency) float complex * s0; // short sequence (time) // PLCP long float complex * S1; // long sequence (frequency) float complex * s1; // long sequence (time) // pilot sequence msequence ms_pilot; }; // create OFDM framing generator object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap) // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] ofdmframegen ofdmframegen_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p) { // validate input if (_M < 8) return liquid_error_config("ofdmframegen_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframegen_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmframegen_create(), cyclic prefix cannot exceed symbol length"); if (_taper_len > _cp_len) return liquid_error_config("ofdmframegen_create(), taper length cannot exceed cyclic prefix"); ofdmframegen q = (ofdmframegen) malloc(sizeof(struct ofdmframegen_s)); q->M = _M; q->cp_len = _cp_len; q->taper_len = _taper_len; // allocate memory for subcarrier allocation IDs q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { // initialize default subcarrier allocation ofdmframe_init_default_sctype(q->M, q->p); } else { // copy user-defined subcarrier allocation memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframegen_create(), invalid subcarrier allocation"); unsigned int i; // allocate memory for transform objects q->X = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); q->x = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); q->ifft = FFT_CREATE_PLAN(q->M, q->X, q->x, FFT_DIR_BACKWARD, FFT_METHOD); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // create tapering window and transition buffer q->taper = (float*) malloc(q->taper_len * sizeof(float)); q->postfix = (float complex*) malloc(q->taper_len * sizeof(float complex)); for (i=0; itaper_len; i++) { float t = ((float)i + 0.5f) / (float)(q->taper_len); float g = sinf(M_PI_2*t); q->taper[i] = g*g; } #if 0 // validate window symmetry for (i=0; itaper_len; i++) { printf(" taper[%2u] = %12.8f (%12.8f)\n", i, q->taper[i], q->taper[i] + q->taper[q->taper_len - i - 1]); } #endif // compute scaling factor q->g_data = 1.0f / sqrtf(q->M_pilot + q->M_data); // set pilot sequence q->ms_pilot = msequence_create_default(8); return q; } // free transform object memory int ofdmframegen_destroy(ofdmframegen _q) { // free subcarrier type array memory free(_q->p); // free transform array memory FFT_FREE(_q->X); FFT_FREE(_q->x); FFT_DESTROY_PLAN(_q->ifft); // free tapering window and transition buffer free(_q->taper); free(_q->postfix); // free PLCP memory arrays free(_q->S0); free(_q->s0); free(_q->S1); free(_q->s1); // free pilot msequence object memory msequence_destroy(_q->ms_pilot); // free main object memory free(_q); return LIQUID_OK; } int ofdmframegen_print(ofdmframegen _q) { printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); printf(", data=%u", _q->M_data); printf(", cp=%u", _q->cp_len); printf(", taper=%u", _q->taper_len); printf(">\n"); return LIQUID_OK; } int ofdmframegen_reset(ofdmframegen _q) { msequence_reset(_q->ms_pilot); // clear internal postfix buffer unsigned int i; for (i=0; i<_q->taper_len; i++) _q->postfix[i] = 0.0f; return LIQUID_OK; } // write first PLCP short sequence 'symbol' to buffer // // |<- 2*cp->|<- M ->|<- M ->| // | | | | // +-----+-------------------+-------------------+ // / | | | // / ..s0 | s0 | s0 | // / | | | // +---------+-------------------+-------------------+-----> time // | | | // |<- s0[a] ->|<- s0[b] ->| // | M + cp_len | M + cp_len | // int ofdmframegen_write_S0a(ofdmframegen _q, float complex * _y) { unsigned int i; unsigned int k; for (i=0; i<_q->M + _q->cp_len; i++) { k = (i + _q->M - 2*_q->cp_len) % _q->M; _y[i] = _q->s0[k]; } // apply tapering window for (i=0; i<_q->taper_len; i++) _y[i] *= _q->taper[i]; return LIQUID_OK; } int ofdmframegen_write_S0b(ofdmframegen _q, float complex * _y) { unsigned int i; unsigned int k; for (i=0; i<_q->M + _q->cp_len; i++) { k = (i + _q->M - _q->cp_len) % _q->M; _y[i] = _q->s0[k]; } // copy postfix (first 'taper_len' samples of s0 symbol) memmove(_q->postfix, _q->s0, _q->taper_len*sizeof(float complex)); return LIQUID_OK; } int ofdmframegen_write_S1(ofdmframegen _q, float complex * _y) { // copy S1 symbol to output, adding cyclic prefix and tapering window memmove(_q->x, _q->s1, (_q->M)*sizeof(float complex)); return ofdmframegen_gensymbol(_q, _y); } // write OFDM symbol // _q : framing generator object // _x : input symbols, [size: _M x 1] // _y : output samples, [size: _M x 1] int ofdmframegen_writesymbol(ofdmframegen _q, float complex * _x, float complex * _y) { // move frequency data to internal buffer unsigned int i; unsigned int k; int sctype; for (i=0; i<_q->M; i++) { // start at mid-point (effective fftshift) k = (i + _q->M/2) % _q->M; sctype = _q->p[k]; if (sctype==OFDMFRAME_SCTYPE_NULL) { // disabled subcarrier _q->X[k] = 0.0f; } else if (sctype==OFDMFRAME_SCTYPE_PILOT) { // pilot subcarrier _q->X[k] = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f) * _q->g_data; } else { // data subcarrier _q->X[k] = _x[k] * _q->g_data; } //printf("X[%3u] = %12.8f + j*%12.8f;\n",i+1,crealf(_q->X[i]),cimagf(_q->X[i])); } // execute transform FFT_EXECUTE(_q->ifft); // copy result to output, adding cyclic prefix and tapering window return ofdmframegen_gensymbol(_q, _y); } // write tail to output int ofdmframegen_writetail(ofdmframegen _q, float complex * _buffer) { // write tail to output, applying tapering window unsigned int i; for (i=0; i<_q->taper_len; i++) _buffer[i] = _q->postfix[i] * _q->taper[_q->taper_len-i-1]; return LIQUID_OK; } // // internal methods // // generate symbol (add cyclic prefix/postfix, overlap) // // ->| |<- taper_len // + +-----+-------------------+ // \ / | | // X | symbol | // / \ | | // +---+-----+-------------------+----> time // | | | // |<- cp ->|<- M ->| // // _q->x : input time-domain symbol [size: _q->M x 1] // _q->postfix : input: post-fix from previous symbol [size: _q->taper_len x 1] // output: post-fix from this new symbol // _q->taper : tapering window // _q->taper_len : tapering window length // // _buffer : output sample buffer [size: (_q->M + _q->cp_len) x 1] int ofdmframegen_gensymbol(ofdmframegen _q, float complex * _buffer) { // copy input symbol with cyclic prefix to output symbol memmove( &_buffer[0], &_q->x[_q->M-_q->cp_len], _q->cp_len*sizeof(float complex)); memmove( &_buffer[_q->cp_len], &_q->x[ 0], _q->M * sizeof(float complex)); // apply tapering window to over-lapping regions unsigned int i; for (i=0; i<_q->taper_len; i++) { _buffer[i] *= _q->taper[i]; _buffer[i] += _q->postfix[i] * _q->taper[_q->taper_len-i-1]; } // copy post-fix to output (first 'taper_len' samples of input symbol) memmove(_q->postfix, _q->x, _q->taper_len*sizeof(float complex)); return LIQUID_OK; } liquid-dsp-1.7.0/src/multichannel/src/ofdmframesync.c000066400000000000000000001247771474751757600227050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // OFDM frame synchronizer #include #include #include #include #include #include "liquid.internal.h" #define DEBUG_OFDMFRAMESYNC 0 #define DEBUG_OFDMFRAMESYNC_PRINT 0 #define DEBUG_OFDMFRAMESYNC_FILENAME "ofdmframesync_internal_debug.m" #define DEBUG_OFDMFRAMESYNC_BUFFER_LEN (2048) #define OFDMFRAMESYNC_ENABLE_SQUELCH 0 // forward declaration of internal methods int ofdmframesync_execute_seekplcp(ofdmframesync _q); int ofdmframesync_execute_S0a(ofdmframesync _q); int ofdmframesync_execute_S0b(ofdmframesync _q); int ofdmframesync_execute_S1( ofdmframesync _q); int ofdmframesync_execute_rxsymbols(ofdmframesync _q); int ofdmframesync_S0_metrics(ofdmframesync _q, float complex * _G, float complex * _s_hat); // estimate short sequence gain // _q : ofdmframesync object // _x : input array (time) // _G : output gain (freq) int ofdmframesync_estimate_gain_S0(ofdmframesync _q, float complex * _x, float complex * _G); // estimate long sequence gain // _q : ofdmframesync object // _x : input array (time) // _G : output gain (freq) int ofdmframesync_estimate_gain_S1(ofdmframesync _q, float complex * _x, float complex * _G); // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing //int ofdmframesync_estimate_eqgain(ofdmframesync _q, unsigned int _ntaps); // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object // _order : polynomial order int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, unsigned int _order); // recover symbol, correcting for gain, pilot phase, etc. int ofdmframesync_rxsymbol(ofdmframesync _q); struct ofdmframesync_s { unsigned int M; // number of subcarriers unsigned int M2; // number of subcarriers (divided by 2) unsigned int cp_len; // cyclic prefix length unsigned char * p; // subcarrier allocation (null, pilot, data) unsigned int taper_len; // number of samples in tapering window/overlap // constants unsigned int M_null; // number of null subcarriers unsigned int M_pilot; // number of pilot subcarriers unsigned int M_data; // number of data subcarriers unsigned int M_S0; // number of enabled subcarriers in S0 unsigned int M_S1; // number of enabled subcarriers in S1 // scaling factors float g_data; // data symbols gain float g_S0; // S0 training symbols gain float g_S1; // S1 training symbols gain // transform object FFT_PLAN fft; // ifft object float complex * X; // frequency-domain buffer float complex * x; // time-domain buffer windowcf input_buffer; // input sequence buffer // PLCP sequences float complex * S0; // short sequence (freq) float complex * s0; // short sequence (time) float complex * S1; // long sequence (freq) float complex * s1; // long sequence (time) // gain float g0; // nominal gain (coarse initial estimate) float complex * G0a; // complex subcarrier gain estimate, S0[a] float complex * G0b; // complex subcarrier gain estimate, S0[b] float complex * G1; // complex subcarrier gain estimate, S1 float complex * G; // complex subcarrier gain estimate float complex * B; // subcarrier phase rotation due to backoff float complex * R; // // receiver state enum { OFDMFRAMESYNC_STATE_SEEKPLCP=0, // seek initial PLCP OFDMFRAMESYNC_STATE_PLCPSHORT0, // seek first PLCP short sequence OFDMFRAMESYNC_STATE_PLCPSHORT1, // seek second PLCP short sequence OFDMFRAMESYNC_STATE_PLCPLONG, // seek PLCP long sequence OFDMFRAMESYNC_STATE_RXSYMBOLS // receive payload symbols } state; // synchronizer objects nco_crcf nco_rx; // numerically-controlled oscillator msequence ms_pilot; // pilot sequence generator float phi_prime; // ... float p1_prime; // filtered pilot phase slope #if OFDMFRAMESYNC_ENABLE_SQUELCH // coarse signal detection float squelch_threshold; int squelch_enabled; #endif // timing unsigned int timer; // input sample timer unsigned int num_symbols; // symbol counter unsigned int backoff; // sample timing backoff float complex s_hat_0; // first S0 symbol metrics estimate float complex s_hat_1; // second S0 symbol metrics estimate // detection thresholds float plcp_detect_thresh; // plcp detection threshold, nominally 0.35 float plcp_sync_thresh; // long symbol threshold, nominally 0.30 // callback ofdmframesync_callback callback; void * userdata; #if DEBUG_OFDMFRAMESYNC int debug_enabled; int debug_objects_created; windowcf debug_x; windowf debug_rssi; windowcf debug_framesyms; float complex * G_hat; // complex subcarrier gain estimate, S1 float * px; // pilot x-value float * py; // pilot y-value float p_phase[2]; // pilot polyfit windowf debug_pilot_0; // pilot polyfit history, p[0] windowf debug_pilot_1; // pilot polyfit history, p[1] #endif }; // create OFDM framing synchronizer object // _M : number of subcarriers, >10 typical // _cp_len : cyclic prefix length // _taper_len : taper length (OFDM symbol overlap), TODO: remove? not used in this object // _p : subcarrier allocation (null, pilot, data), [size: _M x 1] // _callback : user-defined callback function // _userdata : user-defined data pointer ofdmframesync ofdmframesync_create(unsigned int _M, unsigned int _cp_len, unsigned int _taper_len, unsigned char * _p, ofdmframesync_callback _callback, void * _userdata) { // validate input if (_M < 8) return liquid_error_config("ofdmframesync_create(), number of subcarriers must be at least 8"); if (_M % 2) return liquid_error_config("ofdmframesync_create(), number of subcarriers must be even"); if (_cp_len > _M) return liquid_error_config("ofdmframesync_create(), cyclic prefix length cannot exceed number of subcarriers"); if (_taper_len > _cp_len) return liquid_error_config("ofdmframesync_create(), taper length cannot exceed cyclic prefix"); // allocate object and set parameters ofdmframesync q = (ofdmframesync) malloc(sizeof(struct ofdmframesync_s)); q->M = _M; q->cp_len = _cp_len; q->taper_len = _taper_len; // derived values q->M2 = _M/2; // subcarrier allocation q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char)); if (_p == NULL) { ofdmframe_init_default_sctype(q->M, q->p); } else { memmove(q->p, _p, q->M*sizeof(unsigned char)); } // validate and count subcarrier allocation if (ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data)) return liquid_error_config("ofdmframesync_create(), invalid subcarrier allocation"); // create transform object q->X = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); q->x = (float complex*) FFT_MALLOC((q->M)*sizeof(float complex)); q->fft = FFT_CREATE_PLAN(q->M, q->x, q->X, FFT_DIR_FORWARD, FFT_METHOD); // create input buffer the length of the transform q->input_buffer = windowcf_create(q->M + q->cp_len); // allocate memory for PLCP arrays q->S0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s0 = (float complex*) malloc((q->M)*sizeof(float complex)); q->S1 = (float complex*) malloc((q->M)*sizeof(float complex)); q->s1 = (float complex*) malloc((q->M)*sizeof(float complex)); ofdmframe_init_S0(q->p, q->M, q->S0, q->s0, &q->M_S0); ofdmframe_init_S1(q->p, q->M, q->S1, q->s1, &q->M_S1); // compute scaling factor q->g_data = sqrtf(q->M) / sqrtf(q->M_pilot + q->M_data); q->g_S0 = sqrtf(q->M) / sqrtf(q->M_S0); q->g_S1 = sqrtf(q->M) / sqrtf(q->M_S1); // gain q->g0 = 1.0f; q->G0a = (float complex*) malloc((q->M)*sizeof(float complex)); q->G0b = (float complex*) malloc((q->M)*sizeof(float complex)); q->G = (float complex*) malloc((q->M)*sizeof(float complex)); q->B = (float complex*) malloc((q->M)*sizeof(float complex)); q->R = (float complex*) malloc((q->M)*sizeof(float complex)); #if 1 memset(q->G0a, 0x00, q->M*sizeof(float complex)); memset(q->G0b, 0x00, q->M*sizeof(float complex)); memset(q->G , 0x00, q->M*sizeof(float complex)); memset(q->B, 0x00, q->M*sizeof(float complex)); #endif // timing backoff q->backoff = q->cp_len < 2 ? q->cp_len : 2; float phi = (float)(q->backoff)*2.0f*M_PI/(float)(q->M); unsigned int i; for (i=0; iM; i++) q->B[i] = liquid_cexpjf(i*phi); // set callback data q->callback = _callback; q->userdata = _userdata; // // synchronizer objects // // numerically-controlled oscillator q->nco_rx = nco_crcf_create(LIQUID_NCO); // set pilot sequence q->ms_pilot = msequence_create_default(8); #if OFDMFRAMESYNC_ENABLE_SQUELCH // coarse detection q->squelch_threshold = -25.0f; q->squelch_enabled = 0; #endif // reset object ofdmframesync_reset(q); #if DEBUG_OFDMFRAMESYNC q->debug_enabled = 0; q->debug_objects_created = 0; q->debug_x = NULL; q->debug_rssi = NULL; q->debug_framesyms =NULL; q->G_hat = NULL; q->px = NULL; q->py = NULL; q->debug_pilot_0 = NULL; q->debug_pilot_1 = NULL; #endif // return object return q; } int ofdmframesync_destroy(ofdmframesync _q) { #if DEBUG_OFDMFRAMESYNC // destroy debugging objects if (_q->debug_x != NULL) windowcf_destroy(_q->debug_x); if (_q->debug_rssi != NULL) windowf_destroy(_q->debug_rssi); if (_q->debug_framesyms != NULL) windowcf_destroy(_q->debug_framesyms); if (_q->G_hat != NULL) free(_q->G_hat); if (_q->px != NULL) free(_q->px); if (_q->py != NULL) free(_q->py); if (_q->debug_pilot_0 != NULL) windowf_destroy(_q->debug_pilot_0); if (_q->debug_pilot_1 != NULL) windowf_destroy(_q->debug_pilot_1); #endif // free subcarrier type array memory free(_q->p); // free transform object windowcf_destroy(_q->input_buffer); FFT_FREE(_q->X); FFT_FREE(_q->x); FFT_DESTROY_PLAN(_q->fft); // clean up PLCP arrays free(_q->S0); free(_q->s0); free(_q->S1); free(_q->s1); // free gain arrays free(_q->G0a); free(_q->G0b); free(_q->G); free(_q->B); free(_q->R); // destroy synchronizer objects nco_crcf_destroy(_q->nco_rx); // numerically-controlled oscillator msequence_destroy(_q->ms_pilot); // free main object memory free(_q); return LIQUID_OK; } int ofdmframesync_print(ofdmframesync _q) { printf("M); printf(", null=%u", _q->M_null); printf(", pilot=%u", _q->M_pilot); printf(", data=%u", _q->M_data); printf(", cp=%u", _q->cp_len); printf(", taper=%u", _q->taper_len); printf(">\n"); return LIQUID_OK; } int ofdmframesync_reset(ofdmframesync _q) { #if 0 // reset gain parameters unsigned int i; for (i=0; i<_q->M; i++) _q->G[i] = 1.0f; #endif // reset synchronizer objects nco_crcf_reset(_q->nco_rx); msequence_reset(_q->ms_pilot); // reset timers _q->timer = 0; _q->num_symbols = 0; _q->s_hat_0 = 0.0f; _q->s_hat_1 = 0.0f; _q->phi_prime = 0.0f; _q->p1_prime = 0.0f; // set thresholds (increase for small number of subcarriers) _q->plcp_detect_thresh = (_q->M > 44) ? 0.35f : 0.35f + 0.01f*(44 - _q->M); _q->plcp_sync_thresh = (_q->M > 44) ? 0.30f : 0.30f + 0.01f*(44 - _q->M); // reset state _q->state = OFDMFRAMESYNC_STATE_SEEKPLCP; return LIQUID_OK; } int ofdmframesync_is_frame_open(ofdmframesync _q) { return (_q->state == OFDMFRAMESYNC_STATE_SEEKPLCP) ? 0 : 1; } int ofdmframesync_execute(ofdmframesync _q, float complex * _x, unsigned int _n) { unsigned int i; float complex x; for (i=0; i<_n; i++) { x = _x[i]; // correct for carrier frequency offset if (_q->state != OFDMFRAMESYNC_STATE_SEEKPLCP) { nco_crcf_mix_down(_q->nco_rx, x, &x); nco_crcf_step(_q->nco_rx); } // save input sample to buffer windowcf_push(_q->input_buffer,x); #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { windowcf_push(_q->debug_x, x); windowf_push(_q->debug_rssi, crealf(x)*crealf(x) + cimagf(x)*cimagf(x)); } #endif switch (_q->state) { case OFDMFRAMESYNC_STATE_SEEKPLCP: ofdmframesync_execute_seekplcp(_q); break; case OFDMFRAMESYNC_STATE_PLCPSHORT0: ofdmframesync_execute_S0a(_q); break; case OFDMFRAMESYNC_STATE_PLCPSHORT1: ofdmframesync_execute_S0b(_q); break; case OFDMFRAMESYNC_STATE_PLCPLONG: ofdmframesync_execute_S1(_q); break; case OFDMFRAMESYNC_STATE_RXSYMBOLS: ofdmframesync_execute_rxsymbols(_q); break; default:; } } // for (i=0; i<_n; i++) return LIQUID_OK; } // ofdmframesync_execute() // get receiver RSSI float ofdmframesync_get_rssi(ofdmframesync _q) { return -10.0f*log10(_q->g0); } // get receiver carrier frequency offset estimate float ofdmframesync_get_cfo(ofdmframesync _q) { return nco_crcf_get_frequency(_q->nco_rx); } // set receiver carrier frequency offset estimate int ofdmframesync_set_cfo(ofdmframesync _q, float _cfo) { return nco_crcf_set_frequency(_q->nco_rx, _cfo); } // // internal methods // // frame detection int ofdmframesync_execute_seekplcp(ofdmframesync _q) { _q->timer++; if (_q->timer < _q->M) return LIQUID_OK; // reset timer _q->timer = 0; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate gain unsigned int i; // start with a reasonably small number to avoid division by zero float g = 1.0e-9f; for (i=_q->cp_len; i<_q->M + _q->cp_len; i++) { // compute |rc[i]|^2 efficiently g += crealf(rc[i])*crealf(rc[i]) + cimagf(rc[i])*cimagf(rc[i]); } g = (float)(_q->M) / g; #if OFDMFRAMESYNC_ENABLE_SQUELCH // TODO : squelch here if ( -10*log10f( sqrtf(g) ) < _q->squelch_threshold && _q->squelch_enabled) { printf("squelch\n"); return LIQUID_OK; } #endif // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0a); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0a, &s_hat); s_hat *= g; float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); #if DEBUG_OFDMFRAMESYNC_PRINT printf(" - gain=%12.3f, rssi=%12.8f, s_hat=%12.4f <%12.8f>, tau_hat=%8.3f\n", sqrt(g), -10*log10(g), cabsf(s_hat), cargf(s_hat), tau_hat); #endif // save gain (permits dynamic invocation of get_rssi() method) _q->g0 = g; // if (cabsf(s_hat) > _q->plcp_detect_thresh) { int dt = (int)roundf(tau_hat); // set timer appropriately... _q->timer = (_q->M + dt) % (_q->M2); _q->timer += _q->M; // add delay to help ensure good S0 estimate _q->state = OFDMFRAMESYNC_STATE_PLCPSHORT0; #if DEBUG_OFDMFRAMESYNC_PRINT printf("********** frame detected! ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); printf(" dt : %12d\n", dt); printf(" timer : %12u\n", _q->timer); #endif } return LIQUID_OK; } // frame detection int ofdmframesync_execute_S0a(ofdmframesync _q) { //printf("t : %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return LIQUID_OK; // reset timer _q->timer = 0; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // TODO : re-estimate nominal gain // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0a); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0a, &s_hat); s_hat *= _q->g0; _q->s_hat_0 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[0] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); #endif #if 0 // TODO : also check for phase of s_hat (should be small) if (cabsf(s_hat) < 0.3f) { // false alarm #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[0]\n"); #endif ofdmframesync_reset(_q); return; } #endif _q->state = OFDMFRAMESYNC_STATE_PLCPSHORT1; return LIQUID_OK; } // frame detection int ofdmframesync_execute_S0b(ofdmframesync _q) { //printf("t = %u\n", _q->timer); _q->timer++; if (_q->timer < _q->M2) return LIQUID_OK; // reset timer _q->timer = _q->M + _q->cp_len - _q->backoff; // float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S0 gain ofdmframesync_estimate_gain_S0(_q, &rc[_q->cp_len], _q->G0b); float complex s_hat; ofdmframesync_S0_metrics(_q, _q->G0b, &s_hat); s_hat *= _q->g0; _q->s_hat_1 = s_hat; #if DEBUG_OFDMFRAMESYNC_PRINT float tau_hat = cargf(s_hat) * (float)(_q->M2) / (2*M_PI); printf("********** S0[1] received ************\n"); printf(" s_hat : %12.8f <%12.8f>\n", cabsf(s_hat), cargf(s_hat)); printf(" tau_hat : %12.8f\n", tau_hat); // new timing offset estimate tau_hat = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); printf(" tau_hat * : %12.8f\n", tau_hat); printf("**********\n"); #endif // re-adjust timer accordingly float tau_prime = cargf(_q->s_hat_0 + _q->s_hat_1) * (float)(_q->M2) / (2*M_PI); _q->timer -= (int)roundf(tau_prime); #if 0 if (cabsf(s_hat) < 0.3f) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("false alarm S0[1]\n"); #endif // false alarm ofdmframesync_reset(_q); return; } #endif unsigned int i; #if 0 float complex g_hat = 0.0f; for (i=0; i<_q->M; i++) g_hat += _q->G0b[i] * conjf(_q->G0a[i]); // compute carrier frequency offset estimate using freq. domain method float nu_hat = 2.0f * cargf(g_hat) / (float)(_q->M); #else // compute carrier frequency offset estimate using ML method float complex t0 = 0.0f; for (i=0; i<_q->M2; i++) { t0 += conjf(rc[i]) * _q->s0[i] * rc[i+_q->M2] * conjf(_q->s0[i+_q->M2]); } float nu_hat = cargf(t0) / (float)(_q->M2); #endif #if DEBUG_OFDMFRAMESYNC_PRINT printf(" nu_hat : %12.8f\n", nu_hat); #endif // set NCO frequency nco_crcf_set_frequency(_q->nco_rx, nu_hat); _q->state = OFDMFRAMESYNC_STATE_PLCPLONG; return LIQUID_OK; } int ofdmframesync_execute_S1(ofdmframesync _q) { _q->timer--; if (_q->timer > 0) return LIQUID_OK; // increment number of symbols observed _q->num_symbols++; // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); // estimate S1 gain // TODO : add backoff in gain estimation ofdmframesync_estimate_gain_S1(_q, &rc[_q->cp_len], _q->G); // compute detector output float complex g_hat = 0.0f; unsigned int i; for (i=0; i<_q->M; i++) { //g_hat += _q->G[(i+1+_q->M)%_q->M]*conjf(_q->G[(i+_q->M)%_q->M]); g_hat += _q->G[(i+1)%_q->M]*conjf(_q->G[i]); } g_hat /= _q->M_S1; // normalize output g_hat *= _q->g0; // rotate by complex phasor relative to timing backoff g_hat *= liquid_cexpjf((float)(_q->backoff)*2.0f*M_PI/(float)(_q->M)); #if DEBUG_OFDMFRAMESYNC_PRINT printf(" g_hat : %12.4f <%12.8f>\n", cabsf(g_hat), cargf(g_hat)); #endif // check conditions for g_hat: // 1. magnitude should be large (near unity) when aligned // 2. phase should be very near zero (time aligned) if (cabsf(g_hat) > _q->plcp_sync_thresh && fabsf(cargf(g_hat)) < 0.1f*M_PI ) { //printf(" acquisition\n"); _q->state = OFDMFRAMESYNC_STATE_RXSYMBOLS; // reset timer _q->timer = _q->M + _q->cp_len + _q->backoff; _q->num_symbols = 0; // normalize gain by subcarriers, apply timing backoff correction float g = (float)(_q->M) / sqrtf(_q->M_pilot + _q->M_data); for (i=0; i<_q->M; i++) { _q->G[i] *= g; // gain due to relative subcarrier allocation _q->G[i] *= _q->B[i]; // timing backoff correction } #if 0 // TODO : choose number of taps more appropriately //unsigned int ntaps = _q->M / 4; unsigned int ntaps = (_q->M < 8) ? 2 : 8; // FIXME : this is by far the most computationally complex part of synchronization ofdmframesync_estimate_eqgain(_q, ntaps); #else unsigned int poly_order = 4; if (poly_order >= _q->M_pilot + _q->M_data) poly_order = _q->M_pilot + _q->M_data - 1; ofdmframesync_estimate_eqgain_poly(_q, poly_order); #endif #if 1 // compute composite gain unsigned int i; for (i=0; i<_q->M; i++) _q->R[i] = _q->B[i] / _q->G[i]; #endif return LIQUID_OK; } // check if we are stuck searching for the S1 symbol if (_q->num_symbols == 16) { #if DEBUG_OFDMFRAMESYNC_PRINT printf("could not find S1 symbol. bailing...\n"); #endif ofdmframesync_reset(_q); } // 'reset' timer (wait another half symbol) _q->timer = _q->M2; return LIQUID_OK; } int ofdmframesync_execute_rxsymbols(ofdmframesync _q) { // wait for timeout _q->timer--; if (_q->timer == 0) { // run fft float complex * rc; windowcf_read(_q->input_buffer, &rc); memmove(_q->x, &rc[_q->cp_len-_q->backoff], (_q->M)*sizeof(float complex)); FFT_EXECUTE(_q->fft); // recover symbol in internal _q->X buffer ofdmframesync_rxsymbol(_q); #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { unsigned int i; for (i=0; i<_q->M; i++) { if (_q->p[i] == OFDMFRAME_SCTYPE_DATA) windowcf_push(_q->debug_framesyms, _q->X[i]); } } #endif // invoke callback if (_q->callback != NULL) { int retval = _q->callback(_q->X, _q->p, _q->M, _q->userdata); if (retval != 0) ofdmframesync_reset(_q); } // reset timer _q->timer = _q->M + _q->cp_len; } return LIQUID_OK; } // compute S0 metrics int ofdmframesync_S0_metrics(ofdmframesync _q, float complex * _G, float complex * _s_hat) { // timing, carrier offset correction unsigned int i; float complex s_hat = 0.0f; // compute timing estimate, accumulate phase difference across // gains on subsequent pilot subcarriers (note that all the odd // subcarriers are NULL) for (i=0; i<_q->M; i+=2) { s_hat += _G[(i+2)%_q->M]*conjf(_G[i]); } s_hat /= _q->M_S0; // normalize output // set output values *_s_hat = s_hat; return LIQUID_OK; } // estimate short sequence gain // _q : ofdmframesync object // _x : input array (time), [size: M x 1] // _G : output gain (freq) int ofdmframesync_estimate_gain_S0(ofdmframesync _q, float complex * _x, float complex * _G) { // move input array into fft input buffer memmove(_q->x, _x, (_q->M)*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // compute gain, ignoring NULL subcarriers unsigned int i; float gain = sqrtf(_q->M_S0) / (float)(_q->M); for (i=0; i<_q->M; i++) { if (_q->p[i] != OFDMFRAME_SCTYPE_NULL && (i%2)==0) { // NOTE : if cabsf(_q->S0[i]) == 0 then we can multiply by conjugate // rather than compute division //_G[i] = _q->X[i] / _q->S0[i]; _G[i] = _q->X[i] * conjf(_q->S0[i]); } else { _G[i] = 0.0f; } // normalize gain _G[i] *= gain; } return LIQUID_OK; } // estimate long sequence gain // _q : ofdmframesync object // _x : input array (time), [size: M x 1] // _G : output gain (freq) int ofdmframesync_estimate_gain_S1(ofdmframesync _q, float complex * _x, float complex * _G) { // move input array into fft input buffer memmove(_q->x, _x, (_q->M)*sizeof(float complex)); // compute fft, storing result into _q->X FFT_EXECUTE(_q->fft); // compute gain, ignoring NULL subcarriers unsigned int i; float gain = sqrtf(_q->M_S1) / (float)(_q->M); for (i=0; i<_q->M; i++) { if (_q->p[i] != OFDMFRAME_SCTYPE_NULL) { // NOTE : if cabsf(_q->S1[i]) == 0 then we can multiply by conjugate // rather than compute division //_G[i] = _q->X[i] / _q->S1[i]; _G[i] = _q->X[i] * conjf(_q->S1[i]); } else { _G[i] = 0.0f; } // normalize gain _G[i] *= gain; } return LIQUID_OK; } #if 0 // estimate complex equalizer gain from G0 and G1 // _q : ofdmframesync object // _ntaps : number of time-domain taps for smoothing int ofdmframesync_estimate_eqgain(ofdmframesync _q, unsigned int _ntaps) { #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // copy pre-smoothed gain memmove(_q->G_hat, _q->G, _q->M*sizeof(float complex)); } #endif // validate input if (_ntaps == 0 || _ntaps > _q->M) return liquid_error(LIQUID_EICONFIG,"ofdmframesync_estimate_eqgain(), ntaps must be in [1,M]"); unsigned int i; // generate smoothing window (fft of temporal window) for (i=0; i<_q->M; i++) _q->x[i] = (i < _ntaps) ? 1.0f : 0.0f; FFT_EXECUTE(_q->fft); memmove(_q->G0a, _q->G, _q->M*sizeof(float complex)); // smooth complex equalizer gains for (i=0; i<_q->M; i++) { // set gain to zero for null subcarriers if (_q->p[i] == OFDMFRAME_SCTYPE_NULL) { _q->G[i] = 0.0f; continue; } float complex w; float complex w0 = 0.0f; float complex G_hat = 0.0f; unsigned int j; for (j=0; j<_q->M; j++) { if (_q->p[j] == OFDMFRAME_SCTYPE_NULL) continue; // select window sample from array w = _q->X[(i + _q->M - j) % _q->M]; // accumulate gain //G_hat += w * 0.5f * (_q->G0a[j] + _q->G0b[j]); G_hat += w * _q->G0a[j]; w0 += w; } // eliminate divide-by-zero issues if (cabsf(w0) < 1e-4f) { liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain(), weighting factor is zero"); w0 = 1.0f; } _q->G[i] = G_hat / w0; } return LIQUID_OK; } #endif // estimate complex equalizer gain from G0 and G1 using polynomial fit // _q : ofdmframesync object // _order : polynomial order int ofdmframesync_estimate_eqgain_poly(ofdmframesync _q, unsigned int _order) { #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // copy pre-smoothed gain memmove(_q->G_hat, _q->G, _q->M*sizeof(float complex)); } #endif // polynomial interpolation unsigned int i; unsigned int N = _q->M_pilot + _q->M_data; if (_order > N-1) _order = N-1; if (_order > 10) _order = 10; float x_freq[N]; float y_abs[N]; float y_arg[N]; float p_abs[_order+1]; float p_arg[_order+1]; unsigned int n=0; unsigned int k; for (i=0; i<_q->M; i++) { // start at mid-point (effective fftshift) k = (i + _q->M2) % _q->M; if (_q->p[k] != OFDMFRAME_SCTYPE_NULL) { if (n == N) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // store resulting... x_freq[n] = (k > _q->M2) ? (float)k - (float)(_q->M) : (float)k; x_freq[n] = x_freq[n] / (float)(_q->M); y_abs[n] = cabsf(_q->G[k]); y_arg[n] = cargf(_q->G[k]); // update counter n++; } } if (n != N) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase liquid_unwrap_phase(y_arg, N); // fit to polynomial polyf_fit(x_freq, y_abs, N, p_abs, _order+1); polyf_fit(x_freq, y_arg, N, p_arg, _order+1); // compute subcarrier gain for (i=0; i<_q->M; i++) { float freq = (i > _q->M2) ? (float)i - (float)(_q->M) : (float)i; freq = freq / (float)(_q->M); float A = polyf_val(p_abs, _order+1, freq); float theta = polyf_val(p_arg, _order+1, freq); _q->G[i] = (_q->p[i] == OFDMFRAME_SCTYPE_NULL) ? 0.0f : A * liquid_cexpjf(theta); } #if 0 for (i=0; iM; i++) _q->X[i] *= _q->R[i]; // polynomial curve-fit float x_phase[_q->M_pilot]; float y_phase[_q->M_pilot]; float p_phase[2]; unsigned int n=0; unsigned int k; float complex pilot = 1.0f; for (i=0; i<_q->M; i++) { // start at mid-point (effective fftshift) k = (i + _q->M2) % _q->M; if (_q->p[k]==OFDMFRAME_SCTYPE_PILOT) { if (n == _q->M_pilot) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); pilot = (msequence_advance(_q->ms_pilot) ? 1.0f : -1.0f); #if 0 printf("pilot[%3u] = %12.4e + j*%12.4e (expected %12.4e + j*%12.4e)\n", k, crealf(_q->X[k]), cimagf(_q->X[k]), crealf(pilot), cimagf(pilot)); #endif // store resulting... x_phase[n] = (k > _q->M2) ? (float)k - (float)(_q->M) : (float)k; y_phase[n] = cargf(_q->X[k]*conjf(pilot)); // update counter n++; } } if (n != _q->M_pilot) return liquid_error(LIQUID_EINT,"ofdmframesync_estimate_eqgain_poly(), pilot subcarrier mismatch"); // try to unwrap phase liquid_unwrap_phase(y_phase, _q->M_pilot); // fit phase to 1st-order polynomial (2 coefficients) polyf_fit(x_phase, y_phase, _q->M_pilot, p_phase, 2); // filter slope estimate (timing offset) float alpha = 0.3f; p_phase[1] = alpha*p_phase[1] + (1-alpha)*_q->p1_prime; _q->p1_prime = p_phase[1]; #if DEBUG_OFDMFRAMESYNC if (_q->debug_enabled) { // save pilots memmove(_q->px, x_phase, _q->M_pilot*sizeof(float)); memmove(_q->py, y_phase, _q->M_pilot*sizeof(float)); // NOTE : swapping values for octave _q->p_phase[0] = p_phase[1]; _q->p_phase[1] = p_phase[0]; windowf_push(_q->debug_pilot_0, p_phase[0]); windowf_push(_q->debug_pilot_1, p_phase[1]); } #endif // compensate for phase offset // TODO : find more computationally efficient way to do this for (i=0; i<_q->M; i++) { // only apply to data/pilot subcarriers if (_q->p[i] == OFDMFRAME_SCTYPE_NULL) { _q->X[i] = 0.0f; } else { float fx = (i > _q->M2) ? (float)i - (float)(_q->M) : (float)i; float theta = polyf_val(p_phase, 2, fx); _q->X[i] *= liquid_cexpjf(-theta); } } // adjust NCO frequency based on differential phase if (_q->num_symbols > 0) { // compute phase error (unwrapped) float dphi_prime = p_phase[0] - _q->phi_prime; while (dphi_prime > M_PI) dphi_prime -= M_2_PI; while (dphi_prime < -M_PI) dphi_prime += M_2_PI; // adjust NCO proportionally to phase error nco_crcf_adjust_frequency(_q->nco_rx, 1e-3f*dphi_prime); } // set internal phase state _q->phi_prime = p_phase[0]; //printf("%3u : theta : %12.8f, nco freq: %12.8f\n", _q->num_symbols, p_phase[0], nco_crcf_get_frequency(_q->nco_rx)); // increment symbol counter _q->num_symbols++; #if 0 for (i=0; i<_q->M_pilot; i++) printf("x_phase(%3u) = %12.8f; y_phase(%3u) = %12.8f;\n", i+1, x_phase[i], i+1, y_phase[i]); printf("poly : p0=%12.8f, p1=%12.8f\n", p_phase[0], p_phase[1]); #endif return LIQUID_OK; } // enable debugging int ofdmframesync_debug_enable(ofdmframesync _q) { // create debugging objects if necessary #if DEBUG_OFDMFRAMESYNC if (_q->debug_objects_created) return LIQUID_OK; _q->debug_x = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_rssi = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_framesyms = windowcf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->G_hat = (float complex*) malloc((_q->M)*sizeof(float complex)); _q->px = (float*) malloc((_q->M_pilot)*sizeof(float)); _q->py = (float*) malloc((_q->M_pilot)*sizeof(float)); _q->debug_pilot_0 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_pilot_1 = windowf_create(DEBUG_OFDMFRAMESYNC_BUFFER_LEN); _q->debug_enabled = 1; _q->debug_objects_created = 1; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_enable(): compile-time debugging disabled"); #endif } int ofdmframesync_debug_disable(ofdmframesync _q) { // disable debugging #if DEBUG_OFDMFRAMESYNC _q->debug_enabled = 0; return LIQUID_OK; #else return liquid_error(LIQUID_EICONFIG,"ofdmframesync_debug_disable(): compile-time debugging disabled"); #endif } int ofdmframesync_debug_print(ofdmframesync _q, const char * _filename) { #if DEBUG_OFDMFRAMESYNC if (!_q->debug_objects_created) return liquid_error(LIQUID_EICONFIG,"ofdmframe_debug_print(), debugging objects don't exist; enable debugging first"); FILE * fid = fopen(_filename,"w"); if (fid==NULL) return liquid_error(LIQUID_EIO,"ofdmframe_debug_print(), could not open '%s' for writing", _filename); fprintf(fid,"%% %s : auto-generated file\n", DEBUG_OFDMFRAMESYNC_FILENAME); fprintf(fid,"close all;\n"); fprintf(fid,"clear all;\n"); fprintf(fid,"n = %u;\n", DEBUG_OFDMFRAMESYNC_BUFFER_LEN); fprintf(fid,"M = %u;\n", _q->M); fprintf(fid,"M_null = %u;\n", _q->M_null); fprintf(fid,"M_pilot = %u;\n", _q->M_pilot); fprintf(fid,"M_data = %u;\n", _q->M_data); unsigned int i; float complex * rc; float * r; // save subcarrier allocation fprintf(fid,"p = zeros(1,M);\n"); for (i=0; i<_q->M; i++) fprintf(fid,"p(%4u) = %d;\n", i+1, _q->p[i]); fprintf(fid,"i_null = find(p==%d);\n", OFDMFRAME_SCTYPE_NULL); fprintf(fid,"i_pilot = find(p==%d);\n", OFDMFRAME_SCTYPE_PILOT); fprintf(fid,"i_data = find(p==%d);\n", OFDMFRAME_SCTYPE_DATA); // short, long, training sequences for (i=0; i<_q->M; i++) { fprintf(fid,"S0(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S0[i]), cimagf(_q->S0[i])); fprintf(fid,"S1(%4u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); } fprintf(fid,"x = zeros(1,n);\n"); windowcf_read(_q->debug_x, &rc); for (i=0; iM; i++) fprintf(fid,"s1(%3u) = %12.4e + j*%12.4e;\n", i+1, crealf(_q->s1[i]), cimagf(_q->s1[i])); // write agc_rssi fprintf(fid,"\n\n"); fprintf(fid,"agc_rssi = zeros(1,%u);\n", DEBUG_OFDMFRAMESYNC_BUFFER_LEN); windowf_read(_q->debug_rssi, &r); for (i=0; iM; i++) { fprintf(fid,"S0(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->S0[i]), cimagf(_q->S0[i])); fprintf(fid,"S1(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->S1[i]), cimagf(_q->S1[i])); } // write gain arrays fprintf(fid,"\n\n"); fprintf(fid,"G0 = zeros(1,M);\n"); fprintf(fid,"G1 = zeros(1,M);\n"); fprintf(fid,"G_hat = zeros(1,M);\n"); fprintf(fid,"G = zeros(1,M);\n"); for (i=0; i<_q->M; i++) { fprintf(fid,"G0(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G0a[i]), cimagf(_q->G0a[i])); fprintf(fid,"G1(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G0b[i]), cimagf(_q->G0b[i])); fprintf(fid,"G_hat(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G_hat[i]),cimagf(_q->G_hat[i])); fprintf(fid,"G(%3u) = %12.8f + j*%12.8f;\n", i+1, crealf(_q->G[i]), cimagf(_q->G[i])); } fprintf(fid,"f = [0:(M-1)];\n"); fprintf(fid,"figure;\n"); fprintf(fid,"subplot(2,1,1);\n"); fprintf(fid," plot(f, fftshift(abs(G_hat)),'sb',...\n"); fprintf(fid," f, fftshift(abs(G)),'-k','LineWidth',2);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('gain estimate (mag)');\n"); fprintf(fid,"subplot(2,1,2);\n"); fprintf(fid," plot(f, fftshift(arg(G_hat).*[abs(G0) > 1e-3]),'sb',...\n"); fprintf(fid," f, fftshift(arg(G)),'-k','LineWidth',2);\n"); fprintf(fid," grid on;\n"); fprintf(fid," xlabel('subcarrier index');\n"); fprintf(fid," ylabel('gain estimate (phase)');\n"); // write pilot response fprintf(fid,"\n\n"); fprintf(fid,"px = zeros(1,M_pilot);\n"); fprintf(fid,"py = zeros(1,M_pilot);\n"); for (i=0; i<_q->M_pilot; i++) { fprintf(fid,"px(%3u) = %12.8f;\n", i+1, _q->px[i]); fprintf(fid,"py(%3u) = %12.8f;\n", i+1, _q->py[i]); } fprintf(fid,"p_phase(1) = %12.8f;\n", _q->p_phase[0]); fprintf(fid,"p_phase(2) = %12.8f;\n", _q->p_phase[1]); // save pilot history fprintf(fid,"p0 = zeros(1,M);\n"); windowf_read(_q->debug_pilot_0, &r); for (i=0; idebug_pilot_1, &r); for (i=0; idebug_framesyms, &rc); for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // Helper function to keep code base small void firpfbch2_crcf_runtest(unsigned int _M, unsigned int _m, float _as) { float tol = 1e-3f; unsigned int i; // derived values unsigned int num_symbols = 8*_m; // number of symbols unsigned int num_samples = _M * num_symbols; // allocate arrays float complex x[num_samples]; float complex y[num_samples]; // generate pseudo-random sequence unsigned int s = 1; // seed unsigned int p = 524287; // large prime number unsigned int g = 1031; // another large prime number for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: validate analysis correctness // void autotest_firpfbch_crcf_analysis() { float tol = 1e-4f; // error tolerance unsigned int num_channels=4; // number of channels unsigned int p=5; // filter length (symbols) unsigned int num_symbols=40; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence. // For the sake of consistency, use pseudo-random values // chosen from m-sequences unsigned int h_len = p*num_channels; float h[h_len]; msequence ms = msequence_create_default(6); for (i=0; i #include "autotest/autotest.h" #include "liquid.h" void autotest_firpfbch_crcf_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping firpfbch_crcf config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check invalid function calls CONTEND_ISNULL(firpfbch_crcf_create( 77, 76, 12, NULL)) // invalid type CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 0, 12, NULL)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create(LIQUID_ANALYZER, 76, 0, NULL)) // invalid filter semi-length CONTEND_ISNULL(firpfbch_crcf_create_kaiser( 77, 76, 12, 60.0f)) // invalid type CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 0, 12, 60.0f)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 0, 60.0f)) // invalid filter semi-length CONTEND_ISNULL(firpfbch_crcf_create_rnyquist( 77, 76, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid type CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 0, 12, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid number of channels CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 0, 0.2f, LIQUID_FIRFILT_ARKAISER)) // invalid filter semi-length CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 77.f, LIQUID_FIRFILT_ARKAISER)) // invalid filter excess bandwidth CONTEND_ISNULL(firpfbch_crcf_create_rnyquist(LIQUID_ANALYZER, 76, 12, 0.2f, LIQUID_FIRFILT_UNKNOWN )) // invalid filter type //CONTEND_ISNULL(firpfbch_crcf_copy(NULL)) // create proper object and test configurations firpfbch_crcf q = firpfbch_crcf_create_kaiser(LIQUID_ANALYZER, 76, 12, 60.0f); CONTEND_EQUALITY(LIQUID_OK, firpfbch_crcf_print(q)) firpfbch_crcf_destroy(q); } liquid-dsp-1.7.0/src/multichannel/tests/firpfbch_crcf_synthesizer_autotest.c000066400000000000000000000112631474751757600275630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: validate synthesis correctness // void autotest_firpfbch_crcf_synthesis() { // options float tol = 1e-4f; // error tolerance unsigned int num_channels=4; // number of channels unsigned int p=5; // filter length (symbols) unsigned int num_symbols=40; // number of symbols // derived values unsigned int num_samples = num_channels * num_symbols; unsigned int i; unsigned int j; // generate filter // NOTE : these coefficients can be random; the purpose of this // exercise is to demonstrate mathematical equivalence. // For the sake of consistency, use pseudo-random values // chosen from m-sequences unsigned int h_len = p*num_channels; float h[h_len]; msequence ms = msequence_create_default(6); for (i=0; i #include "autotest/autotest.h" #include "liquid.h" void autotest_firpfbchr_crcf() { // options unsigned int M = 16; // number of channels unsigned int P = 6; // output decimation rate unsigned int m = 12; // filter semi-length (symbols) unsigned int num_blocks=1<<16; // number of symbols float As = 60.0f; // filter stop-band attenuation // create filterbank objects from prototype firpfbchr_crcf qa = firpfbchr_crcf_create_kaiser(M, P, m, As); firpfbchr_crcf_print(qa); // create multi-signal source generator msourcecf gen = msourcecf_create_default(); // add signals (gen, fc, bw, gain, {options}) msourcecf_add_noise(gen, 0.00f, 1.00f, -60); // wide-band noise msourcecf_add_noise(gen, -0.30f, 0.10f, -20); // narrow-band noise msourcecf_add_noise(gen, 0.08f, 0.01f, -30); // very narrow-band noise // modulated data msourcecf_add_modem(gen, 0.1875f, // center frequency 0.065f, // bandwidth (symbol rate) -20, // gain LIQUID_MODEM_QPSK, // modulation scheme 12, // filter semi-length 0.3f); // modem parameters // create spectral periodogoram unsigned int nfft = 2400; spgramcf p0 = spgramcf_create_default(nfft); spgramcf c1 = spgramcf_create_default(nfft); spgramcf c3 = spgramcf_create_default(nfft); // run channelizer float complex buf_0[P]; float complex buf_1[M]; unsigned int i; for (i=0; i #include #include #include #include #include #include "autotest/autotest.h" #include "liquid.h" // internal callback // _X : subcarrier symbols // _p : subcarrier allocation // _M : number of subcarriers // _userdata : user-defined data structure int ofdmframesync_autotest_callback(float complex * _X, unsigned char * _p, unsigned int _M, void * _userdata) { if (liquid_autotest_verbose) printf("******** callback invoked!\n"); // type cast _userdata as complex float array float complex * X = (float complex *)_userdata; // copy values and return memmove(X, _X, _M*sizeof(float complex)); // return return 0; } // Helper function to keep code base small // _num_subcarriers : number of subcarriers // _cp_len : cyclic prefix length // _taper_len : taper length void ofdmframesync_acquire_test(unsigned int _num_subcarriers, unsigned int _cp_len, unsigned int _taper_len) { // options unsigned int M = _num_subcarriers; // number of subcarriers unsigned int cp_len = _cp_len; // cyclic prefix length unsigned int taper_len = _taper_len; // taper length float tol = 1e-2f; // error tolerance // float dphi = 1.0f / (float)M; // carrier frequency offset // subcarrier allocation (initialize to default) unsigned char p[M]; ofdmframe_init_default_sctype(M, p); // derived values unsigned int num_samples = (3 + 1)*(M + cp_len); // create synthesizer/analyzer objects ofdmframegen fg = ofdmframegen_create(M, cp_len, taper_len, p); //ofdmframegen_print(fg); float complex X[M]; // original data sequence float complex X_test[M]; // recovered data sequence ofdmframesync fs = ofdmframesync_create(M,cp_len,taper_len,p,ofdmframesync_autotest_callback,(void*)X_test); unsigned int i; float complex y[num_samples]; // frame samples // assemble full frame unsigned int n=0; // write first S0 symbol ofdmframegen_write_S0a(fg, &y[n]); n += M + cp_len; // write second S0 symbol ofdmframegen_write_S0b(fg, &y[n]); n += M + cp_len; // write S1 symbol ofdmframegen_write_S1( fg, &y[n]); n += M + cp_len; // generate data symbol (random) for (i=0; i #include #include "liquid.h" void benchmark_nco_sincos(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float s, c; nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i; // increase number of iterations for NCO *_num_iterations *= 100; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { nco_crcf_sincos(p, &s, &c); nco_crcf_step(p); } getrusage(RUSAGE_SELF, _finish); nco_crcf_destroy(p); } void benchmark_nco_mix_up(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float complex x[16], y[16]; memset(x, 0, 16*sizeof(float complex)); nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i, j; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { for (j=0; j<16; j++) { nco_crcf_mix_up(p, x[j], &y[j]); nco_crcf_step(p); } } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 16; nco_crcf_destroy(p); } void benchmark_nco_mix_block_up(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float complex x[16], y[16]; memset(x, 0, 16*sizeof(float complex)); nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { nco_crcf_mix_block_up(p, x, y, 16); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 16; nco_crcf_destroy(p); } liquid-dsp-1.7.0/src/nco/bench/vco_benchmark.c000066400000000000000000000057171474751757600212250ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" void benchmark_vco_sincos(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float s, c; nco_crcf p = nco_crcf_create(LIQUID_VCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { nco_crcf_sincos(p, &s, &c); nco_crcf_step(p); } getrusage(RUSAGE_SELF, _finish); nco_crcf_destroy(p); } void benchmark_vco_mix_up(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float complex x[16], y[16]; memset(x, 0, 16*sizeof(float complex)); nco_crcf p = nco_crcf_create(LIQUID_VCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i, j; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { for (j=0; j<16; j++) { nco_crcf_mix_up(p, x[j], &y[j]); nco_crcf_step(p); } } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 16; nco_crcf_destroy(p); } void benchmark_vco_mix_block_up(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { float complex x[16], y[16]; memset(x, 0, 16*sizeof(float complex)); nco_crcf p = nco_crcf_create(LIQUID_VCO); nco_crcf_set_phase(p, 0.0f); nco_crcf_set_frequency(p, 0.1f); unsigned int i; getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { nco_crcf_mix_block_up(p, x, y, 16); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 16; nco_crcf_destroy(p); } liquid-dsp-1.7.0/src/nco/src/000077500000000000000000000000001474751757600157565ustar00rootroot00000000000000liquid-dsp-1.7.0/src/nco/src/nco.proto.c000066400000000000000000000601661474751757600200540ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Numerically-controlled oscillator (nco) with internal phase-locked // loop (pll) implementation // #include #include #include #include #include #include #define NCO_STATIC_LUT_WORDBITS 32 #define NCO_STATIC_LUT_NBITS 10 #define NCO_STATIC_LUT_SIZE (1LLU << NCO_STATIC_LUT_NBITS) #define NCO_STATIC_LUT_HSIZE (NCO_STATIC_LUT_SIZE >> 1) #define NCO_STATIC_LUT_QSIZE (NCO_STATIC_LUT_SIZE >> 2) #define NCO_STATIC_LUT_INDEX_SHIFTED_PI2(index) \ (((index) + NCO_STATIC_LUT_QSIZE) & (NCO_STATIC_LUT_SIZE-1)) #define NCO_STATIC_LUT_THETA_SHIFTED_PI2(theta) \ ((theta) + (1LLU << (NCO_STATIC_LUT_WORDBITS - 2))) #define NCO_STATIC_LUT_THETA_ACCUM(theta) \ ((uint32_t)(theta & ((1LLU << (NCO_STATIC_LUT_WORDBITS-NCO_STATIC_LUT_NBITS))-1))) #define NCO_PLL_BANDWIDTH_DEFAULT (0.1) #define NCO_PLL_GAIN_DEFAULT (1000) #define LIQUID_DEBUG_NCO (0) struct vco_tab_e_s { T value, skew; }; typedef struct vco_tab_e_s vco_tab_e; struct NCO(_s) { liquid_ncotype type; // NCO type (e.g. LIQUID_VCO) // type == LIQUID_NCO, LIQUID_VCO_INTERP uint32_t theta; // 32-bit phase [radians] uint32_t d_theta; // 32-bit frequency [radians/sample] // type == LIQUID_NCO T* nco_sintab; // sine look-up table // type == LIQUID_VCO_INTERP vco_tab_e* vcoi_sintab; // sine interpolated look-up table // type == LIQUID_VCO_DIRECT int vcod_n; // normalized multiplier coefficient unsigned int vcod_m; // normalized divider coefficient T* vcod_sintab; // sine direct look-up table T* vcod_costab; // cosine direct look-up table unsigned int vcod_index; // direct look-up index [0, m) // phase-locked loop T alpha; // frequency proportion T beta; // phase proportion }; // reset internal phase-locked loop filter int NCO(_pll_reset)(NCO() _q); /* constrain phase (or frequency) and convert to fixed-point */ uint32_t NCO(_constrain)(T _theta); /* utilities used with type LIQUID_VCO_DIRECT */ void NCO(_constrain_vcod)(int *_n, unsigned int *_m); /* utilities used with types LIQUID_VCO_* */ T NCO(_fp_sin)(T x); T NCO(_fp_cos)(T x); // compute index for sine/cosine look-up table unsigned int NCO(_static_index)(NCO() _q); // create nco/vco object NCO() NCO(_create)(liquid_ncotype _type) { NCO() q = (NCO()) malloc(sizeof(struct NCO(_s))); q->type = _type; // initialize sine/cosine tables unsigned int i; switch (q->type) { case LIQUID_NCO: { q->vcoi_sintab = NULL; q->vcod_sintab = NULL; q->vcod_costab = NULL; q->nco_sintab = (T*)malloc(NCO_STATIC_LUT_SIZE*sizeof(T)); for (i=0; inco_sintab[i] = SIN(TIL(2)*TFL(M_PI)*(T)(i)/(T)(NCO_STATIC_LUT_SIZE)); break; } case LIQUID_VCO_INTERP: { q->nco_sintab = NULL; q->vcod_sintab = NULL; q->vcod_costab = NULL; q->vcoi_sintab = (vco_tab_e*)malloc(NCO_STATIC_LUT_SIZE*sizeof(vco_tab_e)); /* Calculate only [0, PI/2] range and mirror it to [PI, 3*PI/2] range * (in single forward iteration, i.e. "sine" direction) */ uint32_t theta = 0; const int32_t d_theta = (uint32_t)(UINT32_MAX)/NCO_STATIC_LUT_SIZE; unsigned int i; for (i=0; ivcoi_sintab[i].value = value; q->vcoi_sintab[i].skew = skew; q->vcoi_sintab[i+NCO_STATIC_LUT_HSIZE].value = -value; q->vcoi_sintab[i+NCO_STATIC_LUT_HSIZE].skew = -skew; theta += d_theta; } q->vcoi_sintab[NCO_STATIC_LUT_QSIZE].value = TIL(1); q->vcoi_sintab[NCO_STATIC_LUT_QSIZE].skew = - q->vcoi_sintab[NCO_STATIC_LUT_QSIZE-1].skew; q->vcoi_sintab[NCO_STATIC_LUT_QSIZE+NCO_STATIC_LUT_HSIZE].value = - q->vcoi_sintab[NCO_STATIC_LUT_QSIZE].value; q->vcoi_sintab[NCO_STATIC_LUT_QSIZE+NCO_STATIC_LUT_HSIZE].skew = q->vcoi_sintab[NCO_STATIC_LUT_QSIZE-1].skew; /* Mirror [0, PI/2], [PI, 3*PI/2] ranges to [PI/2, PI], [3*PI/2, 2*PI] * (in single backward iteration, i.e. "cosine" direction) */ for (i=1; ivcoi_sintab[NCO_STATIC_LUT_QSIZE - i].value; T skew = q->vcoi_sintab[NCO_STATIC_LUT_QSIZE - i - 1].skew; q->vcoi_sintab[i_pi2].value = value; q->vcoi_sintab[i_pi2].skew = -skew; q->vcoi_sintab[i_pi2 + NCO_STATIC_LUT_HSIZE].value = -value; q->vcoi_sintab[i_pi2 + NCO_STATIC_LUT_HSIZE].skew = skew; } break; } case LIQUID_VCO_DIRECT: { q->nco_sintab = NULL; q->vcoi_sintab = NULL; q->vcod_sintab = NULL; q->vcod_costab = NULL; break; } default: return liquid_error_config("nco_%s_create(), unknown type : %u\n", EXTENSION, q->type); } // set default pll bandwidth NCO(_pll_set_bandwidth)(q, NCO_PLL_BANDWIDTH_DEFAULT); // reset object and return NCO(_reset)(q); return q; } // copy object NCO() NCO(_copy)(NCO() q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("nco_%s_copy(), object cannot be NULL", EXTENSION); // allocate new object, copy main component memory NCO() q_copy = (NCO()) malloc(sizeof(struct NCO(_s))); memmove(q_copy, q_orig, sizeof(struct NCO(_s))); // re-allocate arrays as needed switch (q_copy->type) { case LIQUID_NCO: q_copy->nco_sintab = (T *) liquid_malloc_copy(q_orig->nco_sintab, NCO_STATIC_LUT_SIZE, sizeof(T)); break; case LIQUID_VCO_INTERP: q_copy->vcoi_sintab = (vco_tab_e *) liquid_malloc_copy(q_orig->vcoi_sintab, NCO_STATIC_LUT_SIZE, sizeof(vco_tab_e)); break; case LIQUID_VCO_DIRECT: break; default: return liquid_error_config("nco_%s_copy(), unknown type: %u", q_copy->type, EXTENSION); } return q_copy; } // destroy nco object int NCO(_destroy)(NCO() _q) { if (_q==NULL) return liquid_error(LIQUID_EIOBJ,"nco_%s_destroy(), object is null", EXTENSION); switch (_q->type) { case LIQUID_NCO: free(_q->nco_sintab); break; case LIQUID_VCO_INTERP: free(_q->vcoi_sintab); break; case LIQUID_VCO_DIRECT: free(_q->vcod_sintab); free(_q->vcod_costab); break; default: break; } free(_q); return LIQUID_OK; } // Print nco object internals to stdout int NCO(_print)(NCO() _q) { printf("type) { case LIQUID_NCO: printf(", type=\"nco\""); break; case LIQUID_VCO_INTERP: case LIQUID_VCO_DIRECT: printf(", type=\"vco\""); break; default:; } printf(", phase=0x%.8x", _q->theta); printf(", freq=0x%.8x", _q->d_theta); printf(">\n"); #if 0 // print entire table(s) unsigned int i; switch (_q->type) { case LIQUID_NCO: for (i=0; inco_sintab[i]); break; case LIQUID_VCO_INTERP: for (i=0; ivcoi_sintab[i].value, _q->vcoi_sintab[i].skew); break; case LIQUID_VCO_DIRECT: for (i=0; i<_q->vcod_m; i++) printf(" [%10u] sintab[] = %16.12f costab[] = %16.12f\n", i, _q->vcod_sintab[i], _q->vcod_costab[i]); break; default: break; } #endif return LIQUID_OK; } // reset internal state of nco object int NCO(_reset)(NCO() _q) { switch (_q->type) { case LIQUID_NCO: case LIQUID_VCO_INTERP: // reset phase and frequency states _q->theta = 0; _q->d_theta = 0; break; case LIQUID_VCO_DIRECT: NCO(_set_vcodirect_frequency)(_q, 0, 0); break; default: break; } // reset pll filter state return NCO(_pll_reset)(_q); } // set frequency of nco object int NCO(_set_frequency)(NCO() _q, T _dtheta) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"nco_set_frequency(), " "cannot be used with object type == LIQUID_VCO_DIRECT"); } _q->d_theta = NCO(_constrain)(_dtheta); return LIQUID_OK; } // adjust frequency of nco object int NCO(_adjust_frequency)(NCO() _q, T _df) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"nco_adjust_frequency(), " "cannot be used with object type == LIQUID_VCO_DIRECT"); } _q->d_theta += NCO(_constrain)(_df); return LIQUID_OK; } // set phase of nco object, constraining phase int NCO(_set_phase)(NCO() _q, T _phi) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"error: nco_set_phase(), " "cannot be used with object type == LIQUID_VCO_DIRECT\n"); } _q->theta = NCO(_constrain)(_phi); return LIQUID_OK; } // adjust phase of nco object, constraining phase int NCO(_adjust_phase)(NCO() _q, T _dphi) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"error: nco_adjust_phase(), " "cannot be used with object type == LIQUID_VCO_DIRECT"); } _q->theta += NCO(_constrain)(_dphi); return LIQUID_OK; } // increment internal phase of nco object int NCO(_step)(NCO() _q) { if ((_q->type == LIQUID_NCO) || (_q->type == LIQUID_VCO_INTERP)) { _q->theta += _q->d_theta; } else if (_q->type == LIQUID_VCO_DIRECT) { (_q->vcod_index)++; if (_q->vcod_index == _q->vcod_m) _q->vcod_index = 0; } return LIQUID_OK; } // get phase [radians] T NCO(_get_phase)(NCO() _q) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"error: nco_get_phase(), " "cannot be used with object type == LIQUID_VCO_DIRECT"); } return TIL(2)*TFL(M_PI)*(T)_q->theta / (T)(1LLU<<32); } // get frequency [radians/sample] T NCO(_get_frequency)(NCO() _q) { if (_q->type == LIQUID_VCO_DIRECT) { return liquid_error(LIQUID_EICONFIG,"nco_%s_get_frequency(), cannot be used with object type == LIQUID_VCO_DIRECT", EXTENSION); } T d_theta = TIL(2)*TFL(M_PI)*(T)_q->d_theta / (T)(1LLU<<32); return d_theta > TFL(M_PI) ? d_theta - TIL(2)*TFL(M_PI) : d_theta; } // get frequency of LIQUID_VCO_DIRECT object // [fraction defined by normalized multiplier and divider coefficients] void NCO(_get_vcodirect_frequency)(NCO() _q, int* _n, unsigned int* _m) { if (_q->type != LIQUID_VCO_DIRECT) { liquid_error(LIQUID_EICONFIG, "nco_%s_get_vcodirect_frequency(), cannot be used with object type == LIQUID_VCO_DIRECT", EXTENSION); return; } *_n = _q->vcod_n; *_m = _q->vcod_m; } // set frequency of LIQUID_VCO_DIRECT object // [fraction defined by multiplier and divider coefficients] void NCO(_set_vcodirect_frequency)(NCO() _q, int _n, unsigned int _m) { if (_q->type != LIQUID_VCO_DIRECT) { liquid_error(LIQUID_EICONFIG, "nco_%s_set_vcodirect_frequency(), cannot be used with object type == LIQUID_VCO_DIRECT", EXTENSION); return; } free(_q->vcod_sintab); free(_q->vcod_costab); _q->vcod_index = 0; NCO(_constrain_vcod)(&_n, &_m); if ((_n != 0) && (_m > 0)) { _q->vcod_n = _n; _q->vcod_m = _m; _q->vcod_sintab = (T*)malloc(_q->vcod_m*sizeof(T)); _q->vcod_costab = (T*)malloc(_q->vcod_m*sizeof(T)); const int32_t d_theta = (int32_t)((double)(UINT32_MAX) * (double)(_q->vcod_n)/(double)(_q->vcod_m)); /* Calculate both sine and cosine values * over 'n' integral periods within 'm' count * constraining theta argument to [0, PI/2) range */ static const uint32_t VALUE_PI_2 = (1ULL << 30); static const uint32_t VALUE_PI = (1ULL << 31); uint32_t theta = 0; unsigned int i; for (i=0; i<_q->vcod_m; i++) { uint32_t theta_pi2 = theta % VALUE_PI_2; T sin_theta_pi2 = NCO(_fp_sin)(theta_pi2); T cos_theta_pi2 = NCO(_fp_cos)(theta_pi2); if ((theta % VALUE_PI) < VALUE_PI_2) _q->vcod_sintab[i] = sin_theta_pi2; else _q->vcod_sintab[i] = cos_theta_pi2; if (theta > VALUE_PI) _q->vcod_sintab[i] *= TIL(-1); if (((theta - VALUE_PI_2) % VALUE_PI) >= VALUE_PI_2) _q->vcod_costab[i] = cos_theta_pi2; else _q->vcod_costab[i] = sin_theta_pi2; if ((theta - VALUE_PI_2) <= VALUE_PI) _q->vcod_costab[i] *= TIL(-1); theta += d_theta; } } else { /* Use constant single-element sine/cosine table * in order to optimize indexed access */ _q->vcod_n = 0; _q->vcod_m = 1; _q->vcod_sintab = (T*)malloc(sizeof(T)); _q->vcod_costab = (T*)malloc(sizeof(T)); _q->vcod_sintab[0] = TIL(0); _q->vcod_costab[0] = TIL(1); } } // compute sine, cosine internally T NCO(_sin)(NCO() _q) { T value = TIL(0); if ((_q->type == LIQUID_NCO) || (_q->type == LIQUID_VCO_INTERP)) { unsigned int index = NCO(_static_index)(_q); if (_q->type == LIQUID_NCO) value = _q->nco_sintab[index]; else value = _q->vcoi_sintab[index].value + NCO_STATIC_LUT_THETA_ACCUM(_q->theta) * _q->vcoi_sintab[index].skew; } else if (_q->type == LIQUID_VCO_DIRECT) { value = _q->vcod_sintab[_q->vcod_index]; } return value; } T NCO(_cos)(NCO() _q) { T value = TIL(1); if ((_q->type == LIQUID_NCO) || (_q->type == LIQUID_VCO_INTERP)) { unsigned int index = NCO(_static_index)(_q); /* add pi/2 phase shift */ index = NCO_STATIC_LUT_INDEX_SHIFTED_PI2(index); if (_q->type == LIQUID_NCO) { value = _q->nco_sintab[index]; } else { uint32_t theta = NCO_STATIC_LUT_THETA_SHIFTED_PI2(_q->theta); value = _q->vcoi_sintab[index].value + NCO_STATIC_LUT_THETA_ACCUM(theta) * _q->vcoi_sintab[index].skew; } } else if (_q->type == LIQUID_VCO_DIRECT) { value = _q->vcod_costab[_q->vcod_index]; } return value; } // compute sin, cos of internal phase int NCO(_sincos)(NCO() _q, T * _s, T * _c) { if ((_q->type == LIQUID_NCO) || (_q->type == LIQUID_VCO_INTERP)) { unsigned int index = NCO(_static_index)(_q); unsigned int index_pi2 = NCO_STATIC_LUT_INDEX_SHIFTED_PI2(index); if (_q->type == LIQUID_NCO) { *_s = _q->nco_sintab[index]; *_c = _q->nco_sintab[index_pi2]; } else { uint32_t theta_pi2 = NCO_STATIC_LUT_THETA_SHIFTED_PI2(_q->theta); *_s = _q->vcoi_sintab[index].value + NCO_STATIC_LUT_THETA_ACCUM(_q->theta) * _q->vcoi_sintab[index].skew; *_c = _q->vcoi_sintab[index_pi2].value + NCO_STATIC_LUT_THETA_ACCUM(theta_pi2) * _q->vcoi_sintab[index_pi2].skew; } } else if (_q->type == LIQUID_VCO_DIRECT) { *_s = _q->vcod_sintab[_q->vcod_index]; *_c = _q->vcod_costab[_q->vcod_index]; } else { *_s = TIL(0); *_c = TIL(1); } return LIQUID_OK; } // compute complex exponential of internal phase int NCO(_cexpf)(NCO() _q, TC * _y) { T vsin; T vcos; NCO(_sincos)(_q, &vsin, &vcos); *_y = vcos + _Complex_I*vsin; return LIQUID_OK; } // pll methods // reset pll state, retaining base frequency int NCO(_pll_reset)(NCO() _q) { return LIQUID_OK; } // set pll bandwidth int NCO(_pll_set_bandwidth)(NCO() _q, T _bw) { // validate input if (_bw < TIL(0)) return liquid_error(LIQUID_EIRANGE,"nco_%s_pll_set_bandwidth(), bandwidth must be positive", EXTENSION); _q->alpha = _bw; // frequency proportion _q->beta = SQRT(_q->alpha); // phase proportion return LIQUID_OK; } // advance pll phase // _q : nco object // _dphi : phase error int NCO(_pll_step)(NCO() _q, T _dphi) { if (_q->type == LIQUID_VCO_DIRECT) return liquid_error(LIQUID_EIRANGE,"nco_%s_pll_step(), cannot be used with object type == LIQUID_VCO_DIRECT", EXTENSION); // increase frequency proportional to error NCO(_adjust_frequency)(_q, _dphi*_q->alpha); // TODO: ensure frequency doesn't run away // increase phase proportional to error NCO(_adjust_phase)(_q, _dphi*_q->beta); // constrain frequency //NCO(_constrain_frequency)(_q); return LIQUID_OK; } // mixing functions // Rotate input vector up by NCO angle, y = x exp{+j theta} // _q : nco object // _x : input sample // _y : output sample int NCO(_mix_up)(NCO() _q, TC _x, TC * _y) { // compute complex phasor TC v; NCO(_cexpf)(_q, &v); // rotate input *_y = _x * v; return LIQUID_OK; } // Rotate input vector down by NCO angle, y = x exp{-j theta} // _q : nco object // _x : input sample // _y : output sample int NCO(_mix_down)(NCO() _q, TC _x, TC * _y) { // compute complex phasor TC v; NCO(_cexpf)(_q, &v); // rotate input (negative direction) *_y = _x * CONJ(v); return LIQUID_OK; } // Rotate input vector array up by NCO angle: // y(t) = x(t) exp{+j (f*t + theta)} // TODO : implement NCO/VCO-specific versions // _q : nco object // _x : input array [size: _n x 1] // _y : output sample [size: _n x 1] // _n : number of input, output samples int NCO(_mix_block_up)(NCO() _q, TC * _x, TC * _y, unsigned int _n) { unsigned int i; // FIXME: this method should be more efficient but is causing occasional // errors so instead favor slower but more reliable algorithm // (anyway it must be rewritten to work with LIQUID_VCO_DIRECT type) #if 0 T theta = _q->theta; T d_theta = _q->d_theta; for (i=0; i<_n; i++) { // multiply _x[i] by [cos(theta) + _Complex_I*sin(theta)] _y[i] = _x[i] * liquid_cexpjf(theta); theta += d_theta; } NCO(_set_phase)(_q, theta); #else for (i=0; i<_n; i++) { // mix single sample up NCO(_mix_up)(_q, _x[i], &_y[i]); // step NCO phase NCO(_step)(_q); } #endif return LIQUID_OK; } // Rotate input vector array down by NCO angle: // y(t) = x(t) exp{-j (f*t + theta)} // TODO : implement NCO/VCO-specific versions // _q : nco object // _x : input array [size: _n x 1] // _y : output sample [size: _n x 1] // _n : number of input, output samples int NCO(_mix_block_down)(NCO() _q, TC * _x, TC * _y, unsigned int _n) { unsigned int i; // FIXME: this method should be more efficient but is causing occasional // errors so instead favor slower but more reliable algorithm // (anyway it must be rewritten to work with LIQUID_VCO_DIRECT type) #if 0 T theta = _q->theta; T d_theta = _q->d_theta; for (i=0; i<_n; i++) { // multiply _x[i] by [cos(-theta) + _Complex_I*sin(-theta)] _y[i] = _x[i] * liquid_cexpjf(-theta); theta += d_theta; } NCO(_set_phase)(_q, theta); #else for (i=0; i<_n; i++) { // mix single sample down NCO(_mix_down)(_q, _x[i], &_y[i]); // step NCO phase NCO(_step)(_q); } #endif return LIQUID_OK; } // // internal methods // uint32_t NCO(_constrain)(T _theta) { #if 0 // NOTE: there seems to be an occasional issue with this causing tests to fail, // namely randomly setting the frequency to be pi radians/sample. This // results in nco_crcf_pll not locking // divide value by 2*pi and compute modulo T p = _theta * 0.159154943091895; // 1/(2 pi) ~ 0.159154943091895 // extract fractional part of p T fpart = p - ((long)p); // fpart is in (-1,1) // ensure fpart is in [0,1) if (fpart < 0.) fpart += 1.; // map to range of precision needed uint32_t retVal = (uint32_t)(fpart * 0xffffffff); return retVal >= UINT_MAX ? UINT_MAX : retVal; #else // NOTE: this is not efficient, but resolves the issue above while (_theta >= 2*M_PI) _theta -= 2*M_PI; while (_theta < 0) _theta += 2*M_PI; return (uint32_t) ((_theta/(2*M_PI)) * 0xffffffff); #endif } void NCO(_constrain_vcod)(int *_n, unsigned int *_m) { if ((*_m) == 0) return; /* fold 'n' into [-'m'/2, 'm'/2) range */ *_n %= (int)(*_m); if ((T)(abs(*_n)) >= (T)(*_m)/TIL(2)) { int sign = ((*_n) > 0) ? -1 : 1; *_n = sign*((*_m) - (unsigned int)abs(*_n)); } /* try optimize values via reducing them by common denominators */ // with base 10 while ((((*_n) % 10) == 0) && (((*_m) % 10) == 0)) { *_n /= 10; *_m /= 10; } // with base 2 while ((((*_n) & 1) == 0) && (((*_m) & 1) == 0)) { *_n >>= 1; *_m >>= 1; } } T NCO(_fp_sin)(T x) { return SIN(x * TFL(M_PI) / ((uint32_t)(INT32_MAX)+1)); } T NCO(_fp_cos)(T x) { return COS(x * TFL(M_PI) / ((uint32_t)(INT32_MAX)+1)); } unsigned int NCO(_static_index)(NCO() _q) { /* TODO: LIQUID_NCO and LIQUID_VCO_INTERP are expected to share same code. * But "appropriate" rounding for LIQUID_VCO_INTERP type causes * phase breaks at some wrap points. * Not sure, so just keep it for type it originated from... */ if (_q->type == LIQUID_NCO) { //round down //return (_q->theta >> (NCO_STATIC_LUT_WORDBITS-NCO_STATIC_LUT_NBITS)) // & (NCO_STATIC_LUT_SIZE - 1); // round appropriately return ((_q->theta + (1<<(NCO_STATIC_LUT_WORDBITS-NCO_STATIC_LUT_NBITS-1))) >> (NCO_STATIC_LUT_WORDBITS-NCO_STATIC_LUT_NBITS)) & (NCO_STATIC_LUT_SIZE-1); } else { return (_q->theta >> (NCO_STATIC_LUT_WORDBITS-NCO_STATIC_LUT_NBITS)) & (NCO_STATIC_LUT_SIZE-1); } } liquid-dsp-1.7.0/src/nco/src/nco.utilities.c000066400000000000000000000044711474751757600207210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // nco.utilities.c // // Numerically-controlled oscillator (nco) utilities // #include #include #include // NOTE: this is defined in multiple places, but should be included here // until an appropriate place for literals can be found #define LIQUID_PI (3.14159265358979323846264338327950288f) // unwrap phase of array (basic) void liquid_unwrap_phase(float * _theta, unsigned int _n) { unsigned int i; for (i=1; i<_n; i++) { while ( (_theta[i] - _theta[i-1]) > LIQUID_PI ) _theta[i] -= 2*LIQUID_PI; while ( (_theta[i] - _theta[i-1]) < -LIQUID_PI ) _theta[i] += 2*LIQUID_PI; } } // unwrap phase of array (advanced) // TODO: verify this method void liquid_unwrap_phase2(float * _theta, unsigned int _n) { unsigned int i; // make an initial estimate of phase difference float dphi = 0.0f; for (i=1; i<_n; i++) dphi += _theta[i] - _theta[i-1]; dphi /= (float)(_n-1); for (i=1; i<_n; i++) { while ( (_theta[i] - _theta[i-1]) > LIQUID_PI+dphi ) _theta[i] -= 2*LIQUID_PI; while ( (_theta[i] - _theta[i-1]) < -LIQUID_PI+dphi ) _theta[i] += 2*LIQUID_PI; } } liquid-dsp-1.7.0/src/nco/src/nco_crcf.c000066400000000000000000000033451474751757600177030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // numerically-controlled oscillator (nco) API, floating point precision // #include "liquid.internal.h" #define NCO(name) LIQUID_CONCAT(nco_crcf,name) #define SYNTH(name) LIQUID_CONCAT(synth_crcf,name) #define EXTENSION "crcf" #define T float #define TC float complex #define TIL_(l) l ## .0f #define TFL_(l) l ## f #define TIL(l) TIL_(l) #define TFL(l) TFL_(l) #define SIN sinf #define COS cosf #define CONJ conjf #define SQRT sqrtf #define LIQUID_PI (3.14159265358979323846264338327950288f) // prototypes #include "nco.proto.c" #include "synth.proto.c" liquid-dsp-1.7.0/src/nco/src/synth.proto.c000066400000000000000000000167601474751757600204430ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Numerically-controlled synthesizer (direct digital synthesis) // with internal phase-locked loop (pll) implementation // #include #include #include #include #include #define SYNTH_PLL_BANDWIDTH_DEFAULT (0.1) #define SYNTH_PLL_GAIN_DEFAULT (1000) #define LIQUID_DEBUG_SYNTH (0) struct SYNTH(_s) { T theta; // phase T d_theta; // frequency TC * tab; // synth table unsigned int index; // table index unsigned int length; // table length T sumsq; TC prev_half; TC current; TC next_half; // phase-locked loop T alpha; T beta; }; SYNTH() SYNTH(_create)(const TC * _table, unsigned int _length) { SYNTH() q = (SYNTH())malloc(sizeof(struct SYNTH(_s))); q->length = _length; q->tab = (TC *)malloc(q->length * sizeof(TC)); memcpy(q->tab, _table, q->length * sizeof(TC)); // set default pll bandwidth SYNTH(_pll_set_bandwidth)(q, SYNTH_PLL_BANDWIDTH_DEFAULT); // reset object and return SYNTH(_reset)(q); // default frequency is to visit each sample once SYNTH(_set_frequency)(q, (2.f * M_PI) / _length); SYNTH(_compute_synth)(q); return q; } void SYNTH(_destroy)(SYNTH() _q) { if (!_q) { return; } free(_q->tab); free(_q); } void SYNTH(_reset)(SYNTH() _q) { _q->theta = 0; _q->d_theta = 0; // reset sine table index _q->index = 0; // reset pll filter state SYNTH(_pll_reset)(_q); } void SYNTH(_set_frequency)(SYNTH() _q, T _f) { _q->d_theta = _f; } void SYNTH(_adjust_frequency)(SYNTH() _q, T _df) { _q->d_theta += _df; } void SYNTH(_set_phase)(SYNTH() _q, T _phi) { _q->theta = _phi; SYNTH(_constrain_phase)(_q); SYNTH(_compute_synth)(_q); } void SYNTH(_adjust_phase)(SYNTH() _q, T _dphi) { _q->theta += _dphi; SYNTH(_constrain_phase)(_q); } void SYNTH(_step)(SYNTH() _q) { _q->theta += _q->d_theta; SYNTH(_constrain_phase)(_q); SYNTH(_compute_synth)(_q); } // get phase T SYNTH(_get_phase)(SYNTH() _q) { return _q->theta; } // ge frequency T SYNTH(_get_frequency)(SYNTH() _q) { return _q->d_theta; } unsigned int SYNTH(_get_length)(SYNTH() _q) { return _q->length; } TC SYNTH(_get_current)(SYNTH() _q) { return _q->current; } TC SYNTH(_get_half_previous)(SYNTH() _q) { return _q->prev_half; } TC SYNTH(_get_half_next)(SYNTH() _q) { return _q->next_half; } // pll methods // reset pll state, retaining base frequency void SYNTH(_pll_reset)(SYNTH() _q) { } // set pll bandwidth void SYNTH(_pll_set_bandwidth)(SYNTH() _q, T _bandwidth) { // validate input if (_bandwidth < 0.0f) { liquid_error(LIQUID_EIRANGE,"synth_pll_set_bandwidth(), bandwidth must be positive"); return; } _q->alpha = _bandwidth; // frequency proportion _q->beta = sqrtf(_q->alpha); // phase proportion } void SYNTH(_pll_step)(SYNTH() _q, T _dphi) { // increase frequency proportional to error SYNTH(_adjust_frequency)(_q, _dphi * _q->alpha); // increase phase proportional to error SYNTH(_adjust_phase)(_q, _dphi * _q->beta); SYNTH(_compute_synth)(_q); // constrain frequency // SYNTH(_constrain_frequency)(_q); } // mixing functions void SYNTH(_mix_up)(SYNTH() _q, TC _x, TC * _y) { *_y = _x * _q->current; } void SYNTH(_mix_down)(SYNTH() _q, TC _x, TC * _y) { *_y = _x * conjf(_q->current); } void SYNTH(_mix_block_up)(SYNTH() _q, TC * _x, TC * _y, unsigned int _n) { unsigned int i; for (i = 0; i < _n; i++) { // mix single sample up SYNTH(_mix_up)(_q, _x[i], &_y[i]); // step SYNTH phase SYNTH(_step)(_q); } } void SYNTH(_mix_block_down)(SYNTH() _q, TC * _x, TC * _y, unsigned int _n) { unsigned int i; for (i = 0; i < _n; i++) { // mix single sample down SYNTH(_mix_down)(_q, _x[i], &_y[i]); // step SYNTH phase SYNTH(_step)(_q); } } void SYNTH(_spread)(SYNTH() _q, TC _x, TC * _y) { unsigned int i; for (i = 0; i < _q->length; i++) { SYNTH(_mix_up)(_q, _x, &_y[i]); SYNTH(_step)(_q); } } void SYNTH(_despread)(SYNTH() _q, TC * _x, TC * _y) { TC despread = 0; T sum = 0; unsigned int i; for (i = 0; i < _q->length; i++) { TC temp; SYNTH(_mix_down)(_q, _x[i], &temp); despread += temp; sum += cabsf(_x[i]) * cabsf(_q->current); SYNTH(_step)(_q); } *_y = despread / sum; } void SYNTH(_despread_triple)(SYNTH() _q, TC * _x, TC * _early, TC * _punctual, TC * _late) { TC despread_early = 0; TC despread_punctual = 0; TC despread_late = 0; T sum_early = 0; T sum_punctual = 0; T sum_late = 0; unsigned int i; for (i = 0; i < _q->length; i++) { despread_early += _x[i] * conjf(_q->prev_half); despread_punctual += _x[i] * conjf(_q->current); despread_late += _x[i] * conjf(_q->next_half); sum_early += cabsf(_x[i]) * cabsf(_q->prev_half); sum_punctual += cabsf(_x[i]) * cabsf(_q->current); sum_late += cabsf(_x[i]) * cabsf(_q->next_half); SYNTH(_step)(_q); } *_early = despread_early / sum_early; *_punctual = despread_punctual / sum_punctual; *_late = despread_late / sum_late; } // // internal methods // // constrain frequency of SYNTH object to be in (-pi,pi) void SYNTH(_constrain_frequency)(SYNTH() _q) { if (_q->d_theta > M_PI) _q->d_theta -= 2 * M_PI; else if (_q->d_theta < -M_PI) _q->d_theta += 2 * M_PI; } // constrain phase of SYNTH object to be in (-pi,pi) void SYNTH(_constrain_phase)(SYNTH() _q) { if (_q->theta > M_PI) _q->theta -= 2 * M_PI; else if (_q->theta < -M_PI) _q->theta += 2 * M_PI; } void SYNTH(_compute_synth)(SYNTH() _q) { // assume phase is constrained to be in (-pi,pi) // compute index float index = _q->theta * (float)_q->length / (2 * M_PI) + 2.f * (float)_q->length; _q->index = ((unsigned int)(index + 0.5f)) % _q->length; assert(_q->index < _q->length); unsigned int prev_index = (_q->index + _q->length - 1) % _q->length; unsigned int next_index = (_q->index + 1) % _q->length; _q->current = _q->tab[_q->index]; TC prev = _q->tab[prev_index]; TC next = _q->tab[next_index]; _q->prev_half = (_q->current + prev) / 2; _q->next_half = (_q->current + next) / 2; } liquid-dsp-1.7.0/src/nco/tests/000077500000000000000000000000001474751757600163315ustar00rootroot00000000000000liquid-dsp-1.7.0/src/nco/tests/data/000077500000000000000000000000001474751757600172425ustar00rootroot00000000000000liquid-dsp-1.7.0/src/nco/tests/data/nco_sincos_fsqrt1_2.c000066400000000000000000000333431474751757600232720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest nco sincos data for f=0.707106781187 // #include float complex nco_sincos_fsqrt1_2[256] = { 1.000000000000 + _Complex_I* 0.000000000000, 0.760244597076 + _Complex_I* 0.649636939080, 0.155943694765 + _Complex_I* 0.987765945993, -0.523133894289 + _Complex_I* 0.852250508152, -0.951363128126 + _Complex_I* 0.308071742363, -0.923403461740 + _Complex_I* -0.383830752866, -0.452661857292 + _Complex_I* -0.891682254479, 0.235135999123 + _Complex_I* -0.971962479686, 0.810183603115 + _Complex_I* -0.586176193003, 0.996739414692 + _Complex_I* 0.080687912355, 0.705347906308 + _Complex_I* 0.708861291838, 0.075734454968 + _Complex_I* 0.997128022037, -0.590194485905 + _Complex_I* 0.807261090854, -0.973118793234 + _Complex_I* 0.230303743466, -0.889422123833 + _Complex_I* -0.457086737542, -0.379237935093 + _Complex_I* -0.925299188688, 0.312794941512 + _Complex_I* -0.949820680215, 0.854839263647 + _Complex_I* -0.518892891961, 0.986978921600 + _Complex_I* 0.160849645067, 0.645851521500 + _Complex_I* 0.763463039168, -0.004968662133 + _Complex_I* 0.999987656122, -0.653406318582 + _Complex_I* 0.757007386250, -0.988528584662 + _Complex_I* 0.151033894564, -0.849640712505 + _Complex_I* -0.527361981615, -0.303340937614 + _Complex_I* -0.952882089016, 0.388414094720 + _Complex_I* -0.921484938034, 0.893920371491 + _Complex_I* -0.448225801838, 0.970782170565 + _Complex_I* 0.239962449800, 0.582143428727 + _Complex_I* 0.813086113761, -0.085639377739 + _Complex_I* 0.996326200087, -0.712357177173 + _Complex_I* 0.701817107322, -0.997492012529 + _Complex_I* 0.070779127866, -0.804318649129 + _Complex_I* -0.594198208230, -0.225465802126 + _Complex_I* -0.974251082664, 0.461500333346 + _Complex_I* -0.887140035351, 0.927172072075 + _Complex_I* -0.374635754786, 0.948254783364 + _Complex_I* 0.317510418456, 0.514639079331 + _Complex_I* 0.857406915079, -0.165751624352 + _Complex_I* 0.986167530912, -0.766662633072 + _Complex_I* 0.642050159295, -0.999950624793 + _Complex_I* -0.009937201600, -0.753751486611 + _Complex_I* -0.657159566948, -0.146120365674 + _Complex_I* -0.989266818778, 0.531577049558 + _Complex_I* -0.847009941136, 0.954377525386 + _Complex_I* -0.298602644058, 0.919543664932 + _Complex_I* 0.392987847501, 0.443778680694 + _Complex_I* 0.896136419616, -0.244782976343 + _Complex_I* 0.969577895010, -0.815968551135 + _Complex_I* 0.578096292635, -0.995888388425 + _Complex_I* -0.090588728879, -0.698268982046 + _Complex_I* -0.715835476008, -0.065822053387 + _Complex_I* -0.997831377181, 0.598187261134 + _Complex_I* -0.801356350581, 0.975359320021 + _Complex_I* -0.220622294542, 0.884836045372 + _Complex_I* 0.465902535742, 0.370024325563 + _Complex_I* 0.929022065665, -0.322218056780 + _Complex_I* 0.946665476229, -0.859953399058 + _Complex_I* 0.510372561418, -0.985331793961 + _Complex_I* -0.170649511602, -0.638232946313 + _Complex_I* -0.769843299796, 0.014905495740 + _Complex_I* -0.999888906928, 0.660896591520 + _Complex_I* -0.750476978539, 0.989980630117 + _Complex_I* -0.141203229401, 0.844358258992 + _Complex_I* 0.535778994056, 0.293856978673 + _Complex_I* 0.955849400316, -0.397551898294 + _Complex_I* 0.917579690361, -0.898330344143 + _Complex_I* 0.439320603650, -0.968349682754 + _Complex_I* -0.249597459743, -0.574034884644 + _Complex_I* -0.818830844077, 0.095535843587 + _Complex_I* -0.995425990514, 0.719296102472 + _Complex_I* -0.694703618076, 0.998146107617 + _Complex_I* -0.060863353909, 0.798374268344 + _Complex_I* 0.602161546138, 0.215773340288 + _Complex_I* 0.976443477945, -0.470293236050 + _Complex_I* 0.882510210777, -0.930849123784 + _Complex_I* 0.365403761270, -0.945052798049 + _Complex_I* -0.326917740264, -0.506093443552 + _Complex_I* -0.862478652718, 0.175543185898 + _Complex_I* -0.984471731379, 0.773004960816 + _Complex_I* -0.634399976792, 0.999802504049 + _Complex_I* 0.019873421897, 0.747183942875 + _Complex_I* 0.664617300038, 0.136282607136 + _Complex_I* 0.990670001056, -0.539967711374 + _Complex_I* 0.841685731538, -0.957297677470 + _Complex_I* 0.289104058618, -0.915593062806 + _Complex_I* -0.402106134423, -0.434851680767 + _Complex_I* -0.900502090911, 0.254405781142 + _Complex_I* -0.967097564117, 0.821672921923 + _Complex_I* -0.569959305019, 0.994939017768 + _Complex_I* 0.100480599729, 0.691121103433 + _Complex_I* 0.722738971129, 0.055903151852 + _Complex_I* 0.998436196065, -0.606120965124 + _Complex_I* 0.795372476037, -0.977503529671 + _Complex_I* 0.210919059075, -0.880162588986 + _Complex_I* -0.474672325874, -0.360774175978 + _Complex_I* -0.932653201328, 0.331609352882 + _Complex_I* -0.943416788636, 0.864982613715 + _Complex_I* -0.501801831374, 0.983587364400 + _Complex_I* 0.180432526426, 0.630551345359 + _Complex_I* 0.776147538079, -0.024840857424 + _Complex_I* 0.999691418290, -0.668321600646 + _Complex_I* 0.743872460917, -0.991334914576 + _Complex_I* 0.131358620360, -0.838992424751 + _Complex_I* -0.544143098100, -0.284344001234 + _Complex_I* -0.958722321093, 0.406650443454 + _Complex_I* -0.913583831314, 0.902651606302 + _Complex_I* -0.430372022371, 0.965821570012 + _Complex_I* 0.259207821834, 0.565869654379 + _Complex_I* 0.824494714509, -0.105422875231 + _Complex_I* 0.994427482212, -0.726163996983 + _Complex_I* 0.687521526561, -0.998701635364 + _Complex_I* 0.050941569671, -0.792351047769 + _Complex_I* -0.610065420344, -0.206059570743 + _Complex_I* -0.978539449029, 0.479039697103 + _Complex_I* -0.877793237955, 0.934434253757 + _Complex_I* -0.356135683981, 0.941757488380 + _Complex_I* 0.336292778810, 0.497497830836 + _Complex_I* 0.867465220233, -0.185317412481 + _Complex_I* 0.982678714856, -0.779270954001 + _Complex_I* 0.626687147028, -0.999555652393 + _Complex_I* -0.029807679686, -0.740542614416 + _Complex_I* -0.672009401894, -0.126431390635 + _Complex_I* -0.991975354261, 0.548305051154 + _Complex_I* -0.836278405125, 0.960123296014 + _Complex_I* -0.279576924033, 0.911552045487 + _Complex_I* 0.411184713198, 0.425881739056 + _Complex_I* 0.904778837252, -0.264003463266 + _Complex_I* 0.964521731940, -0.827296152171 + _Complex_I* 0.561766033686, -0.993891396472 + _Complex_I* -0.110362548078, -0.683904976326 + _Complex_I* -0.729571095478, -0.045978729857 + _Complex_I* -0.998942418962, 0.613994814417 + _Complex_I* -0.789310058132, 0.979551210443 + _Complex_I* -0.201194995263, 0.875402216180 + _Complex_I* 0.483395241917, 0.351488399794 + _Complex_I* 0.936192237102, -0.340967902424 + _Complex_I* 0.940074938245, -0.869926410981 + _Complex_I* 0.493181548192, -0.981745805180 + _Complex_I* -0.190197723464, -0.622807477199 + _Complex_I* -0.782375131472, 0.034773766063 + _Complex_I* -0.999395209711, 0.675680612738 + _Complex_I* -0.737194485581, 0.992591304302 + _Complex_I* -0.121501039602, 0.833543739662 + _Complex_I* 0.552453467788, 0.274802944706 + _Complex_I* 0.961500567644, -0.415708831715 + _Complex_I* 0.909497755486, -0.906883731242 + _Complex_I* 0.421380941677, -0.963198081990 + _Complex_I* -0.268792587045, -0.557648544251 + _Complex_I* -0.830077165747, 0.115299496322 + _Complex_I* -0.993330773785, 0.732960182500 + _Complex_I* -0.680271542011, 0.999158540912 + _Complex_I* -0.041014754931, 0.786249582201 + _Complex_I* 0.617909050337, 0.196325452731 + _Complex_I* 0.980538788937, -0.487738852787 + _Complex_I* 0.872989582688, -0.937927107962 + _Complex_I* 0.346832438147, -0.938369179770 + _Complex_I* -0.345634608305, -0.488853090003 + _Complex_I* -0.872366125199, 0.195073338893 + _Complex_I* -0.980788658404, 0.785459993857 + _Complex_I* -0.618912431650, 0.999210094204 + _Complex_I* 0.039738993954, 0.733828157068 + _Complex_I* 0.679335142543, 0.116567688981 + _Complex_I* 0.993182749491, -0.556588245585 + _Complex_I* 0.830788495874, -0.962854101984 + _Complex_I* 0.270022181112, -0.907421012027 + _Complex_I* -0.420222687313, -0.416869741348 + _Complex_I* -0.908966236308, 0.273575074938 + _Complex_I* -0.961850652842, 0.832837686581 + _Complex_I* -0.553517287725, 0.992745627990 + _Complex_I* 0.120233598080, 0.676621313319 + _Complex_I* 0.736331174379, 0.036049767444 + _Complex_I* 0.999349995881, -0.621808031469 + _Complex_I* 0.783169695533, -0.981502160129 + _Complex_I* 0.191451063363, -0.870555397043 + _Complex_I* -0.492070422480, -0.342167913985 + _Complex_I* -0.939638823506, 0.350292781243 + _Complex_I* -0.936640255065, 0.874784302655 + _Complex_I* -0.484512563128, 0.979807298156 + _Complex_I* 0.199944138398, 0.615002106542 + _Complex_I* 0.788525464997, -0.044703240778 + _Complex_I* 0.999000310442, -0.682972901089 + _Complex_I* 0.730443711985, -0.993749675226 + _Complex_I* 0.111631460566, -0.828012741783 + _Complex_I* -0.560709282467, -0.265234751275 + _Complex_I* -0.964183865617, 0.424726168556 + _Complex_I* -0.905321866379, 0.911026301038 + _Complex_I* -0.412348249441, 0.960479477760 + _Complex_I* 0.278350808877, 0.549372366100 + _Complex_I* 0.835577646521, -0.125164731540 + _Complex_I* 0.992135973533, -0.739683987895 + _Complex_I* 0.672954380365, -0.999516779141 + _Complex_I* 0.031083889968, -0.780070474162 + _Complex_I* -0.625691661556, -0.186571947499 + _Complex_I* -0.982441300235, 0.496389844059 + _Complex_I* -0.868099719338, 0.941327341476 + _Complex_I* -0.337494942465, 0.934888206815 + _Complex_I* 0.354942306239, 0.480160074725 + _Complex_I* 0.877180883649, -0.204810001732 + _Complex_I* 0.978801748665, -0.791571469213 + _Complex_I* 0.611076598413, -0.998765863605 + _Complex_I* -0.049666383980, -0.727041233885 + _Complex_I* -0.686593798567, -0.106692476220 + _Complex_I* -0.994292067512, 0.564816476695 + _Complex_I* -0.825216545916, 0.965489825714 + _Complex_I* -0.260440773388, 0.903200370366 + _Complex_I* 0.429219164264, 0.407816577581 + _Complex_I* 0.913063874573, -0.283119670959 + _Complex_I* 0.959084590595, -0.838296977925 + _Complex_I* 0.545213881703, -0.991501825466 + _Complex_I* -0.130092774964, -0.669270833677 + _Complex_I* -0.743018540273, -0.026117245101 + _Complex_I* -0.999658886575, 0.629559844720 + _Complex_I* -0.776951994602, 0.983356186070 + _Complex_I* -0.181688225591, 0.865622610200 + _Complex_I* 0.500697010886, 0.332813638953 + _Complex_I* 0.942992620187, -0.359583068506 + _Complex_I* 0.933113078273, -0.879555809016 + _Complex_I* 0.475795732248, -0.977772034756 + _Complex_I* -0.209670808766, -0.607136004174 + _Complex_I* -0.794597931306, 0.054628301030 + _Complex_I* -0.998506759480, 0.690197745585 + _Complex_I* -0.723620806770, 0.994809912959 + _Complex_I* -0.101750857877, 0.822399977304 + _Complex_I* 0.568909726873, 0.255640365802 + _Complex_I* 0.966771950034, -0.433701563513 + _Complex_I* 0.901056576363, -0.915078906610 + _Complex_I* 0.403274837644, -0.957666025784 + _Complex_I* -0.287881543451, -0.541041937199 + _Complex_I* -0.840995613658, 0.135017606689 + _Complex_I* -0.990843199444, 0.746334749190 + _Complex_I* -0.665570764195, 0.999776314675 + _Complex_I* -0.021149955457, 0.773814333841 + _Complex_I* 0.633412485465, 0.176800018209 + _Complex_I* 0.984246795047, -0.504991816627 + _Complex_I* 0.863124130783, -0.944634618526 + _Complex_I* 0.328124119019, -0.931314913263 + _Complex_I* -0.364214953474, -0.471419643442 + _Complex_I* -0.881909020125, 0.214526439499 + _Complex_I* -0.976718181850, 0.797604776560 + _Complex_I* -0.603180421109, 0.998223004463 + _Complex_I* 0.059588869430, 0.720182515080 + _Complex_I* 0.693784653169, 0.096806727533 + _Complex_I* 0.995303198781, -0.572988931946 + _Complex_I* 0.819563105482, -0.968030206924 + _Complex_I* 0.250833647030, -0.898890537295 + _Complex_I* -0.438173255644, -0.398723141757 + _Complex_I* -0.917071347403, 0.292636308795 + _Complex_I* -0.956223818347, 0.843673487096 + _Complex_I* -0.536856635585, 0.990160111727 + _Complex_I* 0.139939105133, 0.661854263264 + _Complex_I* 0.749632532778, 0.016182143669 + _Complex_I* 0.999869060541, -0.637249488677 + _Complex_I* 0.770657569340, -0.985113105181 + _Complex_I* 0.171907446032, -0.860604342767 + _Complex_I* -0.509274155254, -0.323426498437 + _Complex_I* -0.946253295957}; liquid-dsp-1.7.0/src/nco/tests/data/nco_sincos_fsqrt1_3.c000066400000000000000000000333431474751757600232730ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest nco sincos data for f=0.577350269190 // #include float complex nco_sincos_fsqrt1_3[256] = { 1.000000000000 + _Complex_I* 0.000000000000, 0.837911827695 + _Complex_I* 0.545805614673, 0.404192461982 + _Complex_I* 0.914673960314, -0.160556538575 + _Complex_I* 0.987026644990, -0.673256907353 + _Complex_I* 0.739408639861, -0.967703312923 + _Complex_I* 0.252091844688, -0.948443195842 + _Complex_I* -0.316947163201, -0.621720230463 + _Complex_I* -0.783239398290, -0.093450273402 + _Complex_I* -0.995623948286, 0.465114051693 + _Complex_I* -0.885250766121, 0.872899403683 + _Complex_I* -0.487900226531, 0.997711417775 + _Complex_I* 0.067616025029, 0.799088991477 + _Complex_I* 0.601212760759, 0.341420816904 + _Complex_I* 0.939910541373, -0.226927910067 + _Complex_I* 0.973911558424, -0.721711976662 + _Complex_I* 0.692193486492, -0.982534092802 + _Complex_I* 0.186082660346, -0.924841898283 + _Complex_I* -0.380351762426, -0.567337837836 + _Complex_I* -0.823485141190, -0.025916270960 + _Complex_I* -0.999664117041, 0.523906737901 + _Complex_I* -0.851775633592, 0.903891575553 + _Complex_I* -0.427761638818, 0.990856146318 + _Complex_I* 0.134922560393, 0.756608593536 + _Complex_I* 0.653868057170, 0.277086432600 + _Complex_I* 0.960844997317, -0.292260595196 + _Complex_I* 0.956338718496, -0.766863651569 + _Complex_I* 0.641810049705, -0.992867652562 + _Complex_I* 0.119221745066, -0.897007447265 + _Complex_I* -0.442015429086, -0.510358646627 + _Complex_I* -0.859961657176, 0.041736354516 + _Complex_I* -0.999128658738, 0.580301416814 + _Complex_I* -0.814401783915, 0.930746487037 + _Complex_I* -0.365665115738, 0.979465563334 + _Complex_I* 0.201611533010, 0.710665073638 + _Complex_I* 0.703530491955, 0.211483778128 + _Complex_I* 0.977381507697, -0.356255555520 + _Complex_I* 0.934388558985, -0.808505265432 + _Complex_I* 0.588488942775, -0.998656693799 + _Complex_I* 0.051815132253, -0.865067245650 + _Complex_I* -0.501655918438, -0.451043459964 + _Complex_I* -0.892501987238, 0.109197945833 + _Complex_I* -0.994020024258, 0.634039960711 + _Complex_I* -0.773300283345, 0.953341218789 + _Complex_I* -0.301894883291, 0.963591805394 + _Complex_I* 0.267377696485, 0.661468722830 + _Complex_I* 0.749972751984, 0.144913127625 + _Complex_I* 0.989444382187, -0.418619875580 + _Complex_I* 0.908161549379, -0.846446217737 + _Complex_I* 0.532474225177, -0.999874719120 + _Complex_I* -0.015828646941, -0.829167488991 + _Complex_I* -0.559000246154, -0.389663773211 + _Complex_I* -0.920957188933, 0.176159720196 + _Complex_I* -0.984361596661, 0.684876399442 + _Complex_I* -0.728659260209, 0.971572351007 + _Complex_I* -0.236742828316, 0.943307529299 + _Complex_I* 0.331920028273, 0.609244720899 + _Complex_I* 0.792982263393, 0.077679185906 + _Complex_I* 0.996978407026, -0.479068103627 + _Complex_I* 0.877777735015, -0.880512846507 + _Complex_I* 0.474022285486, -0.996516153423 + _Complex_I* -0.083399975816, -0.789472496379 + _Complex_I* -0.613785937817, -0.326500531288 + _Complex_I* -0.945197018123, 0.242315182549 + _Complex_I* -0.970197584158, 0.732578046264 + _Complex_I* -0.680683043811, 0.985356436799 + _Complex_I* -0.170507162484, 0.918705579515 + _Complex_I* 0.394943107508, 0.554232105691 + _Complex_I* 0.832362164578, 0.010089693778 + _Complex_I* 0.999949097744, -0.537323558182 + _Complex_I* 0.843376187607, -0.910549223177 + _Complex_I* 0.413400667841, -0.988596369416 + _Complex_I* -0.150589569286, -0.746163958323 + _Complex_I* -0.665762230305, -0.261842842740 + _Complex_I* -0.965110525124, 0.307361528464 + _Complex_I* -0.951592817764, 0.776926562896 + _Complex_I* -0.629591229184, 0.994630384139 + _Complex_I* -0.103491057329, 0.889898563214 + _Complex_I* 0.456158467191, 0.496682678992 + _Complex_I* 0.867932207254, -0.057545980537 + _Complex_I* 0.998342857001, -0.593119594448 + _Complex_I* 0.805114368697, -0.936417866314 + _Complex_I* 0.350886847356, -0.976151617251 + _Complex_I* -0.217089889533, -0.699440105123 + _Complex_I* -0.714691219581, -0.195986656442 + _Complex_I* -0.980606562540, 0.371001030117 + _Complex_I* -0.928632454555, 0.817718958886 + _Complex_I* -0.575617671966, 0.999351744645 + _Complex_I* -0.036001256586, 0.857018334845 + _Complex_I* 0.515285914556, 0.436859853992 + _Complex_I* 0.899529581487, -0.124918257436 + _Complex_I* 0.992167036824, -0.646200824792 + _Complex_I* 0.763167408920, -0.958000370884 + _Complex_I* 0.286766960067, -0.959238858607 + _Complex_I* -0.282596553655, -0.649514799540 + _Complex_I* -0.760348949614, -0.129233406987 + _Complex_I* -0.991614202459, 0.432942399044 + _Complex_I* -0.901421587888, 0.854768520727 + _Complex_I* -0.519009418002, 0.999498907872 + _Complex_I* 0.031653327829, 0.820215392622 + _Complex_I* 0.572054813550, 0.375037449599 + _Complex_I* 0.927009660898, -0.191718762927 + _Complex_I* 0.981449904958, -0.696324287694 + _Complex_I* 0.717727306410, -0.975197950213 + _Complex_I* 0.221334493244, -0.937935505961 + _Complex_I* -0.346809726878, -0.596616557906 + _Complex_I* -0.802526437466, -0.061888634976 + _Complex_I* -0.998083061103, 0.492902119414 + _Complex_I* -0.870084766375, 0.887905666482 + _Complex_I* -0.460025572582, 0.995071200231 + _Complex_I* 0.099163029757, 0.779658189663 + _Complex_I* 0.626205323590, 0.311498437124 + _Complex_I* 0.950246664645, -0.257641740113 + _Complex_I* 0.966240515478, -0.743260559821 + _Complex_I* 0.669002047989, -0.987931888154 + _Complex_I* 0.154888942047, -0.912339068261 + _Complex_I* -0.409435494949, -0.540987504175 + _Complex_I* -0.841030629839, 0.005739411495 + _Complex_I* -0.999983529442, 0.550605745726 + _Complex_I* -0.834765423801, 0.916978721986 + _Complex_I* -0.398936114465, 0.986088888068 + _Complex_I* 0.166218846191, 0.735532362955 + _Complex_I* 0.677489588884, 0.246533645077 + _Complex_I* 0.969134233141, -0.322385448685 + _Complex_I* 0.946608484262, -0.786794806137 + _Complex_I* 0.617214657178, -0.996143899378 + _Complex_I* 0.087734438690, -0.882566704612 + _Complex_I* -0.470187209428, -0.482882261671 + _Complex_I* -0.875685286712, 0.073341187736 + _Complex_I* -0.997306908720, 0.605789158993 + _Complex_I* -0.795625222606, 0.941854615084 + _Complex_I* -0.336020660147, 0.972593084902 + _Complex_I* 0.232513851631, 0.688039883664 + _Complex_I* 0.725672872917, 0.180440427994 + _Complex_I* 0.983585914877, -0.385653546043 + _Complex_I* 0.922643670343, -0.826727763238 + _Complex_I* 0.562602173380, -0.999796396159 + _Complex_I* 0.020178360380, -0.848754688019 + _Complex_I* -0.528786799727, -0.422566787646 + _Complex_I* -0.906331788022, 0.140607269299 + _Complex_I* -0.990065450271, 0.658199775658 + _Complex_I* -0.752843313927, 0.962419484720 + _Complex_I* -0.271567184010, 0.954645563245 + _Complex_I* 0.297744602936, 0.637398132678 + _Complex_I* 0.770534632874, 0.113521305399 + _Complex_I* 0.993535562132, -0.447156443700 + _Complex_I* 0.894455764618, -0.862876651411 + _Complex_I* 0.505414566915, -0.998872660419 + _Complex_I* -0.047470077604, -0.811057781641 + _Complex_I* -0.584966045886, -0.360317155943 + _Complex_I* -0.932829859692, 0.207229768268 + _Complex_I* -0.978292299440, 0.707597703708 + _Complex_I* -0.706615517595, 0.978579202106 + _Complex_I* -0.205870700212, 0.932328471853 + _Complex_I* 0.361612528228, 0.583838905619 + _Complex_I* 0.811869529102, 0.046082577121 + _Complex_I* 0.998937633732, -0.506612632779 + _Complex_I* 0.862173787765, -0.895076011251 + _Complex_I* 0.445913594861, -0.993376920248 + _Complex_I* -0.114901237236, -0.769648530419 + _Complex_I* -0.638467806255, -0.296418293364 + _Complex_I* -0.955058215691, 0.272903742509 + _Complex_I* -0.962041343875, 0.753756840705 + _Complex_I* -0.657153425837, 0.990259801557 + _Complex_I* -0.139231912364, 0.905743959725 + _Complex_I* 0.423825293512, 0.527607351878 + _Complex_I* 0.849488364985, -0.021567078691 + _Complex_I* 0.999767403508, -0.563749972526 + _Complex_I* 0.825945499701, -0.923178460993 + _Complex_I* 0.384371602954, -0.983334330553 + _Complex_I* -0.181806475010, -0.724716471305 + _Complex_I* -0.689047194479, -0.231162675510 + _Complex_I* -0.972915113178, 0.337328591442 + _Complex_I* -0.941386966872, 0.796465908688 + _Complex_I* -0.604683434781, 0.997407819049 + _Complex_I* -0.071955837157, 0.875013708545 + _Complex_I* 0.484098140730, 0.468960852521 + _Complex_I* 0.883218952923, -0.089118018438 + _Complex_I* 0.996021073467, -0.618306935941 + _Complex_I* 0.785936723259, -0.947055371103 + _Complex_I* 0.321070279011, -0.968790857919 + _Complex_I* -0.247879554650, -0.676467265722 + _Complex_I* -0.736472700381, -0.164848988076 + _Complex_I* -0.986318818197, 0.400209431938 + _Complex_I* -0.916423706911, 0.835529421227 + _Complex_I* -0.549445708204, 0.999990536929 + _Complex_I* -0.004350408249, 0.840278375725 + _Complex_I* 0.542155191149, 0.408167842223 + _Complex_I* 0.912906902469, -0.156261050358 + _Complex_I* 0.987715791177, -0.670033806829 + _Complex_I* 0.742330585188, -0.966597453037 + _Complex_I* 0.256299363601, -0.949813070210 + _Complex_I* -0.312818048805, -0.625121758220 + _Complex_I* -0.780527249621, -0.097780759713 + _Complex_I* -0.995207979786, 0.461258448050 + _Complex_I* -0.887265824938, 0.870768578204 + _Complex_I* -0.491693078264, 0.997996133675 + _Complex_I* 0.063274933192, 0.801696950596 + _Complex_I* 0.597730708100, 0.345506580588 + _Complex_I* 0.938416326995, -0.222688849754 + _Complex_I* 0.974889571282, -0.718693822797 + _Complex_I* 0.695326677953, -0.981715259472 + _Complex_I* 0.190355323855, -0.926487831883 + _Complex_I* -0.376324723307, -0.570914965629 + _Complex_I* -0.821009197281, -0.030264972734 + _Complex_I* -0.999541910790, 0.520196208392 + _Complex_I* -0.854046781374, 0.902022084201 + _Complex_I* -0.431689888246, 0.991433737996 + _Complex_I* 0.130610654858, 0.759446026685 + _Complex_I* 0.650570313304, 0.281263878515 + _Complex_I* 0.959630465670, -0.288097365664 + _Complex_I* 0.957601121500, -0.764064258949 + _Complex_I* 0.645140146167, -0.992339593722 + _Complex_I* 0.123539996488, -0.898921906390 + _Complex_I* -0.438108897665, -0.514095001354 + _Complex_I* -0.857733250832, 0.037389342002 + _Complex_I* -0.999300774094, 0.576752945141 + _Complex_I* -0.816918625244, 0.929146886781 + _Complex_I* -0.369710782619, 0.980333387059 + _Complex_I* 0.197348550079, 0.713718993420 + _Complex_I* 0.700432151198, 0.215733785416 + _Complex_I* 0.976452217894, -0.352187212553 + _Complex_I* 0.935929573907, -0.805937447338 + _Complex_I* 0.592000701839, -0.998421826461 + _Complex_I* 0.056159206242, -0.867241467503 + _Complex_I* -0.497887775551, -0.454921939715 + _Complex_I* -0.890531318240, 0.104872519572 + _Complex_I* -0.994485673420, 0.630669788815 + _Complex_I* -0.776051298225, 0.952018831263 + _Complex_I* -0.306039449941, 0.964745888993 + _Complex_I* 0.263183148531, 0.664725150952 + _Complex_I* 0.747087995950, 0.149216243304 + _Complex_I* 0.988804587739, -0.414665040654 + _Complex_I* 0.909974122742, -0.844121727495 + _Complex_I* 0.536151572944, -0.999934118311 + _Complex_I* -0.011478633927, -0.831591521802 + _Complex_I* -0.555387739211, -0.393666625547 + _Complex_I* -0.919253277356, 0.171875678373 + _Complex_I* -0.985118648277, 0.681699953151 + _Complex_I* -0.731631856793, 0.970533228996 + _Complex_I* -0.240967324373, 0.944742590342 + _Complex_I* 0.327813114433, 0.612688752154 + _Complex_I* 0.790324296086, 0.082015713908 + _Complex_I* 0.996631036378, -0.475244878672 + _Complex_I* 0.879853570372, -0.878442323690 + _Complex_I* 0.477848390130, -0.996869547263 + _Complex_I* -0.079063934501, -0.792135244952 + _Complex_I* -0.610345601856, -0.330609434495 + _Complex_I* -0.943767663052, 0.238092133930 + _Complex_I* -0.971242573079, 0.729609864697 + _Complex_I* -0.683863616035, 0.984605336535 + _Complex_I* -0.174792251734, 0.920415049492 + _Complex_I* 0.390942625801, 0.557847976181 + _Complex_I* 0.829943151952, 0.014439785103 + _Complex_I* 0.999895740868, -0.533649442727 + _Complex_I* 0.845705783519, -0.908742144910 + _Complex_I* 0.417358016653}; liquid-dsp-1.7.0/src/nco/tests/data/nco_sincos_fsqrt1_5.c000066400000000000000000000333431474751757600232750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest nco sincos data for f=0.447213595500 // #include float complex nco_sincos_fsqrt1_5[256] = { 1.000000000000 + _Complex_I* 0.000000000000, 0.901655595150 + _Complex_I* 0.432454838954, 0.625965624531 + _Complex_I* 0.779850650385, 0.227155220309 + _Complex_I* 0.973858565648, -0.216334073812 + _Complex_I* 0.976319398818, -0.617272876457 + _Complex_I* 0.786749131547, -0.896801011772 + _Complex_I* 0.442434114060, -0.999938423544 + _Complex_I* 0.011097257308, -0.906399137016 + _Complex_I* -0.422422305775, -0.634581283115 + _Complex_I* -0.772856128345, -0.237948391981 + _Complex_I* -0.971277798961, 0.205486285143 + _Complex_I* -0.978659995411, 0.608504109432 + _Complex_I* -0.793550722263, 0.891835984739 + _Complex_I* -0.452358902117, 0.999753701760 + _Complex_I* -0.022193147956, 0.911031053190 + _Complex_I* 0.412337750060, 0.643118791167 + _Complex_I* 0.765766426822, 0.248712259614 + _Complex_I* 0.968577416584, -0.194613190240 + _Complex_I* 0.980880067177, -0.599660403354 + _Complex_I* 0.800254584898, -0.886761125508 + _Complex_I* 0.462227980858, -0.999445857398 + _Complex_I* 0.033286305454, -0.915550773236 + _Complex_I* -0.402202413750, -0.651577097268 + _Complex_I* -0.758582418934, -0.259445497609 + _Complex_I* -0.965757751080, 0.183716128155 + _Complex_I* -0.982979340706, 0.590742847351 + _Complex_I* -0.806859893850, 0.881577059062 + _Complex_I* -0.472040134878, 0.999014928368 + _Complex_I* -0.044375363646, 0.919957740540 + _Complex_I* 0.392017545042, 0.659955159752 + _Complex_I* 0.751304989413, 0.270146784136 + _Complex_I* 0.962819149696, -0.172796440895 + _Complex_I* 0.984957557468, -0.581752539647 + _Complex_I* 0.813365835657, -0.876284423835 + _Complex_I* 0.481794155781, -0.998460967741 + _Complex_I* 0.055458956883, -0.924251412370 + _Complex_I* -0.381784398231, -0.668251946836 + _Complex_I* -0.743935034495, -0.280814801300 + _Complex_I* -0.959761974331, 0.161855473250 + _Complex_I* -0.986814473839, 0.572690587423 + _Complex_I* -0.819771609094, 0.870883871630 + _Complex_I* -0.491488842330, 0.997784043738 + _Complex_I* -0.066535720188, 0.928431259947 + _Complex_I* 0.371504233561, 0.676466436748 + _Complex_I* 0.736473461812, 0.291448235303 + _Complex_I* 0.956586601484, -0.150894572633 + _Complex_I* 0.988549861135, -0.563558106687 + _Complex_I* 0.826076425270, -0.865376067540 + _Complex_I* 0.501123000598, -0.996984239726 + _Complex_I* 0.077604289425, -0.932496768511 + _Complex_I* -0.361178317063, -0.684597617848 + _Complex_I* -0.728921190278, -0.302045776608 + _Complex_I* -0.953293422212, 0.139915088909 + _Complex_I* -0.990163505637, 0.554356222129 + _Complex_I* -0.832279507730, 0.859761689869 + _Complex_I* -0.510695444109, 0.996061654203 + _Complex_I* -0.088663301468, 0.936447437384 + _Complex_I* 0.350807920403, 0.692644488759 + _Complex_I* 0.721279149977, 0.312606120095 + _Complex_I* 0.949882842080, -0.128918374235 + _Complex_I* 0.991655208621, -0.545086066988 + _Complex_I* 0.838380092545, -0.854041430042 + _Complex_I* 0.520204993990, -0.995016400786 + _Complex_I* 0.099711394367, -0.940282780028 + _Complex_I* -0.340394320727, -0.700606058485 + _Complex_I* -0.713548282049, -0.323127965229 + _Complex_I* -0.946355281111, 0.117905782887 + _Complex_I* -0.993024786378, 0.535748782911 + _Complex_I* -0.844377428410, 0.848215992526 + _Complex_I* -0.529650479111, 0.993848608203 + _Complex_I* -0.110747207518, 0.944002324110 + _Complex_I* 0.329938800499, 0.708481346534 + _Complex_I* 0.705729538572, 0.333610016214 + _Complex_I* 0.942711173733, -0.106878671100 + _Complex_I* 0.994272070242, -0.526345519812 + _Complex_I* 0.850270776737, -0.842286094742 + _Complex_I* 0.539030736233, -0.992558420270 + _Complex_I* 0.121769381828, -0.947605611558 + _Complex_I* -0.319442647347, -0.716269383043 + _Complex_I* -0.697823882448, -0.344050982153 + _Complex_I* -0.938950968730, 0.095838396892 + _Complex_I* -0.995396906606, 0.516877435730 + _Complex_I* -0.856059411743, 0.836252466973 + _Complex_I* -0.548344610151, 0.991145995878 + _Complex_I* -0.132776559884, 0.951092198616 + _Complex_I* 0.308907153903, 0.723969208892 + _Complex_I* 0.689832287281, 0.354449577213 + _Complex_I* 0.935075129181, -0.084786319907 + _Complex_I* 0.996399156943, -0.507345696686 + _Complex_I* 0.861742620539, -0.830115852277 + _Complex_I* 0.557590953834, -0.989611508971 + _Complex_I* 0.143767386120, -0.954461655900 + _Complex_I* -0.298333617644, -0.731579875826 + _Complex_I* -0.681755737260, -0.364804520775 + _Complex_I* -0.931084132408, 0.073723801240 + _Complex_I* -0.997278697823, 0.497751476543 + _Complex_I* -0.867319703223, 0.823877006398 + _Complex_I* -0.566768628568, 0.987955148526 + _Complex_I* -0.154740506984, 0.957713568453 + _Complex_I* 0.287723340731, 0.739100446567 + _Complex_I* 0.673595227035, 0.375114537598 + _Complex_I* 0.926978469913, -0.062652203273 + _Complex_I* 0.998035420927, -0.488095956857 + _Complex_I* 0.872789972960, -0.817536697667 + _Complex_I* 0.575876504094, -0.986177118527 + _Complex_I* 0.165694571104, -0.960847535791 + _Complex_I* -0.277077629851, -0.746529994937 + _Complex_I* -0.665351761596, -0.385378357974 + _Complex_I* -0.922758647321, 0.051572889504 + _Complex_I* -0.998669233064, 0.478380326732 + _Complex_I* -0.878152756072, 0.811095706911 + _Complex_I* -0.584913458753, 0.984277637946 + _Complex_I* -0.176628229455, 0.963863171958 + _Complex_I* 0.266397796054, 0.753867605965 + _Complex_I* 0.657026356151, 0.395594717883 + _Complex_I* 0.918425184315, -0.040487224383 + _Complex_I* 0.999180056177, -0.468605782677 + _Complex_I* 0.883407392114, -0.804554827358 + _Complex_I* 0.593878379616, -0.982256940707 + _Complex_I* 0.187540135525, -0.966760105569 + _Complex_I* -0.255685154594, -0.761112376002 + _Complex_I* -0.648620035997, -0.405762359151 + _Complex_I* -0.913978614573, 0.029396573143 + _Complex_I* -0.999567827357, 0.458773528456 + _Complex_I* -0.888553233964, 0.797914864535 + _Complex_I* -0.602770162628, 0.980115275667 + _Complex_I* -0.198428945482, 0.969537979859 + _Complex_I* 0.244941024761, 0.768263412834 + _Complex_I* 0.640133836397, 0.415880029602 + _Complex_I* 0.909419485704, -0.018302301629 + _Complex_I* 0.999832498849, -0.448884774939 + _Complex_I* 0.893589647897, -0.791176636173 + _Complex_I* 0.611587712739, -0.977852906576 + _Complex_I* 0.209293318336, -0.972196452723 + _Complex_I* -0.234166729729, -0.775319835790 + _Complex_I* -0.631568802452, -0.425946483218 + _Complex_I* -0.904748359177, 0.007205776134 + _Complex_I* -0.999974038058, 0.438940739955 + _Complex_I* -0.898516013662, 0.784340972106 + _Complex_I* -0.620329944043, 0.975470112054 + _Complex_I* -0.220131916109, 0.974735196764 + _Complex_I* 0.223363596382, 0.782280775851 + _Complex_I* 0.622925988970, 0.435960480284 + _Complex_I* 0.899965810257, 0.003891636774 + _Complex_I* 0.999992427553, -0.428942648141 + _Complex_I* 0.903331724565, -0.777408714164 + _Complex_I* 0.628995779908, -0.972967185547 + _Complex_I* 0.230943403995, -0.977153899328 + _Complex_I* -0.212532955158, -0.789145375757 + _Complex_I* -0.614206460339, -0.445920787547 + _Complex_I* -0.895072427926, -0.014988570415 + _Complex_I* -0.999887665069, 0.418891730791 + _Complex_I* -0.908036187536, 0.770380716075 + _Complex_I* -0.637584153112, 0.970344435298 + _Complex_I* -0.241726450529, 0.979452262544 + _Complex_I* 0.201676139882, 0.795912790112 + _Complex_I* 0.605411290394, 0.455826178368 + _Complex_I* 0.890068814820, 0.026083658170 + _Complex_I* 0.999659763508, -0.408789225705 + _Complex_I* 0.912628823207, -0.763257843359 + _Complex_I* 0.646094005971, -0.967602184308 + _Complex_I* 0.252479727747, -0.981630003362 + _Complex_I* -0.190794487601, -0.802582185490 + _Complex_I* -0.596541562286, -0.465675432867 + _Complex_I* -0.884955587148, -0.037175533647 + _Complex_I* -0.999308750936, 0.398636377036 + _Complex_I* -0.917109065981, 0.756040973217 + _Complex_I* -0.654524290472, 0.964740770291 + _Complex_I* -0.263201911351, 0.983686853588 + _Complex_I* 0.179889338425, 0.809152740535 + _Complex_I* 0.587598368348, 0.475467338081 + _Complex_I* 0.879733374619, 0.048262830849 + _Complex_I* 0.998834670583, -0.388434435136 + _Complex_I* 0.921476364103, -0.748730994427 + _Complex_I* 0.662873968401, -0.961760545639 + _Complex_I* 0.273891680873, -0.985622559913 + _Complex_I* -0.168962035352, -0.815623646064 + _Complex_I* -0.578582809960, -0.485200688108 + _Complex_I* -0.874402820364, -0.059344184342 + _Complex_I* -0.998237580832, 0.378184656405 + _Complex_I* -0.925730179728, 0.741328807236 + _Complex_I* -0.671142011471, 0.958661877377 + _Complex_I* -0.284547719838, 0.987436883951 + _Complex_I* 0.158013924113, 0.821994105167 + _Complex_I* 0.569495997414, 0.494874284257 + _Complex_I* 0.868964580855, 0.070418229426 + _Complex_I* 0.997517555216, -0.367888303132 + _Complex_I* 0.929869988987, -0.733835323245 + _Complex_I* 0.679327401448, -0.955445147112 + _Complex_I* 0.295168715922, -0.989129602261 + _Complex_I* -0.147046352999, -0.828263333302 + _Complex_I* -0.560339049779, -0.504486935198 + _Complex_I* -0.863419325829, -0.081483602301 + _Complex_I* -0.996674682410, 0.357546643343 + _Complex_I* -0.933895282049, 0.726251465296 + _Complex_I* -0.687429130278, 0.952110750997 + _Complex_I* -0.305753361120, 0.990700506382 + _Complex_I* 0.136060672699, 0.834430558397 + _Complex_I* 0.551113094758, 0.514037457104 + _Complex_I* 0.857767738198, 0.092538940232 + _Complex_I* 0.995709066214, -0.347160950645 + _Complex_I* 0.937805563189, -0.718578167365 + _Complex_I* 0.695446200210, -0.948659099670 + _Complex_I* 0.316300351901, -0.992149402850 + _Complex_I* -0.125058236130, -0.840495020939 + _Complex_I* -0.541819268554, -0.523524673801 + _Complex_I* -0.852010513974, -0.103582881724 + _Complex_I* -0.994620825548, 0.336732504064 + _Complex_I* -0.941600350842, 0.710816374441 + _Complex_I* -0.703377623917, 0.945090618214 + _Complex_I* -0.326808389373, 0.993476113231 + _Complex_I* 0.114040398276, 0.846455974072 + _Complex_I* 0.532458715731, 0.532947416909 + _Complex_I* 0.846148362174, 0.114614066682 + _Complex_I* 0.993410094432, -0.326262587896 + _Complex_I* 0.945279177672, -0.702967042411 + _Complex_I* 0.711222424621, -0.941405746096 + _Complex_I* 0.337276179440, -0.994680474136 + _Complex_I* -0.103008516015, -0.852312683688 + _Complex_I* -0.523032589066, -0.542304525992 + _Complex_I* -0.840182004740, -0.125631136584 + _Complex_I* -0.992077021970, 0.315752491540 + _Complex_I* -0.948841590618, 0.695031137943 + _Complex_I* -0.718979636214, 0.937604937119 + _Complex_I* -0.347702432964, 0.995762337245 + _Complex_I* 0.091963947955, 0.858064428515 + _Complex_I* 0.513542049416, 0.551594848693 + _Complex_I* 0.834112176446, 0.136632734646 + _Complex_I* 0.990621772334, -0.305203509345 + _Complex_I* 0.952287150960, -0.687009638366 + _Complex_I* 0.726648303371, -0.933688659365 + _Complex_I* 0.358085865921, -0.996721569324 + _Complex_I* -0.080908054267, -0.863710500209 + _Complex_I* -0.503988265566, -0.560817240883 + _Complex_I* -0.827939624808, -0.147617505989 + _Complex_I* -0.989044524744, 0.294616940449 + _Complex_I* -0.955615434367, 0.678903531553 + _Complex_I* -0.734227481674, 0.929657395135 + _Complex_I* -0.368425199561, 0.997558052238 + _Complex_I* 0.069842196517, 0.869250203441 + _Complex_I* 0.494372414095, 0.569970566797 + _Complex_I* 0.821665109996, 0.158584097806 + _Complex_I* 0.987345473440, -0.283994088620 + _Complex_I* 0.958826030951, -0.670713815793 + _Complex_I* 0.741716237725, -0.925511640889 + _Complex_I* 0.378719160565, -0.998271682975 + _Complex_I* -0.058767737497, -0.874682855979 + _Complex_I* -0.484695679221, -0.579053699176 + _Complex_I* -0.815289404733, -0.169531159530 + _Complex_I* -0.985524827667, 0.273336262091 + _Complex_I* -0.961918545318, 0.662441499674 + _Complex_I* -0.749113649261, 0.921251907190 + _Complex_I* -0.388966481202, 0.998862373647 + _Complex_I* 0.047686041058, 0.880007788778 + _Complex_I* 0.474959252664, 0.588065519407 + _Complex_I* 0.808813294206}; liquid-dsp-1.7.0/src/nco/tests/data/nco_sincos_fsqrt1_7.c000066400000000000000000000333431474751757600232770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // autotest nco sincos data for f=0.377964473009 // #include float complex nco_sincos_fsqrt1_7[256] = { 1.000000000000 + _Complex_I* 0.000000000000, 0.929417729782 + _Complex_I* 0.369029380357, 0.727634632866 + _Complex_I* 0.685964897829, 0.423135327397 + _Complex_I* 0.906066495743, 0.058904317893 + _Complex_I* 0.998263633182, -0.313641892575 + _Complex_I* 0.949541343608, -0.641912989417 + _Complex_I* 0.766777486640, -0.879568734108 + _Complex_I* 0.475771838153, -0.993060562667 + _Complex_I* 0.117604076781, -0.966367453272 + _Complex_I* -0.257165210044, -0.803257526443 + _Complex_I* -0.595631888176, -0.526756120043 + _Complex_I* -0.850016464545, -0.175895428035 + _Complex_I* -0.984408857333, 0.199795461237 + _Complex_I* -0.979837626175, 0.547282316042 + _Complex_I* -0.836948066817, 0.817512314214 + _Complex_I* -0.575911118237, 0.972338562249 + _Complex_I* -0.233575941320, 0.989905083997 + _Complex_I* 0.141731876011, 0.867732109487 + _Complex_I* 0.497032178200, 0.623066130519 + _Complex_I* 0.782169161371, 0.290445307576 + _Complex_I* 0.956891594334, -0.083176093733 + _Complex_I* 0.996534865136, -0.445055979995 + _Complex_I* 0.895502749673, -0.744109743372 + _Complex_I* 0.668057400093, -0.938121596793 + _Complex_I* 0.346306034644, -0.999703946129 + _Complex_I* -0.024331463036, -0.920163547338 + _Complex_I* -0.391534220918, -0.710728684262 + _Complex_I* -0.703466230439, -0.400964133096 + _Complex_I* -0.916093752828, -0.034597664351 + _Complex_I* -0.999401321603, 0.336652767782 + _Complex_I* -0.941628862103, 0.660379766665 + _Complex_I* -0.750931797023, 0.890884559273 + _Complex_I* -0.454229789917, 0.995628042491 + _Complex_I* -0.093406643266, 0.959824150645 + _Complex_I* 0.280602209256, 0.788527123674 + _Complex_I* 0.614999979863, 0.505918027668 + _Complex_I* 0.862581560944, 0.151891245788 + _Complex_I* 0.988397212386, -0.223577193999 + _Complex_I* 0.974686225574, -0.567484461944 + _Complex_I* 0.823384105659, -0.831283046614 + _Complex_I* 0.555849346867, -0.977733942036 + _Complex_I* 0.209848370473, -0.986163474863 + _Complex_I* -0.165775754701, -0.855381693965 + _Complex_I* -0.517998221646, -0.603850349342 + _Complex_I* -0.797097707687, -0.267076747662 + _Complex_I* -0.963675262139, 0.107398620363 + _Complex_I* -0.994216041082, 0.466713111501 + _Complex_I* -0.884408769491, 0.760144260739 + _Complex_I* -0.649754340398, 0.946269994744 + _Complex_I* -0.323377638447, 0.998815959813 + _Complex_I* 0.048648519224, 0.910364528935 + _Complex_I* 0.413807231035, 0.693401907701 + _Complex_I* 0.720551035248, 0.378555524829 + _Complex_I* 0.925578583709, 0.010270525265 + _Complex_I* 0.999947256764, -0.359464308278 + _Complex_I* 0.933158834858, -0.678455527940 + _Complex_I* 0.734641474875, -0.901672884794 + _Complex_I* 0.432418788707, -0.997606003243 + _Complex_I* 0.069153902954, -0.952712528707 + _Complex_I* -0.303873061728, -0.773329827890 + _Complex_I* -0.634003925300, -0.484780377312 + _Complex_I* -0.874635916123, -0.127797127559 + _Complex_I* -0.991800329798, 0.247226544974 + _Complex_I* -0.968957705713, 0.587350595903 + _Complex_I* -0.809332612399, 0.844561569887 + _Complex_I* -0.535458452795, 0.982550397988 + _Complex_I* -0.185996546781, 0.981837950701 + _Complex_I* 0.189721476283, 0.842524800322 + _Complex_I* 0.538657554336, 0.584277023699 + _Complex_I* 0.811554286279, 0.243550049538 + _Complex_I* 0.969888330361, -0.131557555439 + _Complex_I* 0.991308534013, -0.488093898561 + _Complex_I* 0.872791124031, -0.775728690804 + _Complex_I* 0.631066556129, -0.953858098906 + _Complex_I* 0.300257767846, -0.997336566835 + _Complex_I* -0.072936770247, -0.900026476647 + _Complex_I* -0.435835222687, -0.675664562503 + _Complex_I* -0.737209196211, -0.355922770904 + _Complex_I* -0.934515372346, 0.014062695080 + _Complex_I* -0.999901115414, 0.382063007175 + _Complex_I* -0.924136277044, 0.696129570446 + _Complex_I* -0.717916165824, 0.911927322820 + _Complex_I* -0.410351748984, 0.998993273758 + _Complex_I* -0.044860216082, 0.945036798307 + _Complex_I* 0.326963988607, 0.757674637528 + _Complex_I* 0.652632472106, 0.463355684742 + _Complex_I* 0.886172392606, 0.103627339662 + _Complex_I* 0.994616194557, -0.270729511199 + _Complex_I* 0.962655458493, -0.606868955028 + _Complex_I* 0.794801907033, -0.857340021717 + _Complex_I* 0.514750509629, -0.986785078242 + _Complex_I* 0.162034593094, -0.976931072688 + _Complex_I* -0.213554862310, -0.829169041221 + _Complex_I* -0.558997943718, -0.564357743106 + _Complex_I* -0.825530337296, -0.219879143544 + _Complex_I* -0.975527120194, 0.155638594267 + _Complex_I* -0.987814065487, 0.509185681445 + _Complex_I* -0.860656692190, 0.790853805905 + _Complex_I* -0.612005112466, 0.960881416303 + _Complex_I* -0.276960112297, 0.995266643155 + _Complex_I* 0.097181834844, 0.889155511714 + _Complex_I* 0.457605152930, 0.657527151087 + _Complex_I* 0.753430849902, 0.333079272352 + _Complex_I* 0.942898827197, -0.038387588793 + _Complex_I* 0.999262924873, -0.404435483608 + _Complex_I* 0.914566530985, -0.713391429243 + _Complex_I* 0.700765773053, -0.921641801618 + _Complex_I* 0.388041736814, -0.999789032622 + _Complex_I* 0.020539967128, -0.936801504302 + _Complex_I* -0.349861317578, -0.741570822148 + _Complex_I* -0.670874590172, -0.441656635685 + _Complex_I* -0.897184159555, -0.079396193214 + _Complex_I* -0.996843139367, 0.294072176383 + _Complex_I* -0.955783215524, 0.626027982347 + _Complex_I* -0.779800593305, 0.869610835882 + _Complex_I* -0.493737778701, 0.990435475412 + _Complex_I* -0.137976697470, 0.971445746224 + _Complex_I* 0.237261800850, 0.815322324712 + _Complex_I* 0.579007346089, 0.544104301925 + _Complex_I* 0.839017585410, 0.196078045407 + _Complex_I* 0.980588292868, -0.179627478280 + _Complex_I* 0.983734704606, -0.529975971546 + _Complex_I* 0.848012658858, -0.805510650347 + _Complex_I* 0.592581295839, -0.967335788375 + _Complex_I* 0.253498466521, -0.992607414390 + _Complex_I* -0.121369357324, -0.877758070920 + _Complex_I* -0.479104131619, -0.639000412754 + _Complex_I* -0.769206391354, -0.310038554984 + _Complex_I* -0.950723984353, 0.062689752919 + _Complex_I* -0.998033063019, 0.426568490660 + _Complex_I* -0.904455263004, 0.730230883453 + _Complex_I* -0.683200451443, 0.930810569171 + _Complex_I* -0.365501962128, 0.999992808660 + _Complex_I* 0.003792443700, 0.928011522874 + _Complex_I* 0.372551490955, 0.725027916943 + _Complex_I* 0.688719478201, 0.419696078314 + _Complex_I* 0.907664696817, 0.055118035666 + _Complex_I* 0.998479845638, -0.317240719156 + _Complex_I* 0.948345045914, -0.644816333651 + _Complex_I* 0.764337553609, -0.881366746740 + _Complex_I* 0.472432701811, -0.993499428070 + _Complex_I* 0.113837104776, -0.965385219214 + _Complex_I* -0.260828254841, -0.800992849544 + _Complex_I* -0.598673913729, -0.523528692375 + _Complex_I* -0.852008044716, -0.172160847942 + _Complex_I* -0.985068851622, 0.203510003471 + _Complex_I* -0.979072866791, 0.550452458771 + _Complex_I* -0.834866510667, 0.819690545696 + _Complex_I* -0.572806607239, 0.973217393439 + _Complex_I* -0.229886722341, 0.989360455092 + _Complex_I* 0.145485016068, 0.865840902777 + _Complex_I* 0.500319429044, 0.620095317331 + _Complex_I* 0.784526479747, 0.286814261387 + _Complex_I* 0.957986210477, -0.086954797956 + _Complex_I* 0.996212258062, -0.448448923206 + _Complex_I* 0.893808460060, -0.746637962304 + _Complex_I* 0.665230601556, -0.939428196580 + _Complex_I* 0.342745770900, -0.999604481214 + _Complex_I* -0.028122608992, -0.918672058640 + _Complex_I* -0.395021073709, -0.708055717096 + _Complex_I* -0.706156570094, -0.397487015646 + _Complex_I* -0.917607798786, -0.030807242302 + _Complex_I* -0.999525344262, 0.340221421243 + _Complex_I* -0.940345353861, 0.663222884212 + _Complex_I* -0.748421943731, 0.892600793524 + _Complex_I* -0.450847893862, 0.995975122026 + _Complex_I* -0.089630108250, 0.958753080142 + _Complex_I* 0.284240270403, 0.786189100308 + _Complex_I* 0.617986001910, 0.502643097433 + _Complex_I* 0.864494023463, 0.148141712706 + _Complex_I* 0.988966143483, -0.227272028815 + _Complex_I* 0.973831312353, -0.570603018834 + _Complex_I* 0.821226031551, -0.833385095928 + _Complex_I* 0.552692755412, -0.978522748949 + _Complex_I* 0.206138860453, -0.985527687809 + _Complex_I* -0.169514532008, -0.853411063532 + _Complex_I* -0.521238483461, -0.600823058669 + _Complex_I* -0.799382043938, -0.263420142846 + _Complex_I* -0.964681205551, 0.111168356384 + _Complex_I* -0.993801588114, 0.470063825674 + _Complex_I* -0.882632426207, 0.762602951037 + _Complex_I* -0.646866863481, 0.947489581282 + _Complex_I* -0.319786637248, 0.998624280217 + _Complex_I* 0.052436122669, 0.908788641568 + _Complex_I* 0.417256761428, 0.690664271978 + _Complex_I* 0.723175541216, 0.375042597839 + _Complex_I* 0.927007578074, 0.006478207732 + _Complex_I* 0.999979016192, -0.363000675592 + _Complex_I* 0.931788876044, -0.681236735369 + _Complex_I* 0.732063187426, -0.903306324468 + _Complex_I* 0.428996135385, -0.997861091402 + _Complex_I* 0.065370041044, -0.951553255949 + _Complex_I* -0.307483985100, -0.770919842419 + _Complex_I* -0.636932175796, -0.481459883622 + _Complex_I* -0.876468128606, -0.124034861615 + _Complex_I* -0.992277860835, 0.250899484630 + _Complex_I* -0.968013144855, 0.590415720432 + _Complex_I* -0.807099298145, 0.846586192393 + _Complex_I* -0.532251649927, 0.983248713565 + _Complex_I* -0.182268942150, 0.981111381953 + _Complex_I* 0.193443677081, 0.840475912991 + _Complex_I* 0.541848908537, 0.581195048024 + _Complex_I* 0.813764287833, 0.239870051199 + _Complex_I* 0.970805005414, -0.135316091168 + _Complex_I* 0.990802480554, -0.491400399711 + _Complex_I* 0.870933778863, -0.778116396659 + _Complex_I* 0.628120110528, -0.954989950067 + _Complex_I* 0.296638155453, -0.997052786053 + _Complex_I* -0.076718588513, -0.898367123706 + _Complex_I* -0.439245388188, -0.672863879197 + _Complex_I* -0.739766314502, -0.352376114406 + _Complex_I* -0.935858468998, 0.017854662635 + _Complex_I* -0.999840592806, 0.385564994432 + _Complex_I* -0.922680678821, 0.698847220981 + _Complex_I* -0.715270970841, 0.913477000745 + _Complex_I* -0.406890364975, 0.999156219501 + _Complex_I* -0.041071267730, 0.943790009707 + _Complex_I* 0.330545636150, 0.755194116925 + _Complex_I* 0.655501217209, 0.459991593687 + _Complex_I* 0.887923270186, 0.099854568522 + _Complex_I* 0.995002042784, -0.274378380919 + _Complex_I* 0.961621809281, -0.609878832312 + _Complex_I* 0.792494674997, -0.859286018620 + _Complex_I* 0.511495394119, -0.987392489006 + _Complex_I* 0.158291100995, -0.976114152452 + _Complex_I* -0.217258282656, -0.827043110154 + _Complex_I* -0.562138500679, -0.561222907291 + _Complex_I* -0.827664695593, -0.216177930638 + _Complex_I* -0.976353984119, 0.159383704246 + _Complex_I* -0.987216711174, 0.512446011768 + _Complex_I* -0.858719444885, 0.793169113539 + _Complex_I* -0.609001442796, 0.961924861910 + _Complex_I* -0.273314031909, 0.994890929216 + _Complex_I* 0.100955628686, 0.887413675715 + _Complex_I* 0.460973934354, 0.654665078505 + _Complex_I* 0.755919066426, 0.329500986349 + _Complex_I* 0.944155230878, -0.042176961119 + _Complex_I* 0.999110156064, -0.407901017253 + _Complex_I* 0.913026155224, -0.716043913743 + _Complex_I* 0.698055236776, -0.923106800218 + _Complex_I* 0.384543671630, -0.999859739467 + _Complex_I* 0.016748175800, -0.935467938094 + _Complex_I* -0.353411568569, -0.739021235147 + _Complex_I* -0.673682131277, -0.438250939168 + _Complex_I* -0.898852665523, -0.075615150766 + _Complex_I* -0.997137076321, 0.297694815644 + _Complex_I* -0.954661089989, 0.628980830213 + _Complex_I* -0.777420809616, 0.871477054943 + _Complex_I* -0.490436277929, 0.990951621711 + _Complex_I* -0.134219534454, 0.970538958206 + _Complex_I* 0.240944247919, 0.813120608690 + _Complex_I* 0.582095246264, 0.540918462130 + _Complex_I* 0.841075036680, 0.192357809450 + _Complex_I* 0.981324856071, -0.183356945000 + _Complex_I* 0.983046403137, -0.533188200573 + _Complex_I* 0.845996656476}; liquid-dsp-1.7.0/src/nco/tests/nco_crcf_autotest.c000066400000000000000000000127141474751757600222060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // forward declaration of internal method to constrain phase uint32_t nco_crcf_constrain(float _theta); // compute phase-constrained error uint32_t nco_crcf_constrain_error(float _theta, uint32_t _expected) { uint32_t phase = nco_crcf_constrain(_theta); uint32_t error = phase > _expected ? phase - _expected : _expected - phase; return error < 0x80000000 ? error : 0xffffffff - error; } // test phase constraint void autotest_nco_crcf_constrain() { uint32_t tol = 0x00001fff; // phase: 0 mod 2 pi CONTEND_LESS_THAN( nco_crcf_constrain_error( 0.0f, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 2*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 4*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 6*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 20*M_PI, 0), tol ); // phase: 0 mod 2 pi (negative) CONTEND_LESS_THAN( nco_crcf_constrain_error( -0.0f, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -2*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -4*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -6*M_PI, 0), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-20*M_PI, 0), tol ); // phase: pi mod 2 pi CONTEND_LESS_THAN( nco_crcf_constrain_error( M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 3*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 5*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 7*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( 27*M_PI, 0x80000000), tol ); // phase: pi mod 2 pi (negative) CONTEND_LESS_THAN( nco_crcf_constrain_error( -M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -3*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -5*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error( -7*M_PI, 0x80000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-27*M_PI, 0x80000000), tol ); // check other values CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.500*M_PI, 0x40000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.250*M_PI, 0x20000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.125*M_PI, 0x10000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.750*M_PI, 0x60000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.500*M_PI, 0xc0000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.250*M_PI, 0xe0000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.125*M_PI, 0xf0000000), tol ); // check phase near boundaries CONTEND_LESS_THAN( nco_crcf_constrain_error(+0.000001f, 0x00000000), tol ); CONTEND_LESS_THAN( nco_crcf_constrain_error(-0.000001f, 0x00000000), tol ); } // test copying object void autotest_nco_crcf_copy() { // create and initialize object nco_crcf nco_0 = nco_crcf_create(LIQUID_VCO); nco_crcf_set_phase (nco_0, 1.23456f); nco_crcf_set_frequency (nco_0, 5.67890f); nco_crcf_pll_set_bandwidth(nco_0, 0.011f); // copy object nco_crcf nco_1 = nco_crcf_copy(nco_0); unsigned int i, n = 240; float complex v0, v1; for (i=0; i #include #include "autotest/autotest.h" #include "liquid.h" // declare external arrays extern float complex nco_sincos_fsqrt1_2[]; extern float complex nco_sincos_fsqrt1_3[]; extern float complex nco_sincos_fsqrt1_5[]; extern float complex nco_sincos_fsqrt1_7[]; // autotest helper function // _type : NCO type (e.g. LIQUID_NCO) // _phase : initial phase // _frequency : initial frequency // _sincos : external sin/cosine data // _num_samples: number of samples to test // _tol : error tolerance void nco_crcf_frequency_test(int _type, float _phase, float _frequency, float complex * _sincos, unsigned int _num_samples, float _tol) { // create object nco_crcf nco = nco_crcf_create(_type); // set phase and frequency nco_crcf_set_phase(nco, _phase); nco_crcf_set_frequency(nco, _frequency); // run trials unsigned int i; for (i=0; i<_num_samples; i++) { // compute complex output float complex y_test; nco_crcf_cexpf(nco, &y_test); // compare to expected output float complex y = _sincos[i]; // run tests CONTEND_DELTA( crealf(y_test), crealf(y), _tol ); CONTEND_DELTA( cimagf(y_test), cimagf(y), _tol ); // step oscillator nco_crcf_step(nco); } // destroy object nco_crcf_destroy(nco); } // test floating point precision nco phase void autotest_nco_crcf_frequency() { // error tolerance (higher for NCO) float tol = 0.04f; // test frequencies with irrational values nco_crcf_frequency_test(LIQUID_NCO, 0.0f, 0.707106781186547, nco_sincos_fsqrt1_2, 256, tol); // 1/sqrt(2) nco_crcf_frequency_test(LIQUID_NCO, 0.0f, 0.577350269189626, nco_sincos_fsqrt1_3, 256, tol); // 1/sqrt(3) nco_crcf_frequency_test(LIQUID_NCO, 0.0f, 0.447213595499958, nco_sincos_fsqrt1_5, 256, tol); // 1/sqrt(5) nco_crcf_frequency_test(LIQUID_NCO, 0.0f, 0.377964473009227, nco_sincos_fsqrt1_7, 256, tol); // 1/sqrt(7) } liquid-dsp-1.7.0/src/nco/tests/nco_crcf_mix_autotest.c000066400000000000000000000102751474751757600230630ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" void testbench_nco_crcf_mix(int _type, float _phase, float _frequency) { // options unsigned int buf_len = 1200; float tol = 1e-2f; // create and initialize object nco_crcf nco = nco_crcf_create(_type); nco_crcf_set_phase (nco, _phase); nco_crcf_set_frequency(nco, _frequency); // generate signal (pseudo-random) float complex buf_0[buf_len]; float complex buf_1[buf_len]; unsigned int i; for (i=0; i M_PI) { theta -= 2*M_PI; } while (theta < -M_PI) { theta += 2*M_PI; } } // destroy object nco_crcf_destroy(nco); } // test NCO mixing void autotest_nco_crcf_mix_nco_0() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, 0.000f); } void autotest_nco_crcf_mix_nco_1() { testbench_nco_crcf_mix(LIQUID_NCO, 1.234f, 0.000f); } void autotest_nco_crcf_mix_nco_2() { testbench_nco_crcf_mix(LIQUID_NCO, -1.234f, 0.000f); } void autotest_nco_crcf_mix_nco_3() { testbench_nco_crcf_mix(LIQUID_NCO, 99.000f, 0.000f); } void autotest_nco_crcf_mix_nco_4() { testbench_nco_crcf_mix(LIQUID_NCO, M_PI, 0.000f); } void autotest_nco_crcf_mix_nco_5() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, M_PI); } void autotest_nco_crcf_mix_nco_6() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, -M_PI); } void autotest_nco_crcf_mix_nco_7() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, 0.123f); } void autotest_nco_crcf_mix_nco_8() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, -0.123f); } void autotest_nco_crcf_mix_nco_9() { testbench_nco_crcf_mix(LIQUID_NCO, 0.000f, 1e-5f ); } // test VCO mixing void autotest_nco_crcf_mix_vco_0() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, 0.000f); } void autotest_nco_crcf_mix_vco_1() { testbench_nco_crcf_mix(LIQUID_VCO, 1.234f, 0.000f); } void autotest_nco_crcf_mix_vco_2() { testbench_nco_crcf_mix(LIQUID_VCO, -1.234f, 0.000f); } void autotest_nco_crcf_mix_vco_3() { testbench_nco_crcf_mix(LIQUID_VCO, 99.000f, 0.000f); } void autotest_nco_crcf_mix_vco_4() { testbench_nco_crcf_mix(LIQUID_VCO, M_PI, 0.000f); } void autotest_nco_crcf_mix_vco_5() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, M_PI); } void autotest_nco_crcf_mix_vco_6() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, -M_PI); } void autotest_nco_crcf_mix_vco_7() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, 0.123f); } void autotest_nco_crcf_mix_vco_8() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, -0.123f); } void autotest_nco_crcf_mix_vco_9() { testbench_nco_crcf_mix(LIQUID_VCO, 0.000f, 1e-5f ); } liquid-dsp-1.7.0/src/nco/tests/nco_crcf_phase_autotest.c000066400000000000000000000173471474751757600233750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2018 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper function // _theta : input phase // _cos : expected output: cos(_theta) // _sin : expected output: sin(_theta) // _type : NCO type (e.g. LIQUID_NCO) // _tol : error tolerance void nco_crcf_phase_test(float _theta, float _cos, float _sin, int _type, float _tol) { // create object nco_crcf nco = nco_crcf_create(_type); // set phase nco_crcf_set_phase(nco, _theta); // compute cosine and sine outputs float c = nco_crcf_cos(nco); float s = nco_crcf_sin(nco); if (liquid_autotest_verbose) { printf("cos(%8.5f) = %8.5f (%8.5f) e:%8.5f, sin(%8.5f) = %8.5f (%8.5f) e:%8.5f\n", _theta, _cos, c, _cos-c, _theta, _sin, s, _sin-s); } // run tests CONTEND_DELTA( c, _cos, _tol ); CONTEND_DELTA( s, _sin, _tol ); // destroy object nco_crcf_destroy(nco); } // test floating point precision nco phase void autotest_nco_crcf_phase() { // error tolerance (higher for NCO) float tol = 0.02f; nco_crcf_phase_test(-6.283185307f, 1.000000000f, 0.000000000f, LIQUID_NCO, tol); nco_crcf_phase_test(-6.195739393f, 0.996179042f, 0.087334510f, LIQUID_NCO, tol); nco_crcf_phase_test(-5.951041106f, 0.945345356f, 0.326070787f, LIQUID_NCO, tol); nco_crcf_phase_test(-5.131745978f, 0.407173250f, 0.913350943f, LIQUID_NCO, tol); nco_crcf_phase_test(-4.748043551f, 0.035647016f, 0.999364443f, LIQUID_NCO, tol); nco_crcf_phase_test(-3.041191113f, -0.994963998f, -0.100232943f, LIQUID_NCO, tol); nco_crcf_phase_test(-1.947799864f, -0.368136099f, -0.929771914f, LIQUID_NCO, tol); nco_crcf_phase_test(-1.143752030f, 0.414182352f, -0.910193924f, LIQUID_NCO, tol); nco_crcf_phase_test(-1.029377689f, 0.515352252f, -0.856978446f, LIQUID_NCO, tol); nco_crcf_phase_test(-0.174356887f, 0.984838307f, -0.173474811f, LIQUID_NCO, tol); nco_crcf_phase_test(-0.114520496f, 0.993449692f, -0.114270338f, LIQUID_NCO, tol); nco_crcf_phase_test( 0.000000000f, 1.000000000f, 0.000000000f, LIQUID_NCO, tol); nco_crcf_phase_test( 1.436080000f, 0.134309213f, 0.990939471f, LIQUID_NCO, tol); nco_crcf_phase_test( 2.016119855f, -0.430749878f, 0.902471353f, LIQUID_NCO, tol); nco_crcf_phase_test( 2.996498473f, -0.989492293f, 0.144585621f, LIQUID_NCO, tol); nco_crcf_phase_test( 3.403689755f, -0.965848729f, -0.259106603f, LIQUID_NCO, tol); nco_crcf_phase_test( 3.591162483f, -0.900634128f, -0.434578148f, LIQUID_NCO, tol); nco_crcf_phase_test( 5.111428476f, 0.388533479f, -0.921434607f, LIQUID_NCO, tol); nco_crcf_phase_test( 5.727585681f, 0.849584319f, -0.527452828f, LIQUID_NCO, tol); nco_crcf_phase_test( 6.283185307f, 1.000000000f, -0.000000000f, LIQUID_NCO, tol); } // // test floating point precision nco // void autotest_nco_basic() { nco_crcf p = nco_crcf_create(LIQUID_NCO); unsigned int i; // loop index float s, c; // sine/cosine result float tol=1e-4f; // error tolerance float f=0.0f; // frequency to test nco_crcf_set_phase( p, 0.0f); CONTEND_DELTA( nco_crcf_cos(p), 1.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 0.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 0.0f, tol ); CONTEND_DELTA( c, 1.0f, tol ); nco_crcf_set_phase(p, M_PI/2); CONTEND_DELTA( nco_crcf_cos(p), 0.0f, tol ); CONTEND_DELTA( nco_crcf_sin(p), 1.0f, tol ); nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, 1.0f, tol ); CONTEND_DELTA( c, 0.0f, tol ); // cycle through one full period in 64 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 64.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // double frequency: cycle through one full period in 32 steps nco_crcf_set_phase(p, 0.0f); f = 2.0f * M_PI / 32.0f; nco_crcf_set_frequency(p, f); for (i=0; i<128; i++) { nco_crcf_sincos(p, &s, &c); CONTEND_DELTA( s, sinf(i*f), tol ); CONTEND_DELTA( c, cosf(i*f), tol ); nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); } // // test nco mixing // void autotest_nco_mixing() { // frequency, phase float f = 0.1f; float phi = M_PI; // error tolerance (high for NCO) float tol = 0.05f; // initialize nco object nco_crcf p = nco_crcf_create(LIQUID_NCO); nco_crcf_set_frequency(p, f); nco_crcf_set_phase(p, phi); unsigned int i; float nco_i, nco_q; for (i=0; i<64; i++) { // generate sin/cos nco_crcf_sincos(p, &nco_q, &nco_i); // mix back to zero phase complex float nco_cplx_in = nco_i + _Complex_I*nco_q; complex float nco_cplx_out; nco_crcf_mix_down(p, nco_cplx_in, &nco_cplx_out); // assert mixer output is correct CONTEND_DELTA(crealf(nco_cplx_out), 1.0f, tol); CONTEND_DELTA(cimagf(nco_cplx_out), 0.0f, tol); //printf("%3u : %12.8f + j*%12.8f\n", i, crealf(nco_cplx_out), cimagf(nco_cplx_out)); // step nco nco_crcf_step(p); } // destroy NCO object nco_crcf_destroy(p); } // // test nco block mixing // void autotest_nco_block_mixing() { // frequency, phase float f = 0.1f; float phi = M_PI; // error tolerance (high for NCO) float tol = 0.05f; unsigned int i; // number of samples unsigned int num_samples = 1024; // store samples float complex * x = (float complex*)malloc(num_samples*sizeof(float complex)); float complex * y = (float complex*)malloc(num_samples*sizeof(float complex)); // generate complex sin/cos for (i=0; i 0) { unsigned int n = 7 < num_remaining ? 7 : num_remaining; nco_crcf_mix_block_down(p, &x[i], &y[i], n); i += n; num_remaining -= n; } // assert mixer output is correct for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // // test phase-locked loop // _type : NCO type (e.g. LIQUID_NCO) // _phase_offset : initial phase offset // _freq_offset : initial frequency offset // _pll_bandwidth : bandwidth of phase-locked loop // _num_iterations : number of iterations to run // _tol : error tolerance void nco_crcf_pll_test(int _type, float _phase_offset, float _freq_offset, float _pll_bandwidth, unsigned int _num_iterations, float _tol) { // objects nco_crcf nco_tx = nco_crcf_create(_type); nco_crcf nco_rx = nco_crcf_create(_type); // initialize objects nco_crcf_set_phase(nco_tx, _phase_offset); nco_crcf_set_frequency(nco_tx, _freq_offset); nco_crcf_pll_set_bandwidth(nco_rx, _pll_bandwidth); // run loop unsigned int i; float phase_error; float complex r, v; for (i=0; i<_num_iterations; i++) { // received complex signal nco_crcf_cexpf(nco_tx,&r); nco_crcf_cexpf(nco_rx,&v); // error estimation phase_error = cargf(r*conjf(v)); // update pll nco_crcf_pll_step(nco_rx, phase_error); // update nco objects nco_crcf_step(nco_tx); nco_crcf_step(nco_rx); } // ensure phase of oscillators is locked phase_error = nco_crcf_get_phase(nco_tx) - nco_crcf_get_phase(nco_rx); while (phase_error >= 2*M_PI) phase_error -= 2*M_PI; while (phase_error <= -2*M_PI) phase_error += 2*M_PI; CONTEND_DELTA(phase_error, 0, _tol); // ensure frequency of oscillators is locked float freq_error = nco_crcf_get_frequency(nco_tx) - nco_crcf_get_frequency(nco_rx); while (freq_error >= 2*M_PI) freq_error -= 2*M_PI; while (freq_error <= -2*M_PI) freq_error += 2*M_PI; CONTEND_DELTA(freq_error, 0, _tol); if (liquid_autotest_verbose) { printf(" nco[bw:%6.4f,n=%6u], phase:%9.6f,e=%11.4e, freq:%9.6f,e=%11.4e\n", _pll_bandwidth, _num_iterations, _phase_offset, phase_error, _freq_offset, freq_error); } // clean it up nco_crcf_destroy(nco_tx); nco_crcf_destroy(nco_rx); } // test phase offsets void autotest_nco_crcf_pll_phase() { float bw[4] = {0.1f, 0.01f, 0.001f, 0.0001f}; float tol = 1e-2f; unsigned int i; for (i=0; i<4; i++) { // adjust number of steps according to loop bandwidth unsigned int num_steps = (unsigned int)(32.0f / bw[i]); // test various phase offsets nco_crcf_pll_test(LIQUID_NCO, -M_PI/1.1f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, -M_PI/2.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, -M_PI/4.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, -M_PI/8.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, M_PI/8.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, M_PI/4.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, M_PI/2.0f, 0.0f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, M_PI/1.1f, 0.0f, bw[i], num_steps, tol); } } // test phase offsets void autotest_nco_crcf_pll_freq() { float bw[4] = {0.1f, 0.05f, 0.02f, 0.01f}; float tol = 1e-2f; unsigned int i; for (i=0; i<4; i++) { // adjust number of steps according to loop bandwidth unsigned int num_steps = (unsigned int)(32.0f / bw[i]); // test various frequency offsets nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.8f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.4f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.2f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, -0.1f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.1f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.2f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.4f, bw[i], num_steps, tol); nco_crcf_pll_test(LIQUID_NCO, 0.0f, 0.8f, bw[i], num_steps, tol); } } liquid-dsp-1.7.0/src/nco/tests/nco_crcf_spectrum_autotest.c000066400000000000000000000102351474751757600241240ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "autotest/autotest.h" #include "liquid.h" // autotest helper function // _id : test id for saving log file // _type : NCO type (e.g. LIQUID_NCO) // _freq : normalized frequency (f/Fs), _freq in [-0.5,0.5) void nco_crcf_spectrum_test(int _id, int _type, float _freq) { unsigned long int num_samples = 1UL<<16; unsigned int nfft = 9600; // create object and initialize nco_crcf nco = nco_crcf_create(_type); nco_crcf_set_frequency(nco, 2*M_PI*_freq); // sample buffer unsigned int buf_len = 3*nfft; float complex buf_0[buf_len]; float complex buf_1[buf_len]; unsigned int i; for (i=0; i #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: regular phase-unwrapping // void autotest_nco_unwrap_phase() { unsigned int n=32; // number of steps float tol = 1e-6f; // error tolerance // initialize data arrays float phi[n]; // original array float theta[n]; // wrapped array float phi_hat[n]; // unwrapped array float phi0 = 3.0f; // initial phase float dphi = 0.1f; // phase step unsigned int i; for (i=0; i M_PI) theta[i] -= 2*M_PI; while (theta[i] < -M_PI) theta[i] += 2*M_PI; // initialize output phi_hat[i] = theta[i]; } // unwrap phase liquid_unwrap_phase(phi_hat, n); // compare input to output for (i=0; i #include #include #include #include "liquid.internal.h" #define LIQUID_CHROMOSOME_MAX_SIZE (32) // create chromosome with varying bits/trait // _bits_per_trait : array of bits/trait [size: _num_traits x 1] // _num_traits : number of traits in this chromosome chromosome chromosome_create(unsigned int * _bits_per_trait, unsigned int _num_traits) { // validate input unsigned int i; if (_num_traits < 1) return liquid_error_config("chromosome_create(), must have at least one trait"); for (i=0; i<_num_traits; i++) { if (_bits_per_trait[i] > LIQUID_CHROMOSOME_MAX_SIZE) return liquid_error_config("chromosome_create(), bits/trait cannot exceed %u", LIQUID_CHROMOSOME_MAX_SIZE); } chromosome q; q = (chromosome) malloc( sizeof(struct chromosome_s) ); q->num_traits = _num_traits; // initialize internal arrays q->bits_per_trait = (unsigned int *) malloc(q->num_traits*sizeof(unsigned int)); q->max_value = (unsigned long*) malloc(q->num_traits*sizeof(unsigned long)); q->traits = (unsigned long*) malloc(q->num_traits*sizeof(unsigned long)); // copy/initialize values q->num_bits = 0; for (i=0; inum_traits; i++) { q->bits_per_trait[i] = _bits_per_trait[i]; q->max_value[i] = 1LU << q->bits_per_trait[i]; q->traits[i] = 0LU; q->num_bits += q->bits_per_trait[i]; } return q; } // create basic chromosome // _num_traits : number of traits in this chromosome // _bits_per_trait : number of bits/trait for all traits chromosome chromosome_create_basic(unsigned int _num_traits, unsigned int _bits_per_trait) { // validate input if (_num_traits == 0) return liquid_error_config("chromosome_create_basic(), must have at least one trait"); if (_bits_per_trait == 0 || _bits_per_trait > 64) return liquid_error_config("chromosome_create_basic(), bits per trait out of range"); unsigned int * bpt = (unsigned int *) malloc(_num_traits*sizeof(unsigned int)); unsigned int i; for (i=0; i<_num_traits; i++) bpt[i] = _bits_per_trait; // create chromosome chromosome q = chromosome_create(bpt, _num_traits); // free bits/trait array free(bpt); return q; } // create chromosome cloning a parent chromosome chromosome_create_clone(chromosome _parent) { // create chromosome chromosome q = chromosome_create(_parent->bits_per_trait, _parent->num_traits); // copy internal values chromosome_copy(_parent, q); return q; } // copy chromosome int chromosome_copy(chromosome _parent, chromosome _child) { // copy internal values unsigned int i; for (i=0; i<_parent->num_traits; i++) _child->traits[i] = _parent->traits[i]; return LIQUID_OK; } int chromosome_destroy(chromosome _q) { free(_q->bits_per_trait); free(_q->max_value); free(_q->traits); free(_q); return LIQUID_OK; } unsigned int chromosome_get_num_traits(chromosome _q) { return _q->num_traits; } int chromosome_print(chromosome _q) { unsigned int i,j; printf("num_traits; i++) { for (j=0; j<_q->bits_per_trait[i]; j++) { unsigned int bit = (_q->traits[i] >> (_q->bits_per_trait[i]-j-1) ) & 1; printf("%c", bit ? '1' : '0'); } if (i != _q->num_traits-1) printf("."); } printf(">\n"); return LIQUID_OK; } int chromosome_printf(chromosome _q) { unsigned int i; printf("num_traits; i++) printf("%6.3f", chromosome_valuef(_q,i)); printf(">\n"); return LIQUID_OK; } // clear chromosome (set traits to zero) int chromosome_reset(chromosome _q) { unsigned int i; for (i=0; i<_q->num_traits; i++) _q->traits[i] = 0; return LIQUID_OK; } // initialize chromosome on integer values int chromosome_init(chromosome _c, unsigned int * _v) { unsigned int i; for (i=0; i<_c->num_traits; i++) { //printf("===> [%3u] bits:%3u, max:%12lu, value:%12lu\n", i, _c->bits_per_trait[i], _c->max_value[i], _v[i]); if (_v[i] >= _c->max_value[i]) return liquid_error(LIQUID_EIRANGE,"chromosome_init(), value exceeds maximum"); _c->traits[i] = _v[i]; } return LIQUID_OK; } // initialize chromosome on floating-point values int chromosome_initf(chromosome _c, float * _v) { unsigned int i; for (i=0; i<_c->num_traits; i++) { if (_v[i] < 0.0f || _v[i] > 1.0f) return liquid_error(LIQUID_EIRANGE,"chromosome_initf(), value must be in [0,1]"); // quantize sample unsigned long N = 1LU << _c->bits_per_trait[i]; _c->traits[i] = (unsigned long) floorf( _v[i] * N ); //printf("===> [%3u] quantizing %8.2f, bits:%3u, N:%12lu, trait:%12lu/%12lu => %12.8f\n", // i, _v[i], _c->bits_per_trait[i], N, _c->traits[i], _c->max_value[i], chromosome_valuef(_c,i)); } return LIQUID_OK; } // mutate bit at _index int chromosome_mutate(chromosome _q, unsigned int _index) { if (_index >= _q->num_bits) return liquid_error(LIQUID_EIRANGE,"chromosome_mutate(), maximum index exceeded"); // search for unsigned int i; unsigned int t=0; for (i=0; i<_q->num_traits; i++) { unsigned int b = _q->bits_per_trait[i]; if (t == _index) { _q->traits[i] ^= (unsigned long)(1LU << (b-1)); return LIQUID_OK; } else if (t > _index) { _q->traits[i-1] ^= (unsigned long)(1LU << (t-_index-1)); return LIQUID_OK; } else { t += b; } } _q->traits[i-1] ^= (unsigned long)(1 << (t-_index-1)); return LIQUID_OK; } // crossover parent chromosomes and store in child // _p1 : first parent chromosome // _p2 : second parent chromosome // _q : child chromosome // _threshold : crossover point int chromosome_crossover(chromosome _p1, chromosome _p2, chromosome _q, unsigned int _threshold) { if (_threshold > _q->num_bits) return liquid_error(LIQUID_EIRANGE,"chromosome_crossover(), maximum index exceeded"); // TODO : validate input on all properties of _p1, _p2, and _q // find crossover point unsigned int i; unsigned int t=0; for (i=0; i<_q->num_traits; i++) { if (t >= _threshold) break; else t += _q->bits_per_trait[i]; // child gets first parent's traits up until // threshold is reached _q->traits[i] = _p1->traits[i]; } #if 0 printf(" crossover point : %u\n", i); printf(" accumulator : %u\n", t); printf(" remainder : %u\n", t - _threshold); #endif // determine if trait is split unsigned int rem = t - _threshold; if (rem > 0) { // split trait on remainder unsigned int b = _q->bits_per_trait[i-1]; unsigned int mask1 = ((1 << (b-rem)) - 1) << rem; unsigned int mask2 = ((1 << rem ) - 1); _q->traits[i-1] = (_p1->traits[i-1] & mask1) | (_p2->traits[i-1] & mask2); #if 0 printf(" b : %u\n", b); printf(" mask1 : %.8x\n", mask1); printf(" mask2 : %.8x\n", mask2); #endif } // finish crossover for ( ; i<_q->num_traits; i++) { // child gets second parent's traits beyond threshold _q->traits[i] = _p2->traits[i]; } return LIQUID_OK; } int chromosome_init_random(chromosome _q) { unsigned int i; for (i=0; i<_q->num_traits; i++) _q->traits[i] = rand() & (_q->max_value[i]-1LU); return LIQUID_OK; } float chromosome_valuef(chromosome _q, unsigned int _index) { if (_index > _q->num_traits) { liquid_error(LIQUID_EIRANGE,"chromosome_valuef(), trait index exceeded"); return 0.0f; } return (float) (_q->traits[_index]) / (float)(_q->max_value[_index]-1LU); } unsigned int chromosome_value(chromosome _q, unsigned int _index) { if (_index > _q->num_traits) { liquid_error(LIQUID_EIRANGE,"chromosome_value(), trait index exceeded"); return 0.0f; } return _q->traits[_index]; } liquid-dsp-1.7.0/src/optim/src/gasearch.c000066400000000000000000000306271474751757600202600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // gasearch.c // #include #include #include #include #include "liquid.internal.h" #define LIQUID_GA_SEARCH_MAX_POPULATION_SIZE (1024) #define LIQUID_GA_SEARCH_MAX_CHROMOSOME_SIZE (32) #define LIQUID_DEBUG_GA_SEARCH 0 // Create a simple gasearch object; parameters are specified internally // _utility : chromosome fitness utility function // _userdata : user data, void pointer passed to _utility() callback // _parent : initial population parent chromosome, governs precision, etc. // _minmax : search direction gasearch gasearch_create(gasearch_utility _utility, void * _userdata, chromosome _parent, int _minmax) { return gasearch_create_advanced(_utility,_userdata,_parent,_minmax,16,0.02f); } // Create a gasearch object, specifying search parameters // _utility : chromosome fitness utility function // _userdata : user data, void pointer passed to _utility() callback // _parent : initial population parent chromosome, governs precision, etc. // _minmax : search direction // _population_size : number of chromosomes in population // _mutation_rate : probability of mutating chromosomes gasearch gasearch_create_advanced(gasearch_utility _utility, void * _userdata, chromosome _parent, int _minmax, unsigned int _population_size, float _mutation_rate) { // validate input if (_utility == NULL) return liquid_error_config("gasearch_create(), utility function cannot be NULL") if (_parent == NULL) return liquid_error_config("gasearch_create(), parent cannot be NULL") if (_population_size < 2) return liquid_error_config("gasearch_create(), population size exceeds minimum"); if (_population_size > LIQUID_GA_SEARCH_MAX_POPULATION_SIZE) return liquid_error_config("gasearch_create(), population size exceeds maximum (%u)",LIQUID_GA_SEARCH_MAX_POPULATION_SIZE); if (_mutation_rate < 0.0f || _mutation_rate > 1.0f) return liquid_error_config("gasearch_create(), mutation rate must be in [0,1]"); // create object and initialize values gasearch ga = (gasearch) malloc( sizeof(struct gasearch_s) ); ga->userdata = _userdata; ga->num_parameters = _parent->num_traits; ga->population_size = _population_size; ga->mutation_rate = _mutation_rate; ga->get_utility = _utility; ga->minimize = ( _minmax==LIQUID_OPTIM_MINIMIZE ) ? 1 : 0; ga->bits_per_chromosome = _parent->num_bits; // initialize selection size be be 25% of population, minimum of 2 ga->selection_size = ( ga->population_size >> 2 ) < 2 ? 2 : ga->population_size >> 2; // allocate internal arrays ga->population = (chromosome*) malloc( sizeof(chromosome)*(ga->population_size) ); ga->utility = (float*) calloc( sizeof(float), ga->population_size ); // create optimum chromosome (clone) ga->c = chromosome_create_clone(_parent); //printf("num_parameters: %d\n", ga->num_parameters); //printf("population_size: %d\n", ga->population_size); //printf("\nbits_per_chromosome: %d\n", ga->bits_per_chromosome); // create population unsigned int i; for (i=0; ipopulation_size; i++) ga->population[i] = chromosome_create_clone(_parent); // initialize population to random, preserving first chromosome for (i=1; ipopulation_size; i++) chromosome_init_random( ga->population[i] ); // evaluate population gasearch_evaluate(ga); // rank chromosomes gasearch_rank(ga); // set global utility optimum ga->utility_opt = ga->utility[0]; // return object return ga; } // destroy a gasearch object int gasearch_destroy(gasearch _g) { unsigned int i; for (i=0; i<_g->population_size; i++) chromosome_destroy( _g->population[i] ); free(_g->population); // destroy optimum chromosome chromosome_destroy(_g->c); free(_g->utility); free(_g); return LIQUID_OK; } // print search parameter internals int gasearch_print(gasearch _g) { printf("num_parameters); printf(", bits=%u", _g->bits_per_chromosome); printf(", population=%u", _g->population_size); printf(", selection=%u", _g->selection_size); printf(", mutation=%g", _g->mutation_rate); printf(">\n"); return LIQUID_OK; } // set population/selection size // _q : ga search object // _population_size : new population size (number of chromosomes) // _selection_size : selection size (number of parents for new generation) int gasearch_set_population_size(gasearch _g, unsigned int _population_size, unsigned int _selection_size) { // validate input if (_population_size < 2) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), population must be at least 2"); if (_population_size > LIQUID_GA_SEARCH_MAX_POPULATION_SIZE) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), population exceeds maximum (%u)",LIQUID_GA_SEARCH_MAX_POPULATION_SIZE); if (_selection_size == 0) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), selection size must be greater than zero"); if (_selection_size >= _population_size) return liquid_error(LIQUID_EICONFIG,"gasearch_set_population_size(), selection size must be less than population"); // re-size arrays _g->population = (chromosome*) realloc( _g->population, _population_size*sizeof(chromosome) ); _g->utility = (float*) realloc( _g->utility, _population_size*sizeof(float) ); // initialize new chromosomes (copies) if (_population_size > _g->population_size) { unsigned int i; unsigned int k = _g->population_size-1; // least optimal for (i=_g->population_size; i<_population_size; i++) { // clone chromosome, copying internal values _g->population[i] = chromosome_create_clone(_g->population[k]); // copy utility _g->utility[i] = _g->utility[k]; } } // set internal variables _g->population_size = _population_size; _g->selection_size = _selection_size; return LIQUID_OK; } // set mutation rate int gasearch_set_mutation_rate(gasearch _g, float _mutation_rate) { if (_mutation_rate < 0.0f || _mutation_rate > 1.0f) return liquid_error(LIQUID_EIRANGE,"gasearch_set_mutation_rate(), mutation rate must be in [0,1]"); _g->mutation_rate = _mutation_rate; return LIQUID_OK; } // Execute the search // _g : ga search object // _max_iterations : maximum number of iterations to run before bailing // _tarutility : target utility float gasearch_run(gasearch _g, unsigned int _max_iterations, float _tarutility) { unsigned int i=0; do { i++; gasearch_evolve(_g); } while ( optim_threshold_switch(_g->utility[0], _tarutility, _g->minimize) && i < _max_iterations); // return optimum utility return _g->utility_opt; } // iterate over one evolution of the search algorithm int gasearch_evolve(gasearch _g) { // Inject random chromosome at end chromosome_init_random(_g->population[_g->population_size-1]); // Crossover gasearch_crossover(_g); // Mutation gasearch_mutate(_g); // Evaluation gasearch_evaluate(_g); // Rank gasearch_rank(_g); if ( optim_threshold_switch(_g->utility_opt, _g->utility[0], _g->minimize) ) { // update optimum _g->utility_opt = _g->utility[0]; // copy optimum chromosome chromosome_copy(_g->population[0], _g->c); #if LIQUID_DEBUG_GA_SEARCH printf(" utility: %0.2E", _g->utility_opt); chromosome_printf(_g->c); #endif } return LIQUID_OK; } // get optimal chromosome // _g : ga search object // _c : output optimal chromosome // _utility_opt : fitness of _c int gasearch_getopt(gasearch _g, chromosome _c, float * _utility_opt) { // copy optimum chromosome chromosome_copy(_g->c, _c); // copy optimum utility *_utility_opt = _g->utility_opt; return LIQUID_OK; } // evaluate fitness of entire population int gasearch_evaluate(gasearch _g) { unsigned int i; for (i=0; i<_g->population_size; i++) _g->utility[i] = _g->get_utility(_g->userdata, _g->population[i]); return LIQUID_OK; } // crossover population int gasearch_crossover(gasearch _g) { chromosome p1, p2; // parental chromosomes chromosome c; // child chromosome unsigned int threshold; unsigned int i; for (i=_g->selection_size; i<_g->population_size; i++) { // ensure fittest member is used at least once as parent p1 = (i==_g->selection_size) ? _g->population[0] : _g->population[rand() % _g->selection_size]; p2 = _g->population[rand() % _g->selection_size]; threshold = rand() % _g->bits_per_chromosome; c = _g->population[i]; //printf(" gasearch_crossover, p1: %d, p2: %d, c: %d\n", p1, p2, c); chromosome_crossover(p1, p2, c, threshold); } return LIQUID_OK; } // mutate population int gasearch_mutate(gasearch _g) { unsigned int i; unsigned int index; // mutate all but first (best) chromosome //for (i=_g->selection_size; i<_g->population_size; i++) { for (i=1; i<_g->population_size; i++) { // generate random number and mutate if within mutation_rate range unsigned int num_mutations = 0; // force at least one mutation (otherwise nothing has changed) while ( randf() < _g->mutation_rate || num_mutations == 0) { // generate random mutation index index = rand() % _g->bits_per_chromosome; // mutate chromosome at index chromosome_mutate( _g->population[i], index ); // num_mutations++; if (num_mutations == _g->bits_per_chromosome) break; } } return LIQUID_OK; } // rank population by fitness int gasearch_rank(gasearch _g) { unsigned int i, j; float u_tmp; // temporary utility placeholder chromosome c_tmp; // temporary chromosome placeholder (pointer) for (i=0; i<_g->population_size; i++) { for (j=_g->population_size-1; j>i; j--) { if ( optim_threshold_switch(_g->utility[j], _g->utility[j-1], !(_g->minimize)) ) { // swap chromosome pointers c_tmp = _g->population[j]; _g->population[j] = _g->population[j-1]; _g->population[j-1] = c_tmp; // swap utility values u_tmp = _g->utility[j]; _g->utility[j] = _g->utility[j-1]; _g->utility[j-1] = u_tmp; } } } return LIQUID_OK; } liquid-dsp-1.7.0/src/optim/src/gradsearch.c000066400000000000000000000264351474751757600206100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2021 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" #define DEBUG_GRADSEARCH 0 // gradient search algorithm (steepest descent) object struct gradsearch_s { float * v; // vector to optimize (externally allocated) unsigned int num_parameters;// ... float u; // utility at current position // properties float delta; // gradient approximation step size float alpha; // line search step size float * p; // gradient estimate float pnorm; // L2-norm of gradient estimate utility_function utility; // utility function pointer void * userdata; // object to optimize (user data) int direction; // search direction (minimize/maximimze utility) }; // create a gradient search object // _userdata : user data object pointer // _v : array of parameters to optimize // _num_parameters : array length (number of parameters to optimize) // _u : utility function pointer // _direction : search direction (e.g. LIQUID_OPTIM_MAXIMIZE) gradsearch gradsearch_create(void * _userdata, float * _v, unsigned int _num_parameters, utility_function _utility, int _direction) { gradsearch q = (gradsearch) malloc( sizeof(struct gradsearch_s) ); // set user-defined properties q->userdata = _userdata; q->v = _v; q->num_parameters = _num_parameters; q->utility = _utility; q->direction = _direction; // set internal properties // TODO : make these user-configurable properties q->delta = 1e-6f; // gradient approximation step size q->alpha = q->delta; // line search step size // allocate array for gradient estimate q->p = (float*) malloc(q->num_parameters*sizeof(float)); q->pnorm = 0.0f; q->u = 0.0f; return q; } void gradsearch_destroy(gradsearch _q) { // free gradient estimate array free(_q->p); // free main object memory free(_q); } // print status void gradsearch_print(gradsearch _q) { #if 0 //printf("gradient search:\n"); printf("u=%12.4e ", _q->u); // utility // enable more verbose output printf("|p|=%7.1e ", _q->pnorm); // norm(p) printf("del=%7.1e ", _q->delta); // delta printf("step=%7.1e ", _q->alpha); // alpha (step size) unsigned int i; printf("{"); for (i=0; i<_q->num_parameters; i++) printf("%8.4f", _q->v[i]); printf("}\n"); #else printf("num_parameters); printf(", dir=\"%s\"", _q->direction == LIQUID_OPTIM_MAXIMIZE ? "max" : "min"); printf(", pnorm=%g", _q->pnorm); // norm(p) printf(", delta=%g", _q->delta); // delta printf(", u=%g", _q->u); printf(">\n"); #endif // return LIQUID_OK; } float gradsearch_step(gradsearch _q) { unsigned int i; // ensure norm(p) > 0, otherwise increase delta unsigned int n=20; for (i=0; iutility, _q->userdata, _q->v, _q->num_parameters, _q->delta, _q->p); // normalize gradient vector _q->pnorm = gradsearch_norm(_q->p, _q->num_parameters); if (_q->pnorm > 0.0f) { // try to keep delta about 1e-4 * pnorm if (1e-4f*_q->pnorm < _q->delta) _q->delta *= 0.90f; else if ( 1e-5f*_q->pnorm > _q->delta) _q->delta *= 1.10f; break; } else { // step size is too small to approximate gradient _q->delta *= 10.0f; } } if (i == n) { liquid_error(LIQUID_ENOCONV,"gradsearch_step(), function ill-conditioned"); return _q->utility(_q->userdata, _q->v, _q->num_parameters); } // run line search _q->alpha = gradsearch_linesearch(_q->utility, _q->userdata, _q->direction, _q->num_parameters, _q->v, _q->p, _q->delta); // step in the negative direction of the gradient float dir = _q->direction == LIQUID_OPTIM_MINIMIZE ? 1.0f : -1.0f; for (i=0; i<_q->num_parameters; i++) _q->v[i] = _q->v[i] - dir*_q->alpha*_q->p[i]; // evaluate utility at current position _q->u = _q->utility(_q->userdata, _q->v, _q->num_parameters); // return utility return _q->u; } // batch execution of gradient search : run many steps and stop // when criteria are met float gradsearch_execute(gradsearch _q, unsigned int _max_iterations, float _target_utility) { int continue_running = 1; unsigned int num_iterations = 0; float u = 0.0f; while (continue_running) { // increment number of iterations num_iterations++; // step gradient search algorithm u = gradsearch_step(_q); // check exit criteria (any one of the following) // * maximum number of iterations met // * maximize utility and target exceeded // * minimize utility and target exceeded if ( (num_iterations >= _max_iterations ) || (_q->direction == LIQUID_OPTIM_MINIMIZE && u < _target_utility) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && u > _target_utility) ) { continue_running = 0; } } // return final utility return u; } // // internal (generic functions) // // compute the gradient of a function at a particular point // _utility : user-defined function // _userdata : user-defined data object // _x : operating point, [size: _n x 1] // _n : dimensionality of search // _delta : step value for which to compute gradient // _gradient : resulting gradient void gradsearch_gradient(utility_function _utility, void * _userdata, float * _x, unsigned int _n, float _delta, float * _gradient) { // operating point for evaluation float x_prime[_n]; float u_prime; // evaluate function at current operating point float u0 = _utility(_userdata, _x, _n); unsigned int i; for (i=0; i<_n; i++) { // copy operating point memmove(x_prime, _x, _n*sizeof(float)); // increment test vector by delta along dimension 'i' x_prime[i] += _delta; // evaluate new utility u_prime = _utility(_userdata, x_prime, _n); // compute gradient estimate _gradient[i] = (u_prime - u0) / _delta; } } // execute line search; loosely solve: // // min|max phi(alpha) := f(_x - alpha*_p) // // and return best guess at alpha that achieves this // // _utility : user-defined function // _userdata : user-defined data object // _direction : search direction (e.g. LIQUID_OPTIM_MINIMIZE) // _n : dimensionality of search // _x : operating point, [size: _n x 1] // _p : normalized gradient, [size: _n x 1] // _alpha : initial step size float gradsearch_linesearch(utility_function _utility, void * _userdata, int _direction, unsigned int _n, float * _x, float * _p, float _alpha) { #if DEBUG_GRADSEARCH unsigned int i; // print vector operating point printf(" linesearch v: {"); for (i=0; i<_n; i++) printf("%8.4f", _x[i]); printf("}\n"); // print gradient printf(" linesearch g: {"); for (i=0; i<_n; i++) printf("%8.4f", _p[i]); printf("}\n"); #endif // evaluate utility at base point float u0 = _utility(_userdata, _x, _n); // initialize step size estimate float alpha = _alpha; // step direction float dir = _direction == LIQUID_OPTIM_MINIMIZE ? 1.0f : -1.0f; // test vector, TODO : dynamic allocation? float x_prime[_n]; // run line search int continue_running = 1; unsigned int num_iterations = 0; unsigned int max_iterations = 250; float gamma = 2.00; while (continue_running) { // increment iteration counter num_iterations++; // update evaluation point unsigned int i; for (i=0; i<_n; i++) x_prime[i] = _x[i] - dir*alpha*_p[i]; // compute utility for line search step float uls = _utility(_userdata, x_prime, _n); #if DEBUG_GRADSEARCH printf(" linesearch %6u : alpha=%12.6f, u0=%12.8f, uls=%12.8f\n", num_iterations, alpha, u0, uls); #endif // check exit criteria if ( (_direction == LIQUID_OPTIM_MINIMIZE && uls > u0) || (_direction == LIQUID_OPTIM_MAXIMIZE && uls < u0) ) { // compared this utility to previous; went too far. // backtrack step size and stop line search alpha *= 1.0f/gamma; continue_running = 0; } else if ( num_iterations >= max_iterations ) { // maximum number of iterations met: stop line search continue_running = 0; } else { // save new best estimate, increase step size, and continue u0 = uls; alpha *= gamma; } } return alpha; } // normalize vector, returning its l2-norm float gradsearch_norm(float * _v, unsigned int _n) { // compute l2-norm float vnorm = liquid_vectorf_norm(_v, _n); // scale values (avoiding division by zero) float scale = vnorm == 0.0f ? 0.0f : 1.0f / vnorm; unsigned int i; for (i=0; i<_n; i++) _v[i] *= scale; // return normalization return vnorm; } liquid-dsp-1.7.0/src/optim/src/optim.common.c000066400000000000000000000046011474751757600211130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // optim.common.c // #include #include #include "liquid.internal.h" // optimization threshold switch // _u0 : first utility // _u1 : second utility // _minimize : minimize flag // // returns: // (_u0 > _u1) if (_minimize == 1) // (_u0 < _u1) otherwise int optim_threshold_switch(float _u0, float _u1, int _minimize) { return _minimize ? _u0 > _u1 : _u0 < _u1; } // sort values by index // _v : input values [size: _len x 1] // _rank : output rank array (indices) [size: _len x 1] // _len : length of input array // _descending : descending/ascending void optim_sort(float *_v, unsigned int * _rank, unsigned int _len, int _descending) { unsigned int i, j, tmp_index; for (i=0; i<_len; i++) _rank[i] = i; for (i=0; i<_len; i++) { for (j=_len-1; j>i; j--) { //if (_v[_rank[j]]>_v[_rank[j-1]]) { if ( optim_threshold_switch(_v[_rank[j]], _v[_rank[j-1]], _descending) ) { // swap elements tmp_index = _rank[j]; _rank[j] = _rank[j-1]; _rank[j-1] = tmp_index; } } } } liquid-dsp-1.7.0/src/optim/src/optim.h000066400000000000000000000037551474751757600176420ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Optimization // #ifndef __LIQUID_OPTIM_H__ #define __LIQUID_OPTIM_H__ // optim pattern set (struct) struct optim_ps_s { float *x, *y; unsigned int nx, ny, np; unsigned int na; // num allocated }; typedef struct optim_ps_s * optim_ps; optim_ps optim_ps_create(unsigned int _nx, unsigned int _ny); void optim_ps_destroy(optim_ps _ps); void optim_ps_print(optim_ps _ps); void optim_ps_append_pattern(optim_ps _ps, float *_x, float *_y); void optim_ps_append_patterns(optim_ps _ps, float *_x, float *_y, unsigned int _np); void optim_ps_delete_pattern(optim_ps _ps, unsigned int _i); void optim_ps_clear(optim_ps _ps); void optim_ps_access(optim_ps _ps, unsigned int _i, float **_x, float **_y); typedef void(*optim_target_function)(float *_x, float *_y, void *_p); typedef float(*optim_obj_function)(optim_ps _ps, void *_p, optim_target_function _f); #endif // __LIQUID_OPTIM_H__ liquid-dsp-1.7.0/src/optim/src/qnsearch.c000066400000000000000000000233121474751757600203000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // quasi-Newton search object struct qnsearch_s { float* v; // vector to optimize (externally allocated) unsigned int num_parameters; // number of parameters to optimize [n] float gamma; // nominal stepsize float delta; // differential used to compute (estimate) derivative float dgamma; // decremental gamma parameter float gamma_hat; // step size (decreases each epoch) float* v_prime; // temporary vector array float* dv; // parameter step vector float * B; // approximate Hessian matrix inverse [n x n] float * H; // Hessian matrix float* p; // search direction float* gradient; // gradient approximation float* gradient0; // gradient approximation (previous step) // External utility function. utility_function get_utility; float utility; // current utility void * userdata; // userdata pointer passed to utility callback int minimize; // minimize/maximimze utility (search direction) }; // compute gradient(x_k) int qnsearch_compute_gradient(qnsearch _q); // compute the norm of the gradient(x_k) int qnsearch_normalize_gradient(qnsearch _q); // compute Hessian (estimate) int qnsearch_compute_Hessian(qnsearch _q); // compute the updated inverse hessian matrix using the Broyden, Fletcher, // Goldfarb & Shanno method (BFGS) int qnsearch_update_hessian_bfgs(qnsearch _q); // create quasi-newton method search object qnsearch qnsearch_create(void * _userdata, float * _v, unsigned int _num_parameters, utility_function _u, int _minmax) { // validate input if (_u == NULL) return liquid_error_config("qnsearch_create(), utility function cannot be NULL") if (_num_parameters == 0) return liquid_error_config("qnsearch_create(), number of parameters must be greater than zero"); // create object and initialize public values qnsearch q = (qnsearch) malloc( sizeof(struct qnsearch_s) ); q->delta = 1e-6f; //_delta; q->gamma = 1e-3f; //_gamma; q->dgamma = 0.99f; q->gamma_hat = q->gamma; q->userdata = _userdata; q->v = _v; q->num_parameters = _num_parameters; q->get_utility = _u; q->minimize = ( _minmax == LIQUID_OPTIM_MINIMIZE ) ? 1 : 0; // initialize internal memory arrays q->B = (float*) calloc( q->num_parameters*q->num_parameters, sizeof(float)); q->H = (float*) calloc( q->num_parameters*q->num_parameters, sizeof(float)); q->p = (float*) calloc( q->num_parameters, sizeof(float) ); q->gradient = (float*) calloc( q->num_parameters, sizeof(float) ); q->gradient0= (float*) calloc( q->num_parameters, sizeof(float) ); q->v_prime = (float*) calloc( q->num_parameters, sizeof(float) ); q->dv = (float*) calloc( q->num_parameters, sizeof(float) ); q->utility = q->get_utility(q->userdata, q->v, q->num_parameters); qnsearch_reset(q); return q; } int qnsearch_destroy(qnsearch _q) { free(_q->B); free(_q->H); free(_q->p); free(_q->gradient); free(_q->gradient0); free(_q->v_prime); free(_q->dv); free(_q); return LIQUID_OK; } int qnsearch_print(qnsearch _q) { #if 0 printf("[%.3f] ", _q->utility); unsigned int i; for (i=0; i<_q->num_parameters; i++) printf("%.3f ", _q->v[i]); printf("\n"); #else printf("num_parameters); printf(", dir=\"%s\"", _q->minimize ? "min" : "max"); printf(", gamma=%g", _q->gamma); printf(", delta=%g", _q->delta); // delta printf(", u=%g", _q->utility); printf(">\n"); #endif return LIQUID_OK; } int qnsearch_reset(qnsearch _q) { _q->gamma_hat = _q->gamma; // set B to identity matrix unsigned int i,j,n=0; for (i=0; i<_q->num_parameters; i++) { for (j=0; j<_q->num_parameters; j++) { _q->B[n++] = (i==j) ? 1.0f : 0.0f; } } _q->utility = _q->get_utility(_q->userdata, _q->v, _q->num_parameters); return LIQUID_OK; } int qnsearch_step(qnsearch _q) { unsigned int i; unsigned int n = _q->num_parameters; // compute normalized gradient vector qnsearch_compute_gradient(_q); // TODO : perform line search to find optimal gamma // compute search direction #if 0 matrixf_mul(_q->B, n, n, _q->gradient, n, 1, _q->p, n, 1); for (i=0; i<_q->num_parameters; i++) _q->p[i] = -_q->p[i]; #else qnsearch_compute_Hessian(_q); matrixf_inv(_q->H, n, n); matrixf_mul(_q->H, n, n, _q->gradient, n, 1, _q->p, n, 1); #endif // compute step vector for (i=0; i<_q->num_parameters; i++) _q->dv[i] = -_q->gamma_hat * _q->p[i]; // apply change for (i=0; i<_q->num_parameters; i++) { _q->v[i] += _q->dv[i]; } // TODO update inverse Hessian approximation // store previous gradient memmove(_q->gradient0, _q->gradient, (_q->num_parameters)*sizeof(float)); // update utility float u_prime = _q->get_utility(_q->userdata, _q->v, _q->num_parameters); if (u_prime > _q->utility) { _q->gamma_hat *= 0.99f; } else { _q->gamma_hat *= 1.001f; } _q->utility = u_prime; return LIQUID_OK; } float qnsearch_execute(qnsearch _q, unsigned int _max_iterations, float _target_utility) { unsigned int i=0; do { i++; qnsearch_step(_q); _q->utility = _q->get_utility(_q->userdata, _q->v, _q->num_parameters); } while ( optim_threshold_switch(_q->utility, _target_utility, _q->minimize) && i < _max_iterations); return _q->utility; } // // internal // // compute gradient int qnsearch_compute_gradient(qnsearch _q) { unsigned int i; float f_prime; // reset v_prime memmove(_q->v_prime, _q->v, (_q->num_parameters)*sizeof(float)); for (i=0; i<_q->num_parameters; i++) { _q->v_prime[i] += _q->delta; f_prime = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); _q->v_prime[i] -= _q->delta; _q->gradient[i] = (f_prime - _q->utility) / _q->delta; } return LIQUID_OK; } // compute Hessian int qnsearch_compute_Hessian(qnsearch _q) { unsigned int i, j; unsigned int n = _q->num_parameters; float f00, f01, f10, f11; float f0, f1, f2; float m0, m1; float delta = 1e-2f; // reset v_prime memmove(_q->v_prime, _q->v, (_q->num_parameters)*sizeof(float)); for (i=0; i<_q->num_parameters; i++) { //for (j=0; j<_q->num_parameters; j++) { for (j=0; j<=i; j++) { if (i==j) { _q->v_prime[i] = _q->v[i] - delta; f0 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); _q->v_prime[i] = _q->v[i]; f1 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); _q->v_prime[i] = _q->v[i] + delta; f2 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); m0 = (f1 - f0) / delta; m1 = (f2 - f1) / delta; matrix_access(_q->H, n, n, i, j) = (m1 - m0) / delta; } else { // 0 0 _q->v_prime[i] = _q->v[i] - delta; _q->v_prime[j] = _q->v[j] - delta; f00 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); // 0 1 _q->v_prime[i] = _q->v[i] - delta; _q->v_prime[j] = _q->v[j] + delta; f01 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); // 1 0 _q->v_prime[i] = _q->v[i] + delta; _q->v_prime[j] = _q->v[j] - delta; f10 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); // 1 1 _q->v_prime[i] = _q->v[i] + delta; _q->v_prime[j] = _q->v[j] + delta; f11 = _q->get_utility(_q->userdata, _q->v_prime, _q->num_parameters); // compute second partial derivative m0 = (f01 - f00) / (2.0f*delta); m1 = (f11 - f10) / (2.0f*delta); matrix_access(_q->H, n, n, i, j) = (m1 - m0) / (2.0f*delta); matrix_access(_q->H, n, n, j, i) = (m1 - m0) / (2.0f*delta); } } } return LIQUID_OK; } liquid-dsp-1.7.0/src/optim/src/qs1dsearch.c000066400000000000000000000204411474751757600205320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "liquid.internal.h" // quasi-Newton search object struct qs1dsearch_s { float vn, va, v0, vb, vp; // values float un, ua, u0, ub, up; // utilities int init; // values initialized? // External utility function. liquid_utility_1d utility; // void * context; // user-defined data pointer passed to utility callback int direction; // search direction (minimize/maximimze utility) unsigned int num_steps; // number of steps evaluated }; // create quasi-newton method search object qs1dsearch qs1dsearch_create(liquid_utility_1d _utility, void * _context, int _direction) { // validate input if (_utility == NULL) return liquid_error_config("qs1dsearch_create(), utility callback cannot be NULL"); // allocate main object memory and initialize qs1dsearch q = (qs1dsearch) malloc( sizeof(struct qs1dsearch_s) ); q->utility = _utility; q->context = _context; q->direction = _direction; // reset object and return qs1dsearch_reset(q); return q; } qs1dsearch qs1dsearch_copy(qs1dsearch _q) { liquid_error(LIQUID_ENOIMP,"qs1dsearch_copy(), method not yet implemented"); return NULL; } int qs1dsearch_destroy(qs1dsearch _q) { if (_q == NULL) return liquid_error(LIQUID_EIOBJ,"qs1dsearch_destroy(), invalid null pointer passed"); free(_q); return LIQUID_OK; } int qs1dsearch_print(qs1dsearch _q) { printf("\n", _q->vn, _q->v0, _q->vp, _q->un, _q->u0, _q->up); return LIQUID_OK; } int qs1dsearch_reset(qs1dsearch _q) { _q->init = 0; _q->num_steps = 0; _q->vn = 0.0f; _q->un = 0.0f; _q->va = 0.0f; _q->ua = 0.0f; _q->v0 = 0.0f; _q->u0 = 0.0f; _q->vb = 0.0f; _q->ub = 0.0f; _q->vp = 0.0f; _q->up = 0.0f; return LIQUID_OK; } // perform initial search int qs1dsearch_init(qs1dsearch _q, float _v) { // specify initial step size float step = 1e-16f; // try positive direction if ( qs1dsearch_init_direction(_q, _v, step)==LIQUID_OK ) return LIQUID_OK; // try negative direction if ( qs1dsearch_init_direction(_q, _v, -step)==LIQUID_OK ) return LIQUID_OK; // check edge case where _v is exactly the optimum _q->vn = _v - step; _q->un =_q->utility(_q->vn, _q->context); _q->v0 = _v; _q->u0 =_q->utility(_q->v0, _q->context); _q->vp = _v + step; _q->up =_q->utility(_q->vp, _q->context); if ( (_q->direction == LIQUID_OPTIM_MINIMIZE && (_q->u0 < _q->un && _q->u0 < _q->up)) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && (_q->u0 > _q->un && _q->u0 > _q->up)) ) { _q->init = 1; return LIQUID_OK; } // TODO: be more persistent? return LIQUID_EIVAL;// FIXME: return proper error here, e.g. LIQUID_ENOCONV } // perform initial search along a particular direction int qs1dsearch_init_direction(qs1dsearch _q, float _v_init, float _step) { //printf("# qs1dsearch_init_direction(_q, v_init:%12.8f, step:%12.4e);\n", _v_init, _step); // start over and search in proper direction float vn = _v_init; float un = 0.0f; float v0 = _v_init; float u0 = _q->utility(v0, _q->context); float vp = _v_init + _step*0.5f; float up = _q->utility(vp, _q->context); unsigned int i; for (i=0; i<180; i++) { // move values down vn = v0; v0 = vp; un = u0; u0 = up; // vp = v0 + _step; up = _q->utility(vp, _q->context); //printf("%3u %12.4e:{%12.8f,%12.8f,%12.8f},{%12.8f,%12.8f,%12.8f}\n",i, _step, vn, v0, vp, un, u0, up); //printf("%3u %12.4e:{%12.4e,%12.4e,%12.4e},{%12.4e,%12.4e,%12.4e}\n",i, _step, vn, v0, vp, un, u0, up); if ( (_q->direction == LIQUID_OPTIM_MINIMIZE && (u0 < un && u0 < up)) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && (u0 > un && u0 > up)) ) { // skipped over optimum; set internal bounds and return int swap = (_step < 0); _q->vn = swap ? vp : vn; _q->v0 = v0; _q->vp = swap ? vn : vp; _q->un = swap ? up : un; _q->u0 = u0; _q->up = swap ? un : up; _q->init = 1; return LIQUID_OK; } else if ( (_q->direction == LIQUID_OPTIM_MINIMIZE && (u0 >= un && up > u0)) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && (u0 <= un && up < u0)) ) { // clearly moving in wrong direction: exit early break; } _step *= 1.5; // increase step size } // did not converge; return non-zero value return LIQUID_EIVAL;// FIXME: return proper error here, e.g. LIQUID_ENOCONV } int qs1dsearch_init_bounds(qs1dsearch _q, float _vn, float _vp) { // set bounds appropriately _q->vn = _vn < _vp ? _vn : _vp; _q->vp = _vn < _vp ? _vp : _vn; _q->v0 = 0.5f*(_vn + _vp); // evaluate utility _q->un = _q->utility(_q->vn, _q->context); _q->u0 = _q->utility(_q->v0, _q->context); _q->up = _q->utility(_q->vp, _q->context); _q->init = 1; // TODO: ensure v0 is optimum here return LIQUID_OK; } int qs1dsearch_step(qs1dsearch _q) { if (!_q->init) return liquid_error(LIQUID_ENOINIT,"qs1dsearch_step(), object has not be properly initialized"); // TODO: allow option for geometric mean? // compute new candidate points _q->va = 0.5f*(_q->vn + _q->v0); _q->vb = 0.5f*(_q->v0 + _q->vp); // evaluate utility _q->ua = _q->utility(_q->va, _q->context); _q->ub = _q->utility(_q->vb, _q->context); #if 0 printf(" %3u [%7.3f,%7.3f,%7.3f,%7.3f,%7.3f] : {%7.3f,%7.3f,%7.3f,%7.3f,%7.3f}\n", _q->num_steps, _q->vn, _q->va, _q->v0, _q->vb, _q->vp, _q->un, _q->ua, _q->u0, _q->ub, _q->up); #endif // [ (vn) va (v0) vb (vp) ] // optimum should be va, v0, or vb if ((_q->direction == LIQUID_OPTIM_MINIMIZE && _q->ua < _q->u0 && _q->ua < _q->ub) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && _q->ua > _q->u0 && _q->ua > _q->ub)) { // va is optimum _q->vp = _q->v0; _q->up = _q->u0; _q->v0 = _q->va; _q->u0 = _q->ua; } else if ((_q->direction == LIQUID_OPTIM_MINIMIZE && _q->u0 < _q->ua && _q->u0 < _q->ub) || (_q->direction == LIQUID_OPTIM_MAXIMIZE && _q->u0 > _q->ua && _q->u0 > _q->ub)) { // v0 is optimum _q->vn = _q->va; _q->un = _q->ua; _q->vp = _q->vb; _q->up = _q->ub; } else { // vb is optimum _q->vn = _q->v0; _q->un = _q->u0; _q->v0 = _q->vb; _q->u0 = _q->ub; } _q->num_steps++; return LIQUID_OK; } int qs1dsearch_execute(qs1dsearch _q) { return LIQUID_OK; } unsigned int qs1dsearch_get_num_steps(qs1dsearch _q) { return _q->num_steps; } float qs1dsearch_get_opt_v(qs1dsearch _q) { return _q->v0; } float qs1dsearch_get_opt_u(qs1dsearch _q) { return _q->u0; } liquid-dsp-1.7.0/src/optim/src/utilities.c000066400000000000000000000103601474751757600205060ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // n-dimensional utility functions #include #include #include #include "liquid.internal.h" // n-dimensional Rosenbrock utility function, minimum at _v = {1,1,1...} float liquid_rosenbrock(void * _userdata, float * _v, unsigned int _n) { if (_n == 0) { liquid_error(LIQUID_EICONFIG,"liquid_rosenbrock(), input vector length cannot be zero"); return 0.0f; } else if (_n == 1) { return (1.0f-_v[0])*(1.0f-_v[0]); } float u=0.0f; unsigned int i; for (i=0; i<_n-1; i++) u += powf(1-_v[i],2) + 100*powf( _v[i+1] - powf(_v[i],2), 2); return u; } // n-dimensional inverse Gauss utility function (minimum at _v = {1,1,1...} // _userdata : user-defined data structure (convenience) // _v : input vector [size: _n x 1] // _n : input vector size float liquid_invgauss(void * _userdata, float * _v, unsigned int _n) { if (_n == 0) { liquid_error(LIQUID_EICONFIG,"liquid_invgauss(), input vector length cannot be zero"); return 0.0f; } float t = 0.0f; float sigma = 1.0f; unsigned int i; for (i=0; i<_n; i++) { t += (_v[i]-1.0f)*(_v[i]-1.0f) / (sigma*sigma); // increase variance along this dimension sigma *= 1.5f; } return 1 - expf(-t); } // n-dimensional multimodal utility function (minimum at _v = {0,0,0...} // _userdata : user-defined data structure (convenience) // _v : input vector [size: _n x 1] // _n : input vector size float liquid_multimodal(void * _userdata, float * _v, unsigned int _n) { if (_n == 0) { liquid_error(LIQUID_EICONFIG,"liquid_multimodal(), input vector length cannot be zero"); return 0.0f; } float t0 = 1.0f; float t1 = 0.0f; float sigma = 4.0f; unsigned int i; for (i=0; i<_n; i++) { t0 *= 0.5f + 0.5f*cosf(2*M_PI*_v[i]); t1 += _v[i]*_v[i] / (sigma*sigma); } //t0 = powf(t0, 1.0f / (float)_n); return 1.0f - t0*expf(-t1); } // n-dimensional spiral utility function (minimum at _v = {0,0,0...} // _userdata : user-defined data structure (convenience) // _v : input vector [size: _n x 1] // _n : input vector size float liquid_spiral(void * _userdata, float * _v, unsigned int _n) { if (_n == 0) { liquid_error(LIQUID_EICONFIG,"liquid_rosenbrock(), input vector length cannot be zero"); return 0.0f; } else if (_n == 1) { return _v[0]*_v[0]; } // n is at least 2 float r_hat = sqrtf(_v[0]*_v[0] + _v[1]*_v[1]); float theta_hat = atan2f(_v[1], _v[0]); float delta = theta_hat - r_hat * 10; while (delta > M_PI) delta -= 2*M_PI; while (delta < -M_PI) delta += 2*M_PI; delta = delta / M_PI; float u = 1 - delta*delta*expf(-r_hat*r_hat/10); // additional error... unsigned int i; for (i=2; i<_n; i++) u += _v[i]*_v[i]; return u; } liquid-dsp-1.7.0/src/optim/tests/000077500000000000000000000000001474751757600167025ustar00rootroot00000000000000liquid-dsp-1.7.0/src/optim/tests/gasearch_autotest.c000066400000000000000000000220561474751757600225600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" #include #include #include #include #include #include "liquid.internal.h" // peak callback function; value nearest {p, p, p, ...} where p = 1/sqrt(2) float gasearch_autotest_peak_callback(void * _userdata, chromosome _c) { unsigned int i, n = chromosome_get_num_traits(_c); float u = 1.0f; float sig = 0.2f; float p = M_SQRT1_2; for (i=0; i #include #include #include #include #include "liquid.internal.h" // // AUTOTEST: Find minimum of Rosenbrock function, should be [1 1 1 ...] // void autotest_gradsearch_rosenbrock() { float tol = 1e-2f; // error tolerance unsigned int num_parameters = 6; // dimensionality of search (minimum 2) unsigned int num_iterations = 4000; // number of iterations to run // initialize vector for optimization float v_opt[num_parameters]; unsigned int i; for (i=0; i #include #include #include #include #include "liquid.internal.h" void autotest_qnsearch_rosenbrock() { float tol = 1e-2f; // error tolerance unsigned int num_parameters = 6; // dimensionality of search (minimum 2) unsigned int num_iterations = 4000; // number of iterations to run // initialize vector for optimization float v_opt[num_parameters]; unsigned int i; for (i=0; i #include #include #include #include float qs1dsearch_umin(float _v, void * _context) { float v_opt = *(float*)(_context); float v = _v - v_opt; return tanhf(v)*tanhf(v); } float qs1dsearch_umax(float _v, void * _context) { return -qs1dsearch_umin(_v, _context); } // test initialization on single value void test_qs1dsearch(liquid_utility_1d _utility, float _v_opt, float _v_lo, float _v_hi, int _bounds, int _direction) { // create qs1dsearch object and initialize qs1dsearch q = qs1dsearch_create(_utility, &_v_opt, _direction); if (_bounds) qs1dsearch_init_bounds(q, _v_lo, _v_hi); else qs1dsearch_init (q, _v_lo); // run search unsigned int i; for (i=0; i<32; i++) { qs1dsearch_step(q); if (liquid_autotest_verbose) qs1dsearch_print(q); } // check result CONTEND_DELTA( qs1dsearch_get_opt_v(q), _v_opt, 1e-3f ); CONTEND_DELTA( qs1dsearch_get_opt_u(q), _utility(_v_opt, &_v_opt), 1e-3f ); // print results if (liquid_autotest_verbose) { printf("%3u : u(%12.8f) = %12.4e, v_opt=%12.4e (error=%12.4e)\n", i, qs1dsearch_get_opt_v(q), qs1dsearch_get_opt_u(q), _v_opt, _v_opt - qs1dsearch_get_opt_v(q)); } // clean it upt qs1dsearch_destroy(q); } // unbounded: (utility, opt, lo, hi, bound, dir) void autotest_qs1dsearch_min_01() { test_qs1dsearch(qs1dsearch_umin, 0, -40, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_02() { test_qs1dsearch(qs1dsearch_umin, 0, -20, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_03() { test_qs1dsearch(qs1dsearch_umin, 0, -4, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_05() { test_qs1dsearch(qs1dsearch_umin, 0, 0, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_06() { test_qs1dsearch(qs1dsearch_umin, 0, 4, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_07() { test_qs1dsearch(qs1dsearch_umin, 0, 20, 0, 0, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_08() { test_qs1dsearch(qs1dsearch_umin, 0, 40, 0, 0, LIQUID_OPTIM_MINIMIZE); } // bounded: (utility, opt, lo, hi, bound, dir) void autotest_qs1dsearch_min_10() { test_qs1dsearch(qs1dsearch_umin, 0, -30, 15, 1, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_11() { test_qs1dsearch(qs1dsearch_umin, 0, -20, 15, 1, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_12() { test_qs1dsearch(qs1dsearch_umin, 0, -10, 15, 1, LIQUID_OPTIM_MINIMIZE); } void autotest_qs1dsearch_min_13() { test_qs1dsearch(qs1dsearch_umin, 0, -.1, 15, 1, LIQUID_OPTIM_MINIMIZE); } // repeat to maximize // unbounded: (utility, opt, lo, hi, bound, dir) void autotest_qs1dsearch_max_01() { test_qs1dsearch(qs1dsearch_umax, 0, -40, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_02() { test_qs1dsearch(qs1dsearch_umax, 0, -20, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_03() { test_qs1dsearch(qs1dsearch_umax, 0, -4, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_05() { test_qs1dsearch(qs1dsearch_umax, 0, 0, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_06() { test_qs1dsearch(qs1dsearch_umax, 0, 4, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_07() { test_qs1dsearch(qs1dsearch_umax, 0, 20, 0, 0, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_08() { test_qs1dsearch(qs1dsearch_umax, 0, 40, 0, 0, LIQUID_OPTIM_MAXIMIZE); } // bounded: max (utility, max opt, lo, hi, bound, dir) void autotest_qs1dsearch_max_10() { test_qs1dsearch(qs1dsearch_umax, 0, -30, 15, 1, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_11() { test_qs1dsearch(qs1dsearch_umax, 0, -20, 15, 1, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_12() { test_qs1dsearch(qs1dsearch_umax, 0, -10, 15, 1, LIQUID_OPTIM_MAXIMIZE); } void autotest_qs1dsearch_max_13() { test_qs1dsearch(qs1dsearch_umax, 0, -.1, 15, 1, LIQUID_OPTIM_MAXIMIZE); } // test configuration void autotest_qs1dsearch_config() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping qs1dsearch config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // check invalid function calls CONTEND_ISNULL(qs1dsearch_create(NULL, NULL, LIQUID_OPTIM_MAXIMIZE)) // utility is NULL CONTEND_ISNULL(qs1dsearch_copy (NULL)) // create proper object and test configurations float v_opt = 0; qs1dsearch q = qs1dsearch_create(qs1dsearch_umax, &v_opt, LIQUID_OPTIM_MAXIMIZE); CONTEND_EQUALITY(LIQUID_OK, qs1dsearch_print(q)) // test configurations CONTEND_INEQUALITY(LIQUID_OK, qs1dsearch_step(q)) // object not yet initialized qs1dsearch_init(q, 20); CONTEND_EQUALITY(LIQUID_OK, qs1dsearch_execute(q)) // run a few steps CONTEND_EQUALITY( 0, qs1dsearch_get_num_steps(q)) qs1dsearch_step(q); qs1dsearch_step(q); qs1dsearch_step(q); CONTEND_EQUALITY( 3, qs1dsearch_get_num_steps(q)) // destroy objects qs1dsearch_destroy(q); } liquid-dsp-1.7.0/src/optim/tests/utility_autotest.c000066400000000000000000000040231474751757600225000ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" #include #include #include #include #include #include "liquid.internal.h" void autotest_optim_rosenbrock() { #if LIQUID_STRICT_EXIT AUTOTEST_WARN("skipping rosenbrock config test with strict exit enabled\n"); return; #endif #if !LIQUID_SUPPRESS_ERROR_OUTPUT fprintf(stderr,"warning: ignore potential errors here; checking for invalid configurations\n"); #endif // optimum float v_ones[8] = {1,1,1,1,1,1,1,1}; CONTEND_DELTA( liquid_rosenbrock(NULL, v_ones, 8), 0.0f, 1e-6f ) CONTEND_DELTA( liquid_rosenbrock(NULL, v_ones, 1), 0.0f, 1e-6f ) // very far from optimum float v_misc[8] = {0.3, 1.0, 4.5,-2.2, 6.7,-0.2, 1.1,-0.9,}; CONTEND_GREATER_THAN( liquid_rosenbrock(NULL, v_misc, 8), 1000.0f ) // invalid configuration CONTEND_EQUALITY( liquid_rosenbrock(NULL, v_misc, 0), 0.0f ) } liquid-dsp-1.7.0/src/quantization/000077500000000000000000000000001474751757600171365ustar00rootroot00000000000000liquid-dsp-1.7.0/src/quantization/bench/000077500000000000000000000000001474751757600202155ustar00rootroot00000000000000liquid-dsp-1.7.0/src/quantization/bench/compander_benchmark.c000066400000000000000000000042771474751757600243550ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // void benchmark_compress_mulaw( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { unsigned long int i; float x = -0.1f; float mu = 255.0f; float y = 0.0f; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { y += compress_mulaw(x,mu); y -= compress_mulaw(x,mu); x += compress_mulaw(y,mu); x -= compress_mulaw(y,mu); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } // void benchmark_expand_mulaw( struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { unsigned long int i; float x = 0.0f; float mu = 255.0f; float y = 0.75f; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += expand_mulaw(y,mu); x -= expand_mulaw(y,mu); y += expand_mulaw(x,mu); y -= expand_mulaw(x,mu); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; } liquid-dsp-1.7.0/src/quantization/bench/quantizer_benchmark.c000066400000000000000000000047201474751757600244200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // void benchmark_quantize_adc(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { unsigned long int i; unsigned int q = 0; unsigned int num_bits=8; float x=-0.1f; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { q ^= quantize_adc(x,num_bits); q ^= quantize_adc(x,num_bits); q ^= quantize_adc(x,num_bits); q ^= quantize_adc(x,num_bits); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += q & 1; // trivial use of variable } // void benchmark_quantize_dac(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { unsigned long int i; unsigned int q=0x0f; unsigned int num_bits=8; float x = 0; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += quantize_dac(q,num_bits); x += quantize_dac(q,num_bits); x += quantize_dac(q,num_bits); x += quantize_dac(q,num_bits); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += x > 0; // trivial use of variable } liquid-dsp-1.7.0/src/quantization/src/000077500000000000000000000000001474751757600177255ustar00rootroot00000000000000liquid-dsp-1.7.0/src/quantization/src/compand.c000066400000000000000000000050021474751757600215070ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // // #include #include #include #include "liquid.internal.h" #define LIQUID_VALIDATE_INPUT float compress_mulaw(float _x, float _mu) { #ifdef LIQUID_VALIDATE_INPUT if ( _mu <= 0.0f ) { liquid_error(LIQUID_EIRANGE,"compress_mulaw(), mu out of range"); return 0.0f; } #endif float y = logf(1 + _mu*fabsf(_x)) / logf(1 + _mu); return copysignf(y, _x); } float expand_mulaw(float _y, float _mu) { #ifdef LIQUID_VALIDATE_INPUT if ( _mu <= 0.0f ) { liquid_error(LIQUID_EIRANGE,"expand_mulaw(), mu out of range"); return 0.0f; } #endif float x = (1/_mu)*( powf(1+_mu,fabsf(_y)) - 1); return copysign(x, _y); } int compress_cf_mulaw(float complex _x, float _mu, float complex * _y) { #ifdef LIQUID_VALIDATE_INPUT if ( _mu <= 0.0f ) return liquid_error(LIQUID_EIRANGE,"compress_mulaw(), mu out of range"); #endif *_y = cexpf(_Complex_I*cargf(_x)) * logf(1 + _mu*cabsf(_x)) / logf(1 + _mu); return LIQUID_OK; } int expand_cf_mulaw(float complex _y, float _mu, float complex * _x) { #ifdef LIQUID_VALIDATE_INPUT if ( _mu <= 0.0f ) return liquid_error(LIQUID_EIRANGE,"expand_mulaw(), mu out of range"); #endif *_x = cexpf(_Complex_I*cargf(_y)) * (1/_mu)*( powf(1+_mu,cabsf(_y)) - 1); return LIQUID_OK; } /* float compress_alaw(float _x, float _a) { } float expand_alaw(float _x, float _a) { } */ liquid-dsp-1.7.0/src/quantization/src/quantizer.inline.c000066400000000000000000000045621474751757600233770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // // #include #include #include #include "liquid.internal.h" #define LIQUID_VALIDATE_INPUT #define QUANTIZER_MAX_BITS 32 // inline quantizer: 'analog' signal in [-1, 1] unsigned int quantize_adc(float _x, unsigned int _num_bits) { #ifdef LIQUID_VALIDATE_INPUT if (_num_bits > QUANTIZER_MAX_BITS) { liquid_error(LIQUID_EIRANGE,"quantize_adc(), maximum bits exceeded"); return 0; } #endif if (_num_bits == 0) return 0; unsigned int n = _num_bits-1; // unsigned int N = 1<= N) r = N-1; // if negative set MSB to 1 if (neg) r |= N; return r; } float quantize_dac(unsigned int _s, unsigned int _num_bits) { #ifdef LIQUID_VALIDATE_INPUT if (_num_bits > QUANTIZER_MAX_BITS) { liquid_error(LIQUID_EIRANGE,"quantize_dac(), maximum bits exceeded"); return 0.0f; } #endif if (_num_bits == 0) return 0.0f; unsigned int n = _num_bits-1; // unsigned int N = 1< #include struct QUANTIZER(_s) { int ctype; // compander type unsigned int n; // number of bits // table? }; // create quantizer object // _ctype : compander type (e.g. LIQUID_COMPANDER_LINEAR) // _range : maximum absolute input // _num_bits : number of bits per sample QUANTIZER() QUANTIZER(_create)(liquid_compander_type _ctype, float _range, unsigned int _num_bits) { // validate input if (_num_bits == 0) return liquid_error_config("quantizer_create(), must have at least one bit/sample"); // create quantizer object QUANTIZER() q = (QUANTIZER()) malloc(sizeof(struct QUANTIZER(_s))); // initialize values q->ctype = _ctype; q->n = _num_bits; // return object return q; } int QUANTIZER(_destroy)(QUANTIZER() _q) { // free main object memory free(_q); return LIQUID_OK; } int QUANTIZER(_print)(QUANTIZER() _q) { printf("quantizer:\n"); printf(" compander : "); switch(_q->ctype) { case LIQUID_COMPANDER_NONE: printf("none\n"); break; case LIQUID_COMPANDER_LINEAR: printf("linear\n"); break; case LIQUID_COMPANDER_MULAW: printf("mu-law\n"); break; case LIQUID_COMPANDER_ALAW: printf("A-law\n"); break; default: printf("unknown\n"); } printf(" num bits : %u\n", _q->n); return LIQUID_OK; } int QUANTIZER(_execute_adc)(QUANTIZER() _q, T _x, unsigned int * _sample) { #if T_COMPLEX #else #endif *_sample = 0; return LIQUID_OK; } int QUANTIZER(_execute_dac)(QUANTIZER() _q, unsigned int _sample, T * _x) { #if T_COMPLEX #else #endif *_x = 0.0; return LIQUID_OK; } liquid-dsp-1.7.0/src/quantization/src/quantizercf.c000066400000000000000000000025721474751757600224320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Quantizer API: complex floating point // #include "liquid.internal.h" // #define QUANTIZER(name) LIQUID_CONCAT(quantizercf,name) #define T float complex // general #define T_COMPLEX 1 // prototypes #include "quantizer.proto.c" liquid-dsp-1.7.0/src/quantization/src/quantizerf.c000066400000000000000000000025511474751757600222640ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Quantizer API: floating-point // #include "liquid.internal.h" // #define QUANTIZER(name) LIQUID_CONCAT(quantizerf,name) #define T float // general #define T_COMPLEX 0 // prototypes #include "quantizer.proto.c" liquid-dsp-1.7.0/src/quantization/tests/000077500000000000000000000000001474751757600203005ustar00rootroot00000000000000liquid-dsp-1.7.0/src/quantization/tests/compand_autotest.c000066400000000000000000000046341474751757600240240ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" void autotest_compand_float() { float x = -1.0f; float mu=255.0f; unsigned int n=30; float dx = 2/(float)(n); float y; float x_hat; float tol = 1e-6f; unsigned int i; for (i=0; i %8.4f -> %8.4f\n", x, y, x_hat); CONTEND_DELTA(x,x_hat,tol); x += dx; x = (x > 1.0f) ? 1.0f : x; } } void autotest_compand_cfloat() { float complex x = -0.707f - 0.707f*_Complex_I; float mu=255.0f; unsigned int n=30; float complex dx = 2*(0.707f +0.707f* _Complex_I)/(float)(n); float complex y; float complex z; float tol = 1e-6f; unsigned int i; for (i=0; i ", crealf(x), cimagf(x)); printf("%8.4f +j%8.4f > ", crealf(y), cimagf(y)); printf("%8.4f +j%8.4f\n", crealf(z), cimagf(z)); } CONTEND_DELTA(crealf(x),crealf(z),tol); CONTEND_DELTA(cimagf(x),cimagf(z),tol); x += dx; //x = (x > 1.0f) ? 1.0f : x; } } liquid-dsp-1.7.0/src/quantization/tests/quantize_autotest.c000066400000000000000000000035761474751757600242470ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" void autotest_quantize_float_n8() { float x = -1.0f; unsigned int num_steps=30; unsigned int num_bits=8; float dx = 2/(float)(num_steps); unsigned int q; float x_hat; float tol = 1.0f / (float)(1<>num_bits, 0); x_hat = quantize_dac(q,num_bits); if (liquid_autotest_verbose) printf("%8.4f > 0x%2.2x > %8.4f\n", x, q, x_hat); // ensure original value is recovered within tolerance CONTEND_DELTA(x,x_hat,tol); x += dx; x = (x > 1.0f) ? 1.0f : x; } } liquid-dsp-1.7.0/src/random/000077500000000000000000000000001474751757600156705ustar00rootroot00000000000000liquid-dsp-1.7.0/src/random/bench/000077500000000000000000000000001474751757600167475ustar00rootroot00000000000000liquid-dsp-1.7.0/src/random/bench/random_benchmark.c000066400000000000000000000110021474751757600223770ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // // BENCHMARK: uniform // void benchmark_random_uniform(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // normalize number of iterations *_num_iterations *= 10; float x = 0.0f; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += randf(); x += randf(); x += randf(); x += randf(); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += x > 0; // trivial use of variable } // // BENCHMARK: normal // void benchmark_random_normal(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // normalize number of iterations *_num_iterations *= 1; float x = 0.0f; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += randnf(); x += randnf(); x += randnf(); x += randnf(); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += x > 0; // trivial use of variable } // // BENCHMARK: complex normal // void benchmark_random_complex_normal(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // normalize number of iterations *_num_iterations /= 2; float complex x = 0.0f; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { crandnf(&x); crandnf(&x); crandnf(&x); crandnf(&x); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += crealf(x) > 0; // trivial use of variable } // // BENCHMARK: Weibull // void benchmark_random_weibull(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // normalize number of iterations *_num_iterations *= 2; float x=0.0f; float alpha=1.0f; float beta=2.0f; float gamma=6.0f; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += randweibf(alpha,beta,gamma); x += randweibf(alpha,beta,gamma); x += randweibf(alpha,beta,gamma); x += randweibf(alpha,beta,gamma); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += x > 0; // trivial use of variable } // // BENCHMARK: Rice-K // void benchmark_random_ricek(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations) { // normalize number of iterations *_num_iterations /= 3; float x = 0.0f; float K=2.0f; float omega=1.0f; unsigned long int i; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { x += randricekf(K,omega); x += randricekf(K,omega); x += randricekf(K,omega); x += randricekf(K,omega); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; *_num_iterations += x > 0; // trivial use of variable } liquid-dsp-1.7.0/src/random/src/000077500000000000000000000000001474751757600164575ustar00rootroot00000000000000liquid-dsp-1.7.0/src/random/src/rand.c000066400000000000000000000053141474751757600175520ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Uniform random number generator definitions // #include #include #include #include "liquid.internal.h" // uniform random number generator float randf() { return randf_inline(); } // uniform random number probability distribution function float randf_pdf(float _x) { return (_x < 0.0f || _x > 1.0f) ? 0.0f : 1.0f; } // uniform random number cumulative distribution function float randf_cdf(float _x) { if (_x < 0.0f) { return 0.0f; } else if (_x > 1.0f) { return 1.0f; } return _x; } // uniform random number generator with arbitrary bounds float randuf(float _a, float _b) { // check bounds if (_a >= _b) { liquid_error(LIQUID_EIRANGE,"randuf(%g,%g) has invalid range", _a, _b); return 0; } return _a + (_b - _a)*randf_inline(); } // uniform random number probability distribution function float randuf_pdf(float _x, float _a, float _b) { // check bounds if (_a >= _b) { liquid_error(LIQUID_EIRANGE,"randuf_pdf(%g,%g,%g) has invalid range", _x, _a, _b); return 0; } return (_x < _a || _x > _b) ? 0.0f : 1.0f / (_b - _a); } // uniform random number cumulative distribution function float randuf_cdf(float _x, float _a, float _b) { // check bounds if (_a >= _b) { liquid_error(LIQUID_EIRANGE,"randuf_cdf(%g,%g,%g) has invalid range", _x, _a, _b); return 0; } if (_x < _a) { return 0.0f; } else if (_x > _b) { return 1.0f; } return (_x - _a) / (_b - _a); } liquid-dsp-1.7.0/src/random/src/randexp.c000066400000000000000000000045431474751757600202720ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Exponential distribution // #include #include #include #include "liquid.internal.h" // Exponential float randexpf(float _lambda) { // validate input if (_lambda <= 0) { liquid_error(LIQUID_EIRANGE,"randexpf(%g) has invalid range", _lambda); return 0.0f; } // compute a non-zero uniform random variable in (0,1] float u; do { u = randf(); } while (u==0.0f); // perform variable transformation return -logf( u ) / _lambda; } // Exponential random number probability distribution function float randexpf_pdf(float _x, float _lambda) { // validate input if (_lambda <= 0) { liquid_error(LIQUID_EIRANGE,"randexpf_pdf(%g,%g) has invalid range", _x, _lambda); return 0.0f; } if (_x < 0.0f) return 0.0f; return _lambda * expf(-_lambda*_x); } // Exponential random number cumulative distribution function float randexpf_cdf(float _x, float _lambda) { // validate input if (_lambda <= 0) { liquid_error(LIQUID_EIRANGE,"randexpf_cdf(%g,%g) has invalid range", _x, _lambda); return 0.0f; } if (_x < 0.0f) return 0.0f; return 1.0f - expf(-_lambda*_x); } liquid-dsp-1.7.0/src/random/src/randgamma.c000066400000000000000000000112571474751757600205600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Gamma distribution // #include #include #include #include "liquid.internal.h" float randgammaf(float _alpha, float _beta) { // validate input if (_alpha <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf(), beta must be greater than zero"); return 0.0f; } unsigned int n = (unsigned int) floorf(_alpha); // residual float delta = _alpha - (float)n; // generate x' ~ Gamma(n,1) float x_n = 0.0f; unsigned int i; for (i=0; i 0 // b = beta, b > 0 // Gamma(z) = regular gamma function // x >= 0 float randgammaf_pdf(float _x, float _alpha, float _beta) { // validate input if (_alpha <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf_pdf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf_pdf(), beta must be greater than zero"); return 0.0f; } if (_x <= 0.0f) return 0.0f; float t0 = powf(_x, _alpha-1.0f); float t1 = expf(-_x / _beta); float t2 = liquid_gammaf(_alpha); float t3 = powf(_beta, _alpha); return (t0*t1)/(t2*t3); } // Gamma distribution cumulative distribution function // F(x) = gamma(a,x/b) / Gamma(a) // where // a = alpha, alpha > 0 // b = beta, beta > 0 // gamma(a,z) = lower incomplete gamma function // Gamma(z) = regular gamma function // float randgammaf_cdf(float _x, float _alpha, float _beta) { // validate input if (_alpha <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf_cdf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randgammaf_cdf(), beta must be greater than zero"); return 0.0f; } if (_x <= 0.0f) return 0.0f; return liquid_lowergammaf(_alpha, _x/_beta) / liquid_gammaf(_alpha); } // // internal methods // // generate x ~ Gamma(delta,1) float randgammaf_delta(float _delta) { // validate input if ( _delta < 0.0f || _delta >= 1.0f ) { liquid_error(LIQUID_EICONFIG,"randgammaf_delta(), delta must be in [0,1)"); return 0.0f; } // initialization float delta_inv = 1.0f / _delta; float e = expf(1.0f); float v0 = e / (e + _delta); float V0 = 0.0f; float V1 = 0.0f; float V2 = 0.0f; //unsigned int m = 1; float xi = 0.0f; float eta = 0.0f; while (1) { // step 2 V0 = randf(); V1 = randf(); V2 = randf(); if (V2 <= v0) { // step 4 xi = powf(V1, delta_inv); eta = V0 * powf(xi, _delta - 1.0f); } else { // step 5 xi = 1.0f - logf(V1); eta = V0 * expf(-xi); } // step 6 if ( eta > powf(xi,_delta-1.0f)*expf(-xi) ) { //m++; } else { break; } } // xi ~ Gamma(delta,1) return xi; } liquid-dsp-1.7.0/src/random/src/randn.c000066400000000000000000000052541474751757600177330ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // // #include #include #include #include "liquid.internal.h" // Gauss float randnf() { // generate two uniform random numbers float u1, u2; // ensure u1 does not equal zero do { u1 = randf(); } while (u1 == 0.0f); u2 = randf(); return sqrtf(-2*logf(u1)) * sinf(2*M_PI*u2); //return sqrtf(-2*logf(u1)) * cosf(2*M_PI*u2); } void awgn(float *_x, float _nstd) { *_x += randnf()*_nstd; } // Complex Gauss void crandnf(float complex * _y) { // generate two uniform random numbers float u1, u2; // ensure u1 does not equal zero do { u1 = randf(); } while (u1 == 0.0f); u2 = randf(); *_y = sqrtf(-2*logf(u1)) * cexpf(_Complex_I*2*M_PI*u2); } // Internal complex Gauss (inline) float complex icrandnf() { float complex y; crandnf(&y); return y; } void cawgn(float complex *_x, float _nstd) { *_x += icrandnf()*_nstd*0.707106781186547f; } // Gauss random number probability distribution function float randnf_pdf(float _x, float _eta, float _sig) { // validate input if (_sig <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randnf_pdf(), standard deviation must be greater than zero"); return 0.0f; } float t = _x - _eta; float s2 = _sig * _sig; return expf(-t*t/(2.0f*s2)) / sqrtf(2.0f*M_PI*s2); } // Gauss random number cumulative distribution function float randnf_cdf(float _x, float _eta, float _sig) { return 0.5 + 0.5*erff( M_SQRT1_2*(_x-_eta)/_sig ); } liquid-dsp-1.7.0/src/random/src/randnakm.c000066400000000000000000000066611474751757600204270ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Nakagami-m distribution // #include #include #include #include "liquid.internal.h" float randnakmf(float _m, float _omega) { // validate input if (_m < 0.5f) { liquid_error(LIQUID_EICONFIG,"randnakmf(), m cannot be less than 0.5"); return 0.0f; } else if (_omega <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randnakmf(), omega must be greater than zero"); return 0.0f; } // generate Gamma random variable float alpha = _m; float beta = _omega / _m; float x = randgammaf(alpha,beta); // sqrt(x) ~ Nakagami(m,omega) return sqrtf(x); } // Nakagami-m distribution probability distribution function // Nakagami-m // f(x) = (2/Gamma(m)) (m/omega)^m x^(2m-1) exp{-(m/omega)x^2} // where // m : shape parameter, m >= 0.5 // omega : spread parameter, omega > 0 // Gamma(z): regular complete gamma function // x >= 0 float randnakmf_pdf(float _x, float _m, float _omega) { // validate input if (_m < 0.5f) { liquid_error(LIQUID_EICONFIG,"randnakmf_pdf(), m cannot be less than 0.5"); return 0.0f; } else if (_omega <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randnakmf_pdf(), omega must be greater than zero"); return 0.0f; } if (_x <= 0.0f) return 0.0f; float t0 = liquid_lngammaf(_m); float t1 = _m * logf(_m/_omega); float t2 = (2*_m - 1.0f) * logf(_x); float t3 = -(_m/_omega)*_x*_x; return 2.0f * expf( -t0 + t1 + t2 + t3 ); } // Nakagami-m distribution cumulative distribution function // F(x) = gamma(m, x^2 m / omega) / Gamma(m) // where // gamma(z,a) = lower incomplete gamma function // Gamma(z) = regular gamma function // float randnakmf_cdf(float _x, float _m, float _omega) { // validate input if (_m < 0.5f) { liquid_error(LIQUID_EICONFIG,"randnakmf_cdf(), m cannot be less than 0.5"); return 0.0f; } else if (_omega <= 0.0f) { liquid_error(LIQUID_EICONFIG,"randnakmf_cdf(), omega must be greater than zero"); return 0.0f; } if (_x <= 0.0f) return 0.0f; float t0 = liquid_lnlowergammaf(_m, _x*_x*_m/_omega); float t1 = liquid_lngammaf(_m); return expf( t0 - t1 ); } liquid-dsp-1.7.0/src/random/src/randricek.c000066400000000000000000000062371474751757600205750ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Rice-K distribution // #include #include #include #include "liquid.internal.h" // Rice-K float randricekf(float _K, float _omega) { float complex x, y; float s = sqrtf((_omega*_K)/(_K+1)); float sig = sqrtf(0.5f*_omega/(_K+1)); crandnf(&x); y = _Complex_I*( crealf(x)*sig + s ) + ( cimagf(x)*sig ); return cabsf(y); } // Rice-K random number probability distribution function // f(x) = (x/sigma^2) exp{ -(x^2+s^2)/(2sigma^2) } I0( x s / sigma^2 ) // where // s = sqrt( omega*K/(K+1) ) // sigma = sqrt(0.5 omega/(K+1)) // and // K = shape parameter // omega = spread parameter // I0 = modified Bessel function of the first kind // x >= 0 float randricekf_pdf(float _x, float _K, float _omega) { if (_x < 0.0f) return 0.0f; float s = sqrtf((_omega*_K)/(_K+1)); float sig = sqrtf(0.5f*_omega/(_K+1)); float t = _x*_x + s*s; float sig2 = sig*sig; // check high tail condition if ( (_x*s/sig2) > 80.0f ) return 0.0f; float t0 = logf(_x) - logf(sig2); float t1 = -t / (2*sig2); float t2 = liquid_lnbesselif(0.0f, _x*s/sig2); return expf(t0 + t1 + t2); //return (_x / sig2) * expf(-t / (2*sig2)) * liquid_besseli0f(_x*s/sig2); } // Rice-K random number cumulative distribution function float randricekf_cdf(float _x, float _K, float _omega) { if (_x <= 0.0f) return 0.0f; float s = sqrtf((_omega*_K)/(_K+1)); float sig = sqrtf(0.5f*_omega/(_K+1)); // test arguments of Q1 function float alpha = s/sig; float beta = _x/sig; //float Q1 = liquid_MarcumQ1f(alpha, beta); //printf(" Q1(%12.4e, %12.4e) = %12.4e\n", alpha, beta, Q1); if ( (alpha / beta) > 3.0f ) return 0.0f; if ( (beta / alpha) > 3.0f ) return 1.0f; float F = 1.0f - liquid_MarcumQ1f(alpha, beta); // check for precision error if (F < 0.0f) return 0.0f; if (F > 1.0f) return 1.0f; return F; } liquid-dsp-1.7.0/src/random/src/randweib.c000066400000000000000000000060321474751757600204170ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Weibull distribution // #include #include #include #include "liquid.internal.h" // Weibull float randweibf(float _alpha, float _beta, float _gamma) { // validate input if (_alpha <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf(), beta must be greater than zero"); return 0.0f; } float u; do { u = randf(); } while (u==0.0f); return _gamma + _beta*powf( -logf(u), 1.0f/_alpha ); } // Weibull random number probability distribution function float randweibf_pdf(float _x, float _alpha, float _beta, float _gamma) { #ifdef LIQUID_VALIDATE_INPUT // validate input if (_alpha <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf_pdf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf_pdf(), beta must be greater than zero"); return 0.0f; } #endif if (_x < _gamma) return 0.0f; float t = _x - _gamma; return (_alpha/_beta) * powf(t/_beta, _alpha-1.0f) * expf( -powf(t/_beta, _alpha) ); } // Weibull random number cumulative distribution function float randweibf_cdf(float _x, float _alpha, float _beta, float _gamma) { #ifdef LIQUID_VALIDATE_INPUT // validate input if (_alpha <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf_cdf(), alpha must be greater than zero"); return 0.0f; } else if (_beta <= 0) { liquid_error(LIQUID_EICONFIG,"randweibf_cdf(), beta must be greater than zero"); return 0.0f; } #endif if (_x <= _gamma) return 0.0f; return 1.0f - expf( -powf((_x-_gamma)/_beta, _alpha) ); } liquid-dsp-1.7.0/src/random/src/scramble.c000066400000000000000000000063361474751757600204230ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // data scrambler #include #include #include #include "liquid.internal.h" void scramble_data(unsigned char * _x, unsigned int _n) { // t = 4*(floor(_n/4)) unsigned int t = (_n>>2)<<2; // apply static masks unsigned int i; for (i=0; i> (8-j-1)) & 0x01 ) _x[8*i+j] = 255 - _x[8*i+j]; } #else if ( mask & 0x80 ) _x[8*i+0] = 255 - _x[8*i+0]; if ( mask & 0x40 ) _x[8*i+1] = 255 - _x[8*i+1]; if ( mask & 0x20 ) _x[8*i+2] = 255 - _x[8*i+2]; if ( mask & 0x10 ) _x[8*i+3] = 255 - _x[8*i+3]; if ( mask & 0x08 ) _x[8*i+4] = 255 - _x[8*i+4]; if ( mask & 0x04 ) _x[8*i+5] = 255 - _x[8*i+5]; if ( mask & 0x02 ) _x[8*i+6] = 255 - _x[8*i+6]; if ( mask & 0x01 ) _x[8*i+7] = 255 - _x[8*i+7]; #endif } } liquid-dsp-1.7.0/src/random/tests/000077500000000000000000000000001474751757600170325ustar00rootroot00000000000000liquid-dsp-1.7.0/src/random/tests/random_autotest.c000066400000000000000000000155271474751757600224200ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2024 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" #define LIQUID_RANDOM_AUTOTEST_NUM_TRIALS (250000) #define LIQUID_RANDOM_AUTOTEST_ERROR_TOL (0.15) // uniform void autotest_randf() { unsigned long int N = LIQUID_RANDOM_AUTOTEST_NUM_TRIALS; unsigned long int i; float x, m1=0.0f, m2=0.0f; float tol = LIQUID_RANDOM_AUTOTEST_ERROR_TOL; // uniform for (i=0; i= 0) index = (unsigned int)indexf; if (index >= _num_bins) index = _num_bins - 1; _bins[index]++; return index; } // noramlize histogram (area under curve) float _support_histogram_normalize(float * _bins, unsigned int _num_bins, float _vmin, float _vmax) { float area = 0.0f; unsigned int i; for (i=0; i<_num_bins; i++) area += _bins[i]; area *= (_vmax - _vmin) / (float)_num_bins; for (i=0; i<_num_bins; i++) _bins[i] /= area; return area; } // log histogram void _support_histogram_log(float * _bins, unsigned int _num_bins, float _vmin, float _vmax) { // find max(hist) unsigned int i; float hist_max = 0; for (i=0; i<_num_bins; i++) hist_max = _bins[i] > hist_max ? _bins[i] : hist_max; unsigned int num_chars = 72; float _vstep = (_vmax - _vmin) / (float)(_num_bins-1); printf("%8s : [%12s]\n", "v", "bin value"); for (i=0; i<_num_bins; i++) { printf("%8.2f : [%12g]", _vmin + i*_vstep, _bins[i]); unsigned int k; unsigned int n = round(num_chars * _bins[i] / hist_max); for (k=0; k #include #include #include "autotest/autotest.h" #include "liquid.internal.h" // compute basic entropy metric float liquid_scramble_test_entropy(unsigned char * _x, unsigned int _n) { unsigned int i; // count ones unsigned int num_ones=0; for (i=0; i<_n; i++) num_ones += liquid_c_ones[_x[i]]; // compute probabilities (add small value to prevent // possible log(0)) float p1 = (float)num_ones / (float)(8*_n) + 1e-12f; float p0 = 1.0 - p1; return -p0*log2f(p0) - p1*log2f(p1); } // helper function to keep code base small void liquid_scramble_test(unsigned int _n) { unsigned char x[_n]; // input data unsigned char y[_n]; // scrambled data unsigned char z[_n]; // unscrambled data unsigned int i; // initialize data array for (i=0; i<_n; i++) x[i] = 0x00; // scramble input memmove(y,x,_n); scramble_data(y,_n); // unscramble result memmove(z,y,_n); unscramble_data(z,_n); // ensure data are equivalent CONTEND_SAME_DATA(x,z,_n*sizeof(unsigned char)); // compute entropy metric float H = liquid_scramble_test_entropy(y,_n); CONTEND_EXPRESSION( H > 0.8f ); } // test unscrambling of soft bits (helper function to keep code base small) void liquid_scramble_soft_test(unsigned int _n) { unsigned char msg_org[_n]; // input data unsigned char msg_enc[_n]; // scrambled data unsigned char msg_soft[8*_n]; // scrambled data (soft bits) unsigned char msg_dec[_n]; // unscrambled data unsigned int i; // initialize data array (random) for (i=0; i<_n; i++) msg_org[i] = rand() & 0xff; // scramble input memmove(msg_enc, msg_org, _n); scramble_data(msg_enc,_n); // convert to soft bits for (i=0; i<_n; i++) liquid_unpack_soft_bits(msg_enc[i], 8, &msg_soft[8*i]); // unscramble result unscramble_data_soft(msg_soft, _n); // unpack soft bits for (i=0; i<_n; i++) { unsigned int sym_out; liquid_pack_soft_bits(&msg_soft[8*i], 8, &sym_out); msg_dec[i] = sym_out; } // ensure data are equivalent CONTEND_SAME_DATA(msg_org, msg_dec, _n); } // // AUTOTESTS : simple data scrambling // void autotest_scramble_n16() { liquid_scramble_test(16); }; void autotest_scramble_n64() { liquid_scramble_test(64); }; void autotest_scramble_n256() { liquid_scramble_test(256); }; void autotest_scramble_n11() { liquid_scramble_test(11); }; void autotest_scramble_n33() { liquid_scramble_test(33); }; void autotest_scramble_n277() { liquid_scramble_test(277); }; // // AUTOTESTS : soft data scrambling // void autotest_scramble_soft_n16() { liquid_scramble_soft_test(16); }; void autotest_scramble_soft_n64() { liquid_scramble_soft_test(64); }; void autotest_scramble_soft_n256() { liquid_scramble_soft_test(256); }; void autotest_scramble_soft_n11() { liquid_scramble_soft_test(11); }; void autotest_scramble_soft_n33() { liquid_scramble_soft_test(33); }; void autotest_scramble_soft_n277() { liquid_scramble_soft_test(277); }; liquid-dsp-1.7.0/src/sequence/000077500000000000000000000000001474751757600162205ustar00rootroot00000000000000liquid-dsp-1.7.0/src/sequence/bench/000077500000000000000000000000001474751757600172775ustar00rootroot00000000000000liquid-dsp-1.7.0/src/sequence/bench/bsequence_benchmark.c000066400000000000000000000053411474751757600234320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "liquid.h" // Helper function to keep code base small void bsequence_correlate_bench(struct rusage *_start, struct rusage *_finish, unsigned long int *_num_iterations, unsigned int _n) { // normalize number of iterations *_num_iterations *= 1000; *_num_iterations /= _n; if (*_num_iterations < 1) *_num_iterations = 1; // create and initialize binary sequences bsequence bs1 = bsequence_create(_n); bsequence bs2 = bsequence_create(_n); unsigned long int i; int rxy = 0; // start trials getrusage(RUSAGE_SELF, _start); for (i=0; i<(*_num_iterations); i++) { rxy += bsequence_correlate(bs1, bs2); rxy -= bsequence_correlate(bs1, bs2); rxy += bsequence_correlate(bs1, bs2); rxy -= bsequence_correlate(bs1, bs2); bsequence_push(rxy > 0 ? bs1 : bs2, 1); } getrusage(RUSAGE_SELF, _finish); *_num_iterations *= 4; // clean up memory bsequence_destroy(bs1); bsequence_destroy(bs2); } #define BSEQUENCE_BENCHMARK_API(N) \ ( struct rusage *_start, \ struct rusage *_finish, \ unsigned long int *_num_iterations) \ { bsequence_correlate_bench(_start, _finish, _num_iterations, N); } // void benchmark_bsequence_xcorr_n16 BSEQUENCE_BENCHMARK_API(16) void benchmark_bsequence_xcorr_n64 BSEQUENCE_BENCHMARK_API(64) void benchmark_bsequence_xcorr_n256 BSEQUENCE_BENCHMARK_API(256) void benchmark_bsequence_xcorr_n1024 BSEQUENCE_BENCHMARK_API(1024) liquid-dsp-1.7.0/src/sequence/src/000077500000000000000000000000001474751757600170075ustar00rootroot00000000000000liquid-dsp-1.7.0/src/sequence/src/bsequence.c000066400000000000000000000225331474751757600211320ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // bsequence.c // // generic binary sequence // #include #include #include #include #include "liquid.internal.h" // struct bsequence_s { unsigned int * s; // sequence array, memory pointer unsigned int num_bits; // number of bits in sequence unsigned int num_bits_msb; // number of bits in most-significant block unsigned int bit_mask_msb; // bit mask for most-significant block unsigned int s_len; // length of array, number of allocated blocks }; // Create a binary sequence of a specific length bsequence bsequence_create(unsigned int _num_bits) { bsequence bs; // allocate memory for binary sequence bs = (bsequence) malloc( sizeof(struct bsequence_s) ); // initialize variables bs->s_len = 0; bs->s = NULL; bs->num_bits = _num_bits; // initialize array length div_t d = div( bs->num_bits, sizeof(unsigned int)*8 ); bs->s_len = d.quot; bs->s_len += (d.rem > 0) ? 1 : 0; // number of bits in MSB block bs->num_bits_msb = (d.rem == 0) ? 8*sizeof(unsigned int) : (unsigned int) d.rem; // bit mask for MSB block unsigned int i; bs->bit_mask_msb = 0; for (i=0; inum_bits_msb; i++) { bs->bit_mask_msb <<= 1; bs->bit_mask_msb |= 1; } // initialize array with zeros bs->s = (unsigned int*) malloc( bs->s_len * sizeof(unsigned int) ); bsequence_reset(bs); return bs; } // Free memory in a binary sequence int bsequence_destroy(bsequence _bs) { free( _bs->s ); free( _bs ); return LIQUID_OK; } int bsequence_reset(bsequence _bs) { memset( _bs->s, 0x00, (_bs->s_len)*sizeof(unsigned int) ); return LIQUID_OK; } // initialize sequence on external array int bsequence_init(bsequence _bs, unsigned char * _v) { // push single bit at a time unsigned int i; unsigned int k=0; unsigned char byte = 0x00; unsigned char mask = 0x80; for (i=0; i<_bs->num_bits; i++) { if ( (i%8)==0 ) { byte = _v[k++]; mask = 0x80; } bsequence_push(_bs, byte & mask ? 1 : 0); mask >>= 1; } return LIQUID_OK; } // Print sequence to the screen int bsequence_print(bsequence _bs) { #if 0 unsigned int i, j; unsigned int chunk; unsigned int p = 8*sizeof(unsigned int); printf("bsequence[%6u]: ", _bs->num_bits); for (i=0; i<_bs->s_len; i++) { // strip chunk from sequence, starting with most-significant bits chunk = _bs->s[i]; for (j=0; jnum_bits_msb) printf("."); // print '.' for each bit in byte not included in first byte else printf("%c", (chunk >> (p-j-1)) & 0x01 ? '1' : '0'); if ( ((j+1)%8)==0 ) printf(" "); } } printf("\n"); #else printf("", _bs->num_bits); #endif return LIQUID_OK; } // push bits in from the right int bsequence_push(bsequence _bs, unsigned int _bit) { unsigned int overflow; unsigned int i; unsigned int p = 8*sizeof(unsigned int); // shift first block _bs->s[0] <<= 1; _bs->s[0] &= _bs->bit_mask_msb; for (i=1; i<_bs->s_len; i++) { // overflow for i-th block is its MSB overflow = (_bs->s[i] >> (p-1)) & 1; // shift block 1 bit _bs->s[i] <<= 1; // apply overflow to (i-1)-th block's LSB _bs->s[i-1] |= overflow; } // apply input bit to LSB of last block _bs->s[_bs->s_len-1] |= ( _bit & 1 ); return LIQUID_OK; } // circular shift (left) int bsequence_circshift(bsequence _bs) { // extract most-significant (left-most) bit unsigned int msb_mask = 1u << (_bs->num_bits_msb-1); unsigned int b = (_bs->s[0] & msb_mask) >> (_bs->num_bits_msb-1); // push bit into sequence return bsequence_push(_bs, b); } // Correlate two binary sequences together int bsequence_correlate(bsequence _bs1, bsequence _bs2) { int rxy = 0; unsigned int i; if ( _bs1->s_len != _bs2->s_len ) { liquid_error(LIQUID_EICONFIG,"bsequence_correlate(), binary sequences must be the same length!"); return 0; } unsigned int chunk; for (i=0; i<_bs1->s_len; i++) { // chunk = _bs1->s[i] ^ _bs2->s[i]; chunk = ~chunk; rxy += liquid_count_ones(chunk); } // compensate for most-significant block and return rxy -= 8*sizeof(unsigned int) - _bs1->num_bits_msb; return rxy; } // compute the binary addition of two bit sequences int bsequence_add(bsequence _bs1, bsequence _bs2, bsequence _bs3) { // test lengths of all sequences if ( _bs1->s_len != _bs2->s_len || _bs1->s_len != _bs3->s_len || _bs2->s_len != _bs3->s_len ) { return liquid_error(LIQUID_EICONFIG,"bsequence_add(), binary sequences must be same length!"); } // b3 = b1 + b2 unsigned int i; for (i=0; i<_bs1->s_len; i++) _bs3->s[i] = _bs1->s[i] ^ _bs2->s[i]; // no need to mask most-significant byte return LIQUID_OK; } // compute the binary multiplication of two bit sequences int bsequence_mul(bsequence _bs1, bsequence _bs2, bsequence _bs3) { // test lengths of all sequences if ( _bs1->s_len != _bs2->s_len || _bs1->s_len != _bs3->s_len || _bs2->s_len != _bs3->s_len ) { return liquid_error(LIQUID_EICONFIG,"bsequence_mul(), binary sequences must be same length!"); } // b3 = b1 * b2 unsigned int i; for (i=0; i<_bs1->s_len; i++) _bs3->s[i] = _bs1->s[i] & _bs2->s[i]; // no need to mask most-significant byte return LIQUID_OK; } // accumulate the 1's in a binary sequence unsigned int bsequence_accumulate(bsequence _bs) { unsigned int i; unsigned int r=0; for (i=0; i<_bs->s_len; i++) r += liquid_count_ones(_bs->s[i]); return r; } // return the number of ones in a sequence unsigned int bsequence_get_length(bsequence _bs) { return _bs->num_bits; } // return the i-th bit of the sequence unsigned int bsequence_index(bsequence _bs, unsigned int _i) { if (_i >= _bs->num_bits) { liquid_error(LIQUID_EICONFIG,"bsequence_index(), invalid index %u", _i); return 0; } div_t d = div( _i, 8*sizeof(unsigned int) ); // compute byte index unsigned int k = _bs->s_len - d.quot - 1; // return particular bit at byte index return (_bs->s[k] >> d.rem ) & 1; } // initialize two sequences to complementary codes. sequences must // be of length at least 8 and a power of 2 (e.g. 8, 16, 32, 64,...) int bsequence_create_ccodes(bsequence _qa, bsequence _qb) { // make sure sequences are the same length if (_qa->num_bits != _qb->num_bits) return liquid_error(LIQUID_EICONFIG,"bsequence_create_ccodes(), sequence lengths must match"); if (_qa->num_bits < 8) return liquid_error(LIQUID_EICONFIG,"bsequence_create_ccodes(), sequence too short"); if ( (_qa->num_bits)%8 != 0 ) return liquid_error(LIQUID_EICONFIG,"bsequence_create_ccodes(), sequence must be multiple of 8"); // generate two temporary arrays unsigned int num_bytes = _qa->num_bits / 8; unsigned char a[num_bytes]; unsigned char b[num_bytes]; memset(a, 0x00, num_bytes); memset(b, 0x00, num_bytes); // initialize a[num_bytes-1] = 0xb8; // 1011 1000 b[num_bytes-1] = 0xb7; // 1011 0111 unsigned int i; unsigned int n=1; unsigned int i_n1; unsigned int i_n0; while (n < num_bytes) { i_n1 = num_bytes - n; i_n0 = num_bytes - 2*n; // a -> [a b] // b -> [a ~b] memmove(&a[i_n0], &a[i_n1], n*sizeof(unsigned char)); memmove(&b[i_n0], &a[i_n1], n*sizeof(unsigned char)); memmove(&a[i_n1], &b[i_n1], n*sizeof(unsigned char)); memmove(&b[i_n1], &b[i_n1], n*sizeof(unsigned char)); // complement lower half for (i=0; i #include #include #include #include "liquid.internal.h" #define LIQUID_MIN_MSEQUENCE_M 2 #define LIQUID_MAX_MSEQUENCE_M 31 // maximal-length sequence struct msequence_s { unsigned int m; // length generator polynomial, shift register unsigned int g; // generator polynomial, form: { x^m + ... + 1 } unsigned int a; // initial shift register state, default: 1 // derived values unsigned int n; // length of sequence, n = (2^m)-1 unsigned int state; // shift register }; // create a maximal-length sequence (m-sequence) object with // an internal shift register length of _m bits. // _m : generator polynomial length, sequence length is (2^m)-1 // _g : generator polynomial, starting with most-significant bit // _a : initial shift register state, default: 000...001 msequence msequence_create(unsigned int _m, unsigned int _g, unsigned int _a) { // validate input if (_m > LIQUID_MAX_MSEQUENCE_M || _m < LIQUID_MIN_MSEQUENCE_M) return liquid_error_config("msequence_create(), m (%u) not in range", _m); //if (_a == 0) // return liquid_error_config("msequence_create(), state 'a' cannot be 0"); // allocate memory for msequence object msequence ms = (msequence) malloc(sizeof(struct msequence_s)); // set internal values ms->m = _m; // generator polynomial length ms->g = _g; // generator polynomial ms->a = _a; // generator polynomial ms->n = (1<<_m)-1; // sequence length, (2^m)-1 ms->state = ms->a; // shift register state return ms; } // Copy maximal-length sequence (m-sequence) object msequence msequence_copy(msequence q_orig) { // validate input if (q_orig == NULL) return liquid_error_config("msequence_copy(), object cannot be NULL"); // create filter object and copy base parameters msequence q_copy = (msequence) malloc(sizeof(struct msequence_s)); memmove(q_copy, q_orig, sizeof(struct msequence_s)); return q_copy; } // create a maximal-length sequence (m-sequence) object from a generator polynomial msequence msequence_create_genpoly(unsigned int _g) { unsigned int t = liquid_msb_index(_g); // validate input if (t < 2) return liquid_error_config("msequence_create_genpoly(), invalid generator polynomial: 0x%x", _g); // compute derived values unsigned int m = t; // m-sequence shift register length unsigned int a = 1; // m-sequence initial state // generate object and return return msequence_create(m,_g,a); } // creates a default maximal-length sequence msequence msequence_create_default(unsigned int _m) { unsigned int g = 0; switch (_m) { case 2: g = LIQUID_MSEQUENCE_GENPOLY_M2; break; case 3: g = LIQUID_MSEQUENCE_GENPOLY_M3; break; case 4: g = LIQUID_MSEQUENCE_GENPOLY_M4; break; case 5: g = LIQUID_MSEQUENCE_GENPOLY_M5; break; case 6: g = LIQUID_MSEQUENCE_GENPOLY_M6; break; case 7: g = LIQUID_MSEQUENCE_GENPOLY_M7; break; case 8: g = LIQUID_MSEQUENCE_GENPOLY_M8; break; case 9: g = LIQUID_MSEQUENCE_GENPOLY_M9; break; case 10: g = LIQUID_MSEQUENCE_GENPOLY_M10; break; case 11: g = LIQUID_MSEQUENCE_GENPOLY_M11; break; case 12: g = LIQUID_MSEQUENCE_GENPOLY_M12; break; case 13: g = LIQUID_MSEQUENCE_GENPOLY_M13; break; case 14: g = LIQUID_MSEQUENCE_GENPOLY_M14; break; case 15: g = LIQUID_MSEQUENCE_GENPOLY_M15; break; case 16: g = LIQUID_MSEQUENCE_GENPOLY_M16; break; case 17: g = LIQUID_MSEQUENCE_GENPOLY_M17; break; case 18: g = LIQUID_MSEQUENCE_GENPOLY_M18; break; case 19: g = LIQUID_MSEQUENCE_GENPOLY_M19; break; case 20: g = LIQUID_MSEQUENCE_GENPOLY_M20; break; case 21: g = LIQUID_MSEQUENCE_GENPOLY_M21; break; case 22: g = LIQUID_MSEQUENCE_GENPOLY_M22; break; case 23: g = LIQUID_MSEQUENCE_GENPOLY_M23; break; case 24: g = LIQUID_MSEQUENCE_GENPOLY_M24; break; case 25: g = LIQUID_MSEQUENCE_GENPOLY_M25; break; case 26: g = LIQUID_MSEQUENCE_GENPOLY_M26; break; case 27: g = LIQUID_MSEQUENCE_GENPOLY_M27; break; case 28: g = LIQUID_MSEQUENCE_GENPOLY_M28; break; case 29: g = LIQUID_MSEQUENCE_GENPOLY_M29; break; case 30: g = LIQUID_MSEQUENCE_GENPOLY_M30; break; case 31: g = LIQUID_MSEQUENCE_GENPOLY_M31; break; default: return liquid_error_config("msequence_create_default(), m (%u) not in range", _m); } // return return msequence_create_genpoly(g); } // destroy an msequence object, freeing all internal memory int msequence_destroy(msequence _ms) { free(_ms); return LIQUID_OK; } // prints the sequence's internal state to the screen int msequence_print(msequence _ms) { printf("\n", _ms->m, _ms->n, _ms->g, _ms->state); return LIQUID_OK; } // advance msequence on shift register, returning output bit unsigned int msequence_advance(msequence _ms) { // compute return bit as binary dot product between the // internal shift register and the generator polynomial unsigned int b = liquid_bdotprod( _ms->state, _ms->g); _ms->state <<= 1; // shift internal register _ms->state |= b; // push bit onto register _ms->state &= _ms->n; // apply mask to register return b; // return result } // generate pseudo-random symbol from shift register // _ms : m-sequence object // _bps : bits per symbol of output unsigned int msequence_generate_symbol(msequence _ms, unsigned int _bps) { unsigned int i; unsigned int s = 0; for (i=0; i<_bps; i++) { s <<= 1; s |= msequence_advance(_ms); } return s; } // reset msequence shift register to original state, typically '1' int msequence_reset(msequence _ms) { _ms->state = _ms->a; return LIQUID_OK; } // initialize a bsequence object on an msequence object // _bs : bsequence object // _ms : msequence object int bsequence_init_msequence(bsequence _bs, msequence _ms) { // clear binary sequence bsequence_reset(_bs); unsigned int i; for (i=0; i<(_ms->n); i++) bsequence_push(_bs, msequence_advance(_ms)); return LIQUID_OK; } // get the length of the generator polynomial, g (m) unsigned int msequence_get_genpoly_length(msequence _ms) { return _ms->m; } // get the length of the sequence unsigned int msequence_get_length(msequence _ms) { return _ms->n; } // get the generator polynomial, g unsigned int msequence_get_genpoly(msequence _ms) { return _ms->g; } // get the internal state of the sequence unsigned int msequence_get_state(msequence _ms) { return _ms->state; } // set the internal state of the sequence int msequence_set_state(msequence _ms, unsigned int _a) { // set internal state // NOTE: if state is set to zero, this will lock the sequence generator, // but let the user set this value if they wish _ms->state = _a; return LIQUID_OK; } // measure the period the shift register (should be 2^m-1 with a proper generator polynomial) unsigned int msequence_measure_period(msequence _ms) { // get current state unsigned int s = msequence_get_state(_ms); // cycle through sequence and look for initial state unsigned int i; unsigned int period = 0; for (i=0; i<_ms->n+1; i++) { msequence_advance(_ms); period++; if (msequence_get_state(_ms)==s) break; } // assert that state has been returned return period; } // measure the period of a generator polynomial unsigned int msequence_genpoly_period(unsigned int _g) { msequence q = msequence_create_genpoly(_g); if (q == NULL) { liquid_error(LIQUID_EICONFIG,"msequence_genpoly_period(), invalid generator polynomial 0x%x\n", _g); return 0; } unsigned int period = msequence_measure_period(q); msequence_destroy(q); return period; } liquid-dsp-1.7.0/src/sequence/tests/000077500000000000000000000000001474751757600173625ustar00rootroot00000000000000liquid-dsp-1.7.0/src/sequence/tests/bsequence_autotest.c000066400000000000000000000142701474751757600234340ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // // test initialization of binary sequence // void autotest_bsequence_init() { // 1111 0000 1100 1010 unsigned char v[2] = {0xf0, 0xca}; // create and initialize sequence bsequence q = bsequence_create(16); bsequence_init(q,v); // run tests CONTEND_EQUALITY( bsequence_index(q,15), 1 ); CONTEND_EQUALITY( bsequence_index(q,14), 1 ); CONTEND_EQUALITY( bsequence_index(q,13), 1 ); CONTEND_EQUALITY( bsequence_index(q,12), 1 ); CONTEND_EQUALITY( bsequence_index(q,11), 0 ); CONTEND_EQUALITY( bsequence_index(q,10), 0 ); CONTEND_EQUALITY( bsequence_index(q, 9), 0 ); CONTEND_EQUALITY( bsequence_index(q, 8), 0 ); CONTEND_EQUALITY( bsequence_index(q, 7), 1 ); CONTEND_EQUALITY( bsequence_index(q, 6), 1 ); CONTEND_EQUALITY( bsequence_index(q, 5), 0 ); CONTEND_EQUALITY( bsequence_index(q, 4), 0 ); CONTEND_EQUALITY( bsequence_index(q, 3), 1 ); CONTEND_EQUALITY( bsequence_index(q, 2), 0 ); CONTEND_EQUALITY( bsequence_index(q, 1), 1 ); CONTEND_EQUALITY( bsequence_index(q, 0), 0 ); // clean up memory bsequence_destroy(q); } // // test correlation between to sequences // void autotest_bsequence_correlate() { // v0 : 1111 0000 1100 1010 // v1 : 1100 1011 0001 1110 // sim : 1100 0100 0010 1011 (7 similar bits) unsigned char v0[2] = {0xf0, 0xca}; unsigned char v1[2] = {0xcb, 0x1e}; // create and initialize sequences bsequence q0 = bsequence_create(16); bsequence q1 = bsequence_create(16); bsequence_init(q0,v0); bsequence_init(q1,v1); // run tests CONTEND_EQUALITY( bsequence_correlate(q0,q1), 7 ); // clean up memory bsequence_destroy(q0); bsequence_destroy(q1); } // // test add operations on two sequences // void autotest_bsequence_add() { // v0 : 1111 0000 1100 1010 // v1 : 1100 1011 0001 1110 // sum : 0011 1011 1101 0100 unsigned char v0[2] = {0xf0, 0xca}; unsigned char v1[2] = {0xcb, 0x1e}; // create and initialize sequences bsequence q0 = bsequence_create(16); bsequence q1 = bsequence_create(16); bsequence_init(q0,v0); bsequence_init(q1,v1); // create result sequence bsequence r = bsequence_create(16); bsequence_add(q0, q1, r); // run tests CONTEND_EQUALITY( bsequence_index(r,15), 0 ); CONTEND_EQUALITY( bsequence_index(r,14), 0 ); CONTEND_EQUALITY( bsequence_index(r,13), 1 ); CONTEND_EQUALITY( bsequence_index(r,12), 1 ); CONTEND_EQUALITY( bsequence_index(r,11), 1 ); CONTEND_EQUALITY( bsequence_index(r,10), 0 ); CONTEND_EQUALITY( bsequence_index(r, 9), 1 ); CONTEND_EQUALITY( bsequence_index(r, 8), 1 ); CONTEND_EQUALITY( bsequence_index(r, 7), 1 ); CONTEND_EQUALITY( bsequence_index(r, 6), 1 ); CONTEND_EQUALITY( bsequence_index(r, 5), 0 ); CONTEND_EQUALITY( bsequence_index(r, 4), 1 ); CONTEND_EQUALITY( bsequence_index(r, 3), 0 ); CONTEND_EQUALITY( bsequence_index(r, 2), 1 ); CONTEND_EQUALITY( bsequence_index(r, 1), 0 ); CONTEND_EQUALITY( bsequence_index(r, 0), 0 ); // clean up memory bsequence_destroy(q0); bsequence_destroy(q1); bsequence_destroy(r); } // // test multiply operations on two sequences // void autotest_bsequence_mul() { // v0 : 1111 0000 1100 1010 // v1 : 1100 1011 0001 1110 // prod : 1100 0000 0000 1010 unsigned char v0[2] = {0xf0, 0xca}; unsigned char v1[2] = {0xcb, 0x1e}; // create and initialize sequences bsequence q0 = bsequence_create(16); bsequence q1 = bsequence_create(16); bsequence_init(q0,v0); bsequence_init(q1,v1); // create result sequence bsequence r = bsequence_create(16); bsequence_mul(q0, q1, r); // run tests CONTEND_EQUALITY( bsequence_index(r,15), 1 ); CONTEND_EQUALITY( bsequence_index(r,14), 1 ); CONTEND_EQUALITY( bsequence_index(r,13), 0 ); CONTEND_EQUALITY( bsequence_index(r,12), 0 ); CONTEND_EQUALITY( bsequence_index(r,11), 0 ); CONTEND_EQUALITY( bsequence_index(r,10), 0 ); CONTEND_EQUALITY( bsequence_index(r, 9), 0 ); CONTEND_EQUALITY( bsequence_index(r, 8), 0 ); CONTEND_EQUALITY( bsequence_index(r, 7), 0 ); CONTEND_EQUALITY( bsequence_index(r, 6), 0 ); CONTEND_EQUALITY( bsequence_index(r, 5), 0 ); CONTEND_EQUALITY( bsequence_index(r, 4), 0 ); CONTEND_EQUALITY( bsequence_index(r, 3), 1 ); CONTEND_EQUALITY( bsequence_index(r, 2), 0 ); CONTEND_EQUALITY( bsequence_index(r, 1), 1 ); CONTEND_EQUALITY( bsequence_index(r, 0), 0 ); // clean up memory bsequence_destroy(q0); bsequence_destroy(q1); bsequence_destroy(r); } // // test accumulation of binary sequence // void autotest_bsequence_accumulate() { // 1111 0000 1100 1010 (8 total bits) unsigned char v[2] = {0xf0, 0xca}; // create and initialize sequence bsequence q = bsequence_create(16); bsequence_init(q,v); // run tests CONTEND_EQUALITY( bsequence_accumulate(q), 8 ); // clean up memory bsequence_destroy(q); } liquid-dsp-1.7.0/src/sequence/tests/complementary_codes_autotest.c000066400000000000000000000054201474751757600255130ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // // AUTOTEST: validate autocorrelation properties of // complementary codes // void complementary_codes_test(unsigned int _n) { // create and initialize codes bsequence a = bsequence_create(_n); bsequence b = bsequence_create(_n); bsequence_create_ccodes(a, b); // print if (liquid_autotest_verbose) { bsequence_print(a); bsequence_print(b); } // generate test sequences bsequence ax = bsequence_create(_n); bsequence bx = bsequence_create(_n); bsequence_create_ccodes(ax, bx); unsigned int i; signed int raa, rbb; for (i=0; i<_n; i++) { // correlate like sequences raa = 2*bsequence_correlate(a,ax) - _n; rbb = 2*bsequence_correlate(b,bx) - _n; if (i==0) { CONTEND_EQUALITY(raa+rbb,2*_n); } else { CONTEND_EQUALITY(raa+rbb,0); } bsequence_circshift(ax); bsequence_circshift(bx); } // clean up memory bsequence_destroy(a); bsequence_destroy(b); bsequence_destroy(ax); bsequence_destroy(bx); } void autotest_complementary_code_n8() { complementary_codes_test(8); } void autotest_complementary_code_n16() { complementary_codes_test(16); } void autotest_complementary_code_n32() { complementary_codes_test(32); } void autotest_complementary_code_n64() { complementary_codes_test(64); } void autotest_complementary_code_n128() { complementary_codes_test(128); } void autotest_complementary_code_n256() { complementary_codes_test(256); } void autotest_complementary_code_n512() { complementary_codes_test(512); } liquid-dsp-1.7.0/src/sequence/tests/msequence_autotest.c000066400000000000000000000162111474751757600234440ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2023 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.h" // test initialization of binary sequence on m-sequence void autotest_bsequence_init_msequence() { // create and initialize m-sequence msequence ms = msequence_create_default(4); // create and initialize binary sequence on m-sequence bsequence bs; bs = bsequence_create( msequence_get_length(ms) ); bsequence_init_msequence(bs, ms); if (liquid_autotest_verbose) bsequence_print(bs); CONTEND_EQUALITY( bsequence_get_length(bs), msequence_get_length(ms) ) // clean up memory bsequence_destroy(bs); msequence_destroy(ms); } // helper function to test auto-correlation properties of m-sequence void msequence_test_autocorrelation(unsigned int _m) { // create and initialize m-sequence msequence ms = msequence_create_default(_m); unsigned int n = msequence_get_length(ms); // create and initialize first binary sequence on m-sequence bsequence bs1 = bsequence_create(n); bsequence_init_msequence(bs1, ms); // create and initialize second binary sequence on same m-sequence bsequence bs2 = bsequence_create(n); bsequence_init_msequence(bs2, ms); // ensure sequences are the same length CONTEND_EQUALITY( bsequence_get_length(bs1), n ) CONTEND_EQUALITY( bsequence_get_length(bs2), n ) // when sequences are aligned, autocorrelation is equal to length signed int rxy; rxy = bsequence_correlate(bs1, bs2); CONTEND_EQUALITY( rxy, n ) // when sequences are misaligned, autocorrelation is equal to -1 unsigned int i; for (i=0; i #include #include "liquid.h" void benchmark_count_ones(struct rusage * _start, struct rusage * _finish, unsigned long int * _num_iterations) { // allocate buffer of bytes and initialize unsigned int i, j; unsigned int buf_len = 1024; unsigned int * buf = (unsigned int *) malloc(buf_len*sizeof(unsigned int)); for (i=0; i #include #include #include "liquid.internal.h" // shift array to the left _b bits, filling in zeros // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_lbshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_b >= 8) return liquid_error(LIQUID_EIRANGE,"liquid_lbshift(), shift amount must be in [0,7]"); // invoke circular shift left and mask last byte liquid_lbcircshift(_src, _n, _b); _src[_n-1] &= 0xff << _b; return LIQUID_OK; } // shift array to the right _b bits filling in zeros // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_rbshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_b >= 8) return liquid_error(LIQUID_EIRANGE,"liquid_rbshift(), shift amount must be in [0,7]"); // invoke circular shift right and mask first byte liquid_rbcircshift(_src, _n, _b); _src[0] &= 0xff >> _b; return LIQUID_OK; } // circular shift array to the left _b bits // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_lbcircshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_b >= 8) return liquid_error(LIQUID_EIRANGE,"liquid_lbcircshift(), shift amount must be in [0,7]"); // unsigned int shift_0 = _b; // shift amount: first byte unsigned int shift_1 = 8 - _b; // shift amount: second byte unsigned char mask_0 = 0xff << shift_0; // bit mask: first byte unsigned char mask_1 = 0xff >> shift_1; // bit mask: second byte #if 0 printf("num_bits = %1u, shift_0 = %1u, shift_1 = %1u mask_0=%.2x, mask_1=%.2x\n", _b, shift_0, shift_1, mask_0, mask_1); #endif // shift then mask unsigned int i; unsigned char byte; unsigned char byte_0; unsigned char byte_1; unsigned char src_0 = _src[0]; // retain first byte for (i=0; i<_n; i++) { // strip bytes byte_0 = _src[i]; byte_1 = (i==_n-1) ? src_0 : _src[i+1]; // shift then mask byte = ((byte_0 << shift_0) & mask_0) | ((byte_1 >> shift_1) & mask_1); // store result _src[i] = byte; } return LIQUID_OK; } // circular shift array to the right _b bits // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bits to shift int liquid_rbcircshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_b >= 8) return liquid_error(LIQUID_EIRANGE,"liquid_rbshift(), shift amount must be in [0,7]"); // unsigned int shift_0 = 8 - _b; // shift amount: first byte unsigned int shift_1 = _b; // shift amount: second byte unsigned char mask_0 = 0xff << shift_0; // bit mask: first byte unsigned char mask_1 = 0xff >> shift_1; // bit mask: second byte #if 0 printf("num_bits = %1u, shift_0 = %1u, shift_1 = %1u mask_0=%.2x, mask_1=%.2x\n", _b, shift_0, shift_1, mask_0, mask_1); #endif // shift then mask int i; unsigned char byte; unsigned char byte_0; unsigned char byte_1; unsigned char src_n = _src[_n-1]; // retain last byte for (i=_n-1; i>=0; i--) { // strip bytes byte_0 = (i==0) ? src_n : _src[i-1]; byte_1 = _src[i]; // shift then mask byte = ((byte_0 << shift_0) & mask_0) | ((byte_1 >> shift_1) & mask_1); // store result _src[i] = byte; } return LIQUID_OK; } liquid-dsp-1.7.0/src/utility/src/byte_utilities.c000066400000000000000000000204231474751757600221050ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // general utilities for manipulating bits and bytes, including // * counting ones in a byte, word, long word, etc. // * counting bit differences (e.g. errors) in arrays // * arrays for fast counting // * array for reversing bytes // #include #include "liquid.internal.h" // count the number of ones in an integer unsigned int liquid_count_ones(unsigned int _x) { #if SIZEOF_INT == 2 return liquid_count_ones_uint16(_x); #elif SIZEOF_INT == 4 return liquid_count_ones_uint32(_x); #else unsigned int i; unsigned int c=0; for (i=0; i>= 8; } return c; #endif } // count the number of ones in an integer, modulo 2 unsigned int liquid_count_ones_mod2(unsigned int _x) { #if SIZEOF_INT == 2 return liquid_count_ones_mod2_uint16(_x); #elif SIZEOF_INT == 4 return liquid_count_ones_mod2_uint32(_x); #else unsigned int i; unsigned int c=0; for (i=0; i>= 8; } return c & 1; #endif } // count the binary dot-product between two integers unsigned int liquid_bdotprod(unsigned int _x, unsigned int _y) { unsigned int t = _x & _y; #if SIZEOF_INT == 2 return liquid_count_ones_mod2_uint16(t); #elif SIZEOF_INT == 4 return liquid_count_ones_mod2_uint32(t); #else unsigned int i; unsigned int c=0; for (i=0; i>= 8; } return c & 1; #endif } // counts the number of different bits between two symbols unsigned int count_bit_errors(unsigned int _s1, unsigned int _s2) { return liquid_count_ones(_s1^_s2); } // counts the number of different bits between two arrays of symbols // _msg0 : original message [size: _n x 1] // _msg1 : copy of original message [size: _n x 1] // _n : message size unsigned int count_bit_errors_array(unsigned char * _msg0, unsigned char * _msg1, unsigned int _n) { unsigned int num_bit_errors = 0; unsigned int i; for (i=0; i<_n; i++) num_bit_errors += liquid_c_ones[_msg0[i] ^ _msg1[i]]; return num_bit_errors; } // print string of bits to standard output int liquid_print_bitstring(unsigned int _x, unsigned int _n) { unsigned int i; for (i=0; i<_n; i++) printf("%1u", (_x >> (_n-i-1)) & 1); return LIQUID_OK; } // number of ones in a byte unsigned const char liquid_c_ones[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; // number of ones in a byte modulo 2 unsigned const char liquid_c_ones_mod2[256] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; // reverse byte table unsigned const char liquid_reverse_byte_gentab[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff}; // // byte reversal // // slow implementation of byte reversal unsigned char liquid_reverse_byte(unsigned char _x) { unsigned char y = 0x00; unsigned int i; for (i=0; i<8; i++) { y <<= 1; y |= _x & 1; _x >>= 1; } return y; } // reverse integer with 16 bits of data unsigned int liquid_reverse_uint16(unsigned int _x) { return (liquid_reverse_byte_gentab[(_x ) & 0xff] << 8) | (liquid_reverse_byte_gentab[(_x >> 8) & 0xff] ); } // reverse integer with 24 bits of data unsigned int liquid_reverse_uint24(unsigned int _x) { return (liquid_reverse_byte_gentab[(_x ) & 0xff] << 16) | (liquid_reverse_byte_gentab[(_x >> 8) & 0xff] << 8) | (liquid_reverse_byte_gentab[(_x >> 16) & 0xff] ); } // reverse integer with 32 bits of data unsigned int liquid_reverse_uint32(unsigned int _x) { return ((unsigned int)(liquid_reverse_byte_gentab[(_x ) & 0xff]) << 24) | (liquid_reverse_byte_gentab[(_x >> 8) & 0xff] << 16) | (liquid_reverse_byte_gentab[(_x >> 16) & 0xff] << 8) | (liquid_reverse_byte_gentab[(_x >> 24) & 0xff] ); } liquid-dsp-1.7.0/src/utility/src/memory.c000066400000000000000000000031031474751757600203530ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2022 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "liquid.h" // allocate memory and copy from original location // _orig : pointer to original memory array // _num : number of original elements // _size : size of each element void * liquid_malloc_copy(void * _orig, unsigned int _num, unsigned int _size) { void * copy = malloc(_num * _size); memmove(copy, _orig, _num * _size); return copy; } liquid-dsp-1.7.0/src/utility/src/msb_index.c000066400000000000000000000101161474751757600210150ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "liquid.internal.h" // number of leading zeros in a byte // 0 0000 0000 : 8 // 1 0000 0001 : 7 // 2 0000 0010 : 6 // 3 0000 0011 : 6 // 4 0000 0100 : 5 // ... // 126 0111 1110 : 1 // 127 0111 1111 : 1 // 128 1000 0000 : 0 // 129 1000 0001 : 0 // ... // 253 1111 1101 : 0 // 254 1111 1110 : 0 // 255 1111 1111 : 0 unsigned int liquid_c_leading_zeros[256] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // count leading zeros in an integer (like leading_zeros[], but // extending to integer) unsigned int liquid_count_leading_zeros(unsigned int _x) { #if 0 // look for first non-zero byte in _x int i, B, clz=0; for (i=(SIZEOF_INT-1)*8; i>=0; i-=8) { B = (_x >> i) & 0xff; if ( B ) // B != 0 return clz + leading_zeros[B]; else clz += 8; } return (SIZEOF_INT*8); #else return SIZEOF_INT*8 - liquid_msb_index(_x); #endif } // computes the index of the most-significant bit // // Examples: // 0x00000000 : 0 // 0x00000001 : 1 // 0x00000002 : 2 // ... // 0x00010000 : 17 // 0x00020000 : 17 // 0x00040000 : 17 // ... // 0x80000000 : 32 // // 0 0000 0000 : 0 // 1 0000 0001 : 1 // 2 0000 0010 : 2 // 3 0000 0011 : 2 // 4 0000 0100 : 3 // ... // 126 0111 1110 : 7 // 127 0111 1111 : 7 // 128 1000 0000 : 8 // 129 1000 0001 : 8 // ... // 253 1111 1101 : 8 // 254 1111 1110 : 8 // 255 1111 1111 : 8 unsigned int liquid_msb_index(unsigned int _x) { unsigned int bits; #if defined __i386__ || defined __amd64__ || defined __x86_64__ if (!_x) return 0; __asm volatile("bsrl %1,%0\n" : "=r" (bits) : "c" (_x) ); return bits + 1; #elif 0 // slow method; look one bit at a time for (bits = 0; _x != 0 && bits < 32; _x >>= 1, ++bits) ; return bits; #else // look for first non-zero byte unsigned int i, b; bits = 8*SIZEOF_INT; for (i=SIZEOF_INT*8; i>0; i-=8) { b = (_x >> (i-8)) & 0xff; if ( b ) return bits - liquid_c_leading_zeros[b]; else bits -= 8; } return 0; #endif } liquid-dsp-1.7.0/src/utility/src/msb_index.x86.s000066400000000000000000000002651474751757600214650ustar00rootroot00000000000000; Index of most-significant bit .text .globl msb_index msb_index: pushl %ebx pushl %ecx pushl %edx bsrl %eax,%eax popl %edx popl %ecx popl %ebx ret liquid-dsp-1.7.0/src/utility/src/pack_bytes.c000066400000000000000000000266551474751757600212100ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // pack_bytes.c // // Useful byte-packing utilities // #include #include #include "liquid.internal.h" // pack binary array with symbol(s) // _src : source array [size: _n x 1] // _n : input source array length // _k : bit index to write in _src // _b : number of bits in input symbol // _sym_in : input symbol int liquid_pack_array(unsigned char * _src, unsigned int _n, unsigned int _k, unsigned int _b, unsigned char _sym_in) { // validate input if (_k >= 8*_n) return liquid_error(LIQUID_EIRANGE,"liquid_pack_array(), bit index exceeds array length"); if (_b > 8) return liquid_error(LIQUID_EIRANGE,"liquid_pack_array(), symbol size cannot exceed 8 bits"); // find base index unsigned int i0 = _k / 8; // byte index unsigned int b0 = _k - 8*i0; // bit index //printf("base index : %2u, %2u\n", i0, b0); // determine if index spans multiple bytes if (b0 + _b > 8) { // compute number of bits in each symbol unsigned int n0 = 8 - b0; unsigned int n1 = _b - n0; // generate mask for each symbol unsigned char mask_0 = 0xff >> (8-n0); unsigned char mask_1 = (0xff >> (8-n1)) << (8-n1); // shift then mask unsigned char sym_0 = (_sym_in >> n1 ) & mask_0; unsigned char sym_1 = (_sym_in << (8-n1)) & mask_1; // mask and pack first byte _src[i0] &= ~mask_0; // clear relevant bits _src[i0] |= sym_0; // set relevant bits // mask and pack second byte (if not exceeding array size) if (i0 < _n-1) { _src[i0+1] &= ~mask_1; // clear relevant bits _src[i0+1] |= sym_1; // set relevant bits } #if 0 printf(" output symbol spans multiple bytes\n"); printf(" n0 : %u\n", n0); printf(" n1 : %u\n", n1); printf(" mask0 : 0x%.2x\n", mask_0); printf(" mask1 : 0x%.2x\n", mask_1); printf(" sym 0 : 0x%.2x\n", sym_0); printf(" sym 1 : 0x%.2x\n", sym_1); #endif } else { // compute mask unsigned char mask_0 = (0xff >> (8-_b)) << (8-_b-b0); unsigned char sym_0 = (_sym_in << (8-_b-b0)) & mask_0; // shift then mask _src[i0] &= ~mask_0; // clear relevant bits _src[i0] |= sym_0; // set relevant bits #if 0 printf(" _b : %u\n", _b); printf(" b0 : %u\n", b0); printf(" mask : 0x%.2x\n", mask_0); #endif } return LIQUID_OK; } // unpack symbols from binary array // _src : source array [size: _n x 1] // _n : input source array length // _k : bit index to write in _src // _b : number of bits in output symbol // _sym_out : output symbol int liquid_unpack_array(unsigned char * _src, unsigned int _n, unsigned int _k, unsigned int _b, unsigned char * _sym_out) { // validate input if (_k >= 8*_n) return liquid_error(LIQUID_EIRANGE,"liquid_unpack_array(), bit index exceeds array length"); if (_b > 8) return liquid_error(LIQUID_EIRANGE,"liquid_unpack_array(), symbol size cannot exceed 8 bits"); // find base index unsigned int i0 = _k / 8; // byte index unsigned int b0 = _k - 8*i0; // bit index //printf("base index : %2u, %2u\n", i0, b0); // determine if index spans multiple bytes if (b0 + _b > 8) { // compute number of bits in each symbol unsigned int n0 = 8 - b0; unsigned int n1 = _b - n0; // generate mask for each symbol unsigned char mask_0 = 0xff >> (8-n0); unsigned char mask_1 = 0xff >> (8-n1); // shift then mask unsigned char sym_0 = _src[i0] & mask_0; unsigned char sym_1 = (i0==_n-1) ? 0x00 : (_src[i0+1] >> (8-n1)) & mask_1; // concatenate output symbols *_sym_out = (sym_0 << n1) | sym_1; #if 0 printf(" output symbol spans multiple bytes\n"); printf(" n0 : %u\n", n0); printf(" n1 : %u\n", n1); printf(" mask0 : 0x%.2x\n", mask_0); printf(" mask1 : 0x%.2x\n", mask_1); printf(" sym 0 : 0x%.2x\n", sym_0); printf(" sym 1 : 0x%.2x\n", sym_1); #endif } else { // compute mask unsigned char mask_0 = ((1 << _b) - 1); // shift then mask *_sym_out = (_src[i0] >> (8-_b-b0)) & mask_0; #if 0 printf(" _b : %u\n", _b); printf(" b0 : %u\n", b0); printf(" mask : 0x%.2x\n", mask_0); #endif } return LIQUID_OK; } // pack one-bit symbols into bytes (8-bit symbols) // _sym_in : input symbols array [size: _sym_in_len x 1] // _sym_in_len : number of input symbols // _sym_out : output symbols // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_pack_bytes(unsigned char * _sym_in, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_len, unsigned int * _num_written) { div_t d = div(_sym_in_len,8); unsigned int req__sym_out_len = d.quot; req__sym_out_len += ( d.rem > 0 ) ? 1 : 0; if ( _sym_out_len < req__sym_out_len ) return liquid_error(LIQUID_EIMEM,"pack_bytes(), output too short"); unsigned int i; unsigned int N = 0; // number of bytes written to output unsigned char byte = 0; for (i=0; i<_sym_in_len; i++) { byte |= _sym_in[i] & 0x01; if ( (i+1)%8 == 0 ) { _sym_out[N++] = byte; byte = 0; } else { byte <<= 1; } } if ( i%8 != 0 ) _sym_out[N++] = byte >> 1; *_num_written = N; return LIQUID_OK; } // unpack 8-bit symbols (full bytes) into one-bit symbols // _sym_in : input symbols array [size: _sym_in_len x 1] // _sym_in_len : number of input symbols // _sym_out : output symbols array // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_unpack_bytes(unsigned char * _sym_in, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_len, unsigned int * _num_written) { if ( _sym_out_len < 8*_sym_in_len ) return liquid_error(LIQUID_EIMEM,"unpack_bytes(), output too short"); unsigned int i; unsigned int n = 0; unsigned char byte; for (i=0; i<_sym_in_len; i++) { // read input byte byte = _sym_in[i]; // unpack byte into 8 one-bit symbols _sym_out[n++] = (byte >> 7) & 0x01; _sym_out[n++] = (byte >> 6) & 0x01; _sym_out[n++] = (byte >> 5) & 0x01; _sym_out[n++] = (byte >> 4) & 0x01; _sym_out[n++] = (byte >> 3) & 0x01; _sym_out[n++] = (byte >> 2) & 0x01; _sym_out[n++] = (byte >> 1) & 0x01; _sym_out[n++] = byte & 0x01; } *_num_written = n; return LIQUID_OK; } // repack bytes with arbitrary symbol sizes // _sym_in : input symbols array [size: _sym_in_len x 1] // _sym_in_bps : number of bits per input symbol // _sym_in_len : number of input symbols // _sym_out : output symbols array // _sym_out_bps : number of bits per output symbol // _sym_out_len : number of bytes allocated to output symbols array // _num_written : number of output symbols actually written int liquid_repack_bytes(unsigned char * _sym_in, unsigned int _sym_in_bps, unsigned int _sym_in_len, unsigned char * _sym_out, unsigned int _sym_out_bps, unsigned int _sym_out_len, unsigned int * _num_written) { // compute number of output symbols and determine if output array // is sufficiently sized div_t d = div(_sym_in_len*_sym_in_bps,_sym_out_bps); unsigned int req__sym_out_len = d.quot; req__sym_out_len += ( d.rem > 0 ) ? 1 : 0; if ( _sym_out_len < req__sym_out_len ) { return liquid_error(LIQUID_EIMEM, "repack_bytes(), output too short; %u %u-bit symbols cannot be packed into %u %u-bit elements", _sym_in_len, _sym_in_bps, _sym_out_len, _sym_out_bps); } unsigned int i; unsigned char s_in = 0; // input symbol unsigned char s_out = 0; // output symbol // there is probably a more efficient way to do this, but... unsigned int total_bits = _sym_in_len*_sym_in_bps; unsigned int i_in = 0; // input index counter unsigned int i_out = 0; // output index counter unsigned int k=0; // input symbol enable unsigned int n=0; // output symbol enable unsigned int v; // bit mask for (i=0; i> v) & 0x01; //printf("\n b = %d, v = %d, s_in = %d, sym_out = %d", (sym_in >> v) & 0x01, v, s_in, sym_out ); // push output if available if ( n == _sym_out_bps-1 ) { //printf("\n _sym_out[%d] = %d", i_out, sym_out); _sym_out[i_out++] = s_out; s_out = 0; } // update input/output symbol pop/push flags k = (k+1) % _sym_in_bps; n = (n+1) % _sym_out_bps; } // if uneven, push zeros into remaining output symbol if (i_out != req__sym_out_len) { for (i=n; i<_sym_out_bps; i++) s_out <<= 1; _sym_out[i_out++] = s_out; } *_num_written = i_out; return LIQUID_OK; } liquid-dsp-1.7.0/src/utility/src/shift_array.c000066400000000000000000000110071474751757600213600ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // shift_array.c // // byte-wise array shifting // #include #include #include #include "liquid.internal.h" // shift array to the left _b bytes, filling in zeros // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_lshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // shift amount exceeds buffer size; fill with zeros if (_b >= _n) { memset(_src, 0x00, _n*sizeof(unsigned char)); return LIQUID_OK; } // move memory memmove(_src, &_src[_b], (_n-_b)*sizeof(unsigned char)); // fill remaining buffer with zeros memset(&_src[_n-_b], 0x00, _b*sizeof(unsigned char)); return LIQUID_OK; } // shift array to the right _b bytes, filling in zeros // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_rshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // shift amount exceeds buffer size; fill with zeros if (_b >= _n) { memset(_src, 0x00, _n*sizeof(unsigned char)); return LIQUID_OK; } // move memory memmove(&_src[_b], _src, (_n-_b)*sizeof(unsigned char)); // fill remaining buffer with zeros memset(_src, 0x00, _b*sizeof(unsigned char)); return LIQUID_OK; } // circular shift array to the left _n bytes // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_lcircshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_n == 0) return LIQUID_OK; // ensure 0 <= _b < _n _b = _b % _n; // check if less memory is used with rcircshift if (_b > (_n>>1)) return liquid_rcircshift(_src, _n, _n-_b); // allocate memory for temporary array unsigned char * tmp = (unsigned char*) malloc(_b*sizeof(unsigned char)); // copy to temporary array memmove(tmp, _src, _b*sizeof(unsigned char)); // shift left memmove(_src, &_src[_b], (_n-_b)*sizeof(unsigned char)); // copy from temporary array memmove(&_src[_n-_b], tmp, _b*sizeof(unsigned char)); // free temporary array free(tmp); return LIQUID_OK; } // circular shift array to the right _n bytes // _src : source address [size: _n x 1] // _n : input data array size // _b : number of bytes to shift int liquid_rcircshift(unsigned char * _src, unsigned int _n, unsigned int _b) { // validate input if (_n == 0) return LIQUID_OK; // ensure 0 <= _b < _n _b = _b % _n; // check if less memory is used with lcircshift if (_b > (_n>>1)) return liquid_lcircshift(_src, _n, _n-_b); // allocate memory for temporary array unsigned char * tmp = (unsigned char*) malloc(_b*sizeof(unsigned char)); // copy to temporary array memmove(tmp, &_src[_n-_b], _b*sizeof(unsigned char)); // shift right memmove(&_src[_b], _src, (_n-_b)*sizeof(unsigned char)); // copy from temporary array memmove(_src, tmp, _b*sizeof(unsigned char)); // free temporary array free(tmp); return LIQUID_OK; } liquid-dsp-1.7.0/src/utility/src/utility.c000066400000000000000000000042131474751757600205510ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2020 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // utility.c // // Useful generic utilities // #include #include #include #include "liquid.h" // get scale for constant, particularly for plotting purposes // _val : input value (e.g. 100e6) // _unit : output unit character (e.g. 'M') // _scale : output scale (e.g. 1e-6) int liquid_get_scale(float _val, char * _unit, float * _scale) { float v = fabsf(_val); if (v < 1e-9) { *_scale = 1e12; *_unit = 'p'; } else if (v < 1e-6) { *_scale = 1e9 ; *_unit = 'n'; } else if (v < 1e-3) { *_scale = 1e6 ; *_unit = 'u'; } else if (v < 1e+0) { *_scale = 1e3 ; *_unit = 'm'; } else if (v < 1e3) { *_scale = 1e0 ; *_unit = ' '; } else if (v < 1e6) { *_scale = 1e-3; *_unit = 'k'; } else if (v < 1e9) { *_scale = 1e-6; *_unit = 'M'; } else if (v < 1e12) { *_scale = 1e-9; *_unit = 'G'; } else if (v < 1e15) { *_scale = 1e-12; *_unit = 'T'; } else { *_scale = 1e-15; *_unit = 'P'; } return LIQUID_OK; } liquid-dsp-1.7.0/src/utility/tests/000077500000000000000000000000001474751757600172555ustar00rootroot00000000000000liquid-dsp-1.7.0/src/utility/tests/bdotprod_gentest.m000066400000000000000000000005021474751757600227760ustar00rootroot00000000000000 clear all; close all; a = floor(rand(1) * 2^16); b = floor(rand(1) * 2^16); as = dec2bin(a,16); bs = dec2bin(b,16); ap = []; bp = []; for i=1:16, ap = [ap str2num(as(i))]; bp = [bp str2num(bs(i))]; end; bit = mod(sum(ap.*bp),2); printf('CONTEND_EQUALITY( liquid_bdotprod(0x%.4x, 0x%.4x), %1u);\n', a,b,bit); liquid-dsp-1.7.0/src/utility/tests/bshift_array_autotest.c000066400000000000000000000217111474751757600240300ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST : lbshift // void autotest_lbshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 0000 0011 1101 1110 1011 1111 0101 0100 // output [2] : 0000 0111 1011 1101 0111 1110 1010 1000 // output [3] : 0000 1111 0111 1010 1111 1101 0101 0000 // output [4] : 0001 1110 1111 0101 1111 1010 1010 0000 // output [5] : 0011 1101 1110 1011 1111 0101 0100 0000 // output [6] : 0111 1011 1101 0111 1110 1010 1000 0000 // output [7] : 1111 0111 1010 1111 1101 0101 0000 0000 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0x03, 0xDE, 0xBF, 0x54}; unsigned char output_test_2[4] = {0x07, 0xBD, 0x7E, 0xA8}; unsigned char output_test_3[4] = {0x0F, 0x7A, 0xFD, 0x50}; unsigned char output_test_4[4] = {0x1E, 0xF5, 0xFA, 0xA0}; unsigned char output_test_5[4] = {0x3D, 0xEB, 0xF5, 0x40}; unsigned char output_test_6[4] = {0x7B, 0xD7, 0xEA, 0x80}; unsigned char output_test_7[4] = {0xF7, 0xAF, 0xD5, 0x00}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<8; i++) { memmove(output, input, 4); liquid_lbshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; case 5: CONTEND_SAME_DATA( output, output_test_5, 4 ); break; case 6: CONTEND_SAME_DATA( output, output_test_6, 4 ); break; case 7: CONTEND_SAME_DATA( output, output_test_7, 4 ); break; default:; } } } // // AUTOTEST : rbshift // void autotest_rbshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 0100 0000 1111 0111 1010 1111 1101 0101 // output [2] : 0010 0000 0111 1011 1101 0111 1110 1010 // output [3] : 0001 0000 0011 1101 1110 1011 1111 0101 // output [4] : 0000 1000 0001 1110 1111 0101 1111 1010 // output [5] : 0000 0100 0000 1111 0111 1010 1111 1101 // output [6] : 0000 0010 0000 0111 1011 1101 0111 1110 // output [7] : 0000 0001 0000 0011 1101 1110 1011 1111 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0x40, 0xF7, 0xAF, 0xD5}; unsigned char output_test_2[4] = {0x20, 0x7B, 0xD7, 0xEA}; unsigned char output_test_3[4] = {0x10, 0x3D, 0xEB, 0xF5}; unsigned char output_test_4[4] = {0x08, 0x1E, 0xF5, 0xFA}; unsigned char output_test_5[4] = {0x04, 0x0F, 0x7A, 0xFD}; unsigned char output_test_6[4] = {0x02, 0x07, 0xBD, 0x7E}; unsigned char output_test_7[4] = {0x01, 0x03, 0xDE, 0xBF}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<8; i++) { memmove(output, input, 4); liquid_rbshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; case 5: CONTEND_SAME_DATA( output, output_test_5, 4 ); break; case 6: CONTEND_SAME_DATA( output, output_test_6, 4 ); break; case 7: CONTEND_SAME_DATA( output, output_test_7, 4 ); break; default:; } } } // // AUTOTEST : lbcircshift // void autotest_lbcircshift() { // input : 1001 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1001 0001 1110 1111 0101 1111 1010 1010 // output [1] : 0010 0011 1101 1110 1011 1111 0101 0101 // output [2] : 0100 0111 1011 1101 0111 1110 1010 1010 // output [3] : 1000 1111 0111 1010 1111 1101 0101 0100 // output [4] : 0001 1110 1111 0101 1111 1010 1010 1001 // output [5] : 0011 1101 1110 1011 1111 0101 0101 0010 // output [6] : 0111 1011 1101 0111 1110 1010 1010 0100 // output [7] : 1111 0111 1010 1111 1101 0101 0100 1000 unsigned char input[4] = {0x91, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x91, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0x23, 0xDE, 0xBF, 0x55}; unsigned char output_test_2[4] = {0x47, 0xBD, 0x7E, 0xAA}; unsigned char output_test_3[4] = {0x8F, 0x7A, 0xFD, 0x54}; unsigned char output_test_4[4] = {0x1E, 0xF5, 0xFA, 0xA9}; unsigned char output_test_5[4] = {0x3D, 0xEB, 0xF5, 0x52}; unsigned char output_test_6[4] = {0x7B, 0xD7, 0xEA, 0xA4}; unsigned char output_test_7[4] = {0xF7, 0xAF, 0xD5, 0x48}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<8; i++) { memmove(output, input, 4); liquid_lbcircshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; case 5: CONTEND_SAME_DATA( output, output_test_5, 4 ); break; case 6: CONTEND_SAME_DATA( output, output_test_6, 4 ); break; case 7: CONTEND_SAME_DATA( output, output_test_7, 4 ); break; default:; } } } // // AUTOTEST : rbcircshift // void autotest_rbcircshift() { // input : 1001 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1001 0001 1110 1111 0101 1111 1010 1010 // output [1] : 0100 1000 1111 0111 1010 1111 1101 0101 // output [2] : 1010 0100 0111 1011 1101 0111 1110 1010 // output [3] : 0101 0010 0011 1101 1110 1011 1111 0101 // output [4] : 1010 1001 0001 1110 1111 0101 1111 1010 // output [5] : 0101 0100 1000 1111 0111 1010 1111 1101 // output [6] : 1010 1010 0100 0111 1011 1101 0111 1110 // output [7] : 0101 0101 0010 0011 1101 1110 1011 1111 unsigned char input[4] = {0x91, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x91, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0x48, 0xF7, 0xAF, 0xD5}; unsigned char output_test_2[4] = {0xA4, 0x7B, 0xD7, 0xEA}; unsigned char output_test_3[4] = {0x52, 0x3D, 0xEB, 0xF5}; unsigned char output_test_4[4] = {0xA9, 0x1E, 0xF5, 0xFA}; unsigned char output_test_5[4] = {0x54, 0x8F, 0x7A, 0xFD}; unsigned char output_test_6[4] = {0xAA, 0x47, 0xBD, 0x7E}; unsigned char output_test_7[4] = {0x55, 0x23, 0xDE, 0xBF}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<8; i++) { memmove(output, input, 4); liquid_rbcircshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; case 5: CONTEND_SAME_DATA( output, output_test_5, 4 ); break; case 6: CONTEND_SAME_DATA( output, output_test_6, 4 ); break; case 7: CONTEND_SAME_DATA( output, output_test_7, 4 ); break; default:; } } } liquid-dsp-1.7.0/src/utility/tests/count_bits_autotest.c000066400000000000000000000201151474751757600235210ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST: count number of ones in an integer // void autotest_count_ones() { CONTEND_EQUALITY( liquid_count_ones(0x0000), 0 ); CONTEND_EQUALITY( liquid_count_ones(0x0001), 1 ); CONTEND_EQUALITY( liquid_count_ones(0x0003), 2 ); CONTEND_EQUALITY( liquid_count_ones(0xFFFF), 16 ); CONTEND_EQUALITY( liquid_count_ones(0x00FF), 8 ); CONTEND_EQUALITY( liquid_count_ones(0x5555), 8 ); CONTEND_EQUALITY( liquid_count_ones(0x0007), 3 ); CONTEND_EQUALITY( liquid_count_ones(0x0037), 5 ); CONTEND_EQUALITY( liquid_count_ones(0x0137), 6 ); CONTEND_EQUALITY( liquid_count_ones(0xf137), 10 ); } // // AUTOTEST: count number of ones in an integer (modulo 2) // void autotest_count_ones_mod2() { CONTEND_EQUALITY( liquid_count_ones_mod2(0x0000), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x0001), 1 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x0003), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0xFFFF), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x00FF), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x5555), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x0007), 1 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x0037), 1 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0x0137), 0 ); CONTEND_EQUALITY( liquid_count_ones_mod2(0xf137), 0 ); } // // AUTOTEST: binary dot product // void autotest_bdotprod() { // simple checks CONTEND_EQUALITY( liquid_bdotprod(0x1111,0x1111), 0 ); CONTEND_EQUALITY( liquid_bdotprod(0xffff,0xffff), 0 ); CONTEND_EQUALITY( liquid_bdotprod(0xffff,0x0000), 0 ); CONTEND_EQUALITY( liquid_bdotprod(0x0001,0x0001), 1 ); // random data CONTEND_EQUALITY( liquid_bdotprod(0x4379, 0xf2dc), 1); CONTEND_EQUALITY( liquid_bdotprod(0xc9a1, 0xc99d), 0); CONTEND_EQUALITY( liquid_bdotprod(0xa8ba, 0x26d9), 0); CONTEND_EQUALITY( liquid_bdotprod(0x5235, 0x8e1b), 1); CONTEND_EQUALITY( liquid_bdotprod(0x0f85, 0xa3d1), 0); CONTEND_EQUALITY( liquid_bdotprod(0x23e0, 0x5869), 0); CONTEND_EQUALITY( liquid_bdotprod(0xc8a4, 0x32a4), 1); CONTEND_EQUALITY( liquid_bdotprod(0xe1c3, 0x000c), 0); CONTEND_EQUALITY( liquid_bdotprod(0x4039, 0x192d), 1); CONTEND_EQUALITY( liquid_bdotprod(0x2e1c, 0x55a3), 1); CONTEND_EQUALITY( liquid_bdotprod(0x5a1b, 0x0241), 0); CONTEND_EQUALITY( liquid_bdotprod(0x440c, 0x7ddb), 1); CONTEND_EQUALITY( liquid_bdotprod(0xd2e2, 0x5c98), 1); CONTEND_EQUALITY( liquid_bdotprod(0xe36c, 0x5bc9), 1); CONTEND_EQUALITY( liquid_bdotprod(0xaa96, 0xf233), 1); CONTEND_EQUALITY( liquid_bdotprod(0xab0f, 0x3912), 0); } // // AUTOTEST: count number of leading zeros in an integer // void autotest_count_leading_zeros() { // NOTE: this tests assumes a 4-byte integer CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000000), 32 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000001), 31 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000002), 30 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000004), 29 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000008), 28 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000010), 27 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000020), 26 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000040), 25 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000080), 24 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000100), 23 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000200), 22 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000400), 21 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00000800), 20 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00001000), 19 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00002000), 18 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00004000), 17 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00008000), 16 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00010000), 15 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00020000), 14 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00040000), 13 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00080000), 12 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00100000), 11 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00200000), 10 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00400000), 9 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x00800000), 8 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x01000000), 7 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x02000000), 6 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x04000000), 5 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x08000000), 4 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x10000000), 3 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x20000000), 2 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x40000000), 1 ); CONTEND_EQUALITY( liquid_count_leading_zeros(0x80000000), 0 ); } // // AUTOTEST: find location of most-significant bit // void autotest_msb_index() { // NOTE: this tests assumes a 4-byte integer CONTEND_EQUALITY( liquid_msb_index(0x00000000), 0 ); CONTEND_EQUALITY( liquid_msb_index(0x00000001), 1 ); CONTEND_EQUALITY( liquid_msb_index(0x00000002), 2 ); CONTEND_EQUALITY( liquid_msb_index(0x00000004), 3 ); CONTEND_EQUALITY( liquid_msb_index(0x00000008), 4 ); CONTEND_EQUALITY( liquid_msb_index(0x00000010), 5 ); CONTEND_EQUALITY( liquid_msb_index(0x00000020), 6 ); CONTEND_EQUALITY( liquid_msb_index(0x00000040), 7 ); CONTEND_EQUALITY( liquid_msb_index(0x00000080), 8 ); CONTEND_EQUALITY( liquid_msb_index(0x00000100), 9 ); CONTEND_EQUALITY( liquid_msb_index(0x00000200), 10 ); CONTEND_EQUALITY( liquid_msb_index(0x00000400), 11 ); CONTEND_EQUALITY( liquid_msb_index(0x00000800), 12 ); CONTEND_EQUALITY( liquid_msb_index(0x00001000), 13 ); CONTEND_EQUALITY( liquid_msb_index(0x00002000), 14 ); CONTEND_EQUALITY( liquid_msb_index(0x00004000), 15 ); CONTEND_EQUALITY( liquid_msb_index(0x00008000), 16 ); CONTEND_EQUALITY( liquid_msb_index(0x00010000), 17 ); CONTEND_EQUALITY( liquid_msb_index(0x00020000), 18 ); CONTEND_EQUALITY( liquid_msb_index(0x00040000), 19 ); CONTEND_EQUALITY( liquid_msb_index(0x00080000), 20 ); CONTEND_EQUALITY( liquid_msb_index(0x00100000), 21 ); CONTEND_EQUALITY( liquid_msb_index(0x00200000), 22 ); CONTEND_EQUALITY( liquid_msb_index(0x00400000), 23 ); CONTEND_EQUALITY( liquid_msb_index(0x00800000), 24 ); CONTEND_EQUALITY( liquid_msb_index(0x01000000), 25 ); CONTEND_EQUALITY( liquid_msb_index(0x02000000), 26 ); CONTEND_EQUALITY( liquid_msb_index(0x04000000), 27 ); CONTEND_EQUALITY( liquid_msb_index(0x08000000), 28 ); CONTEND_EQUALITY( liquid_msb_index(0x10000000), 29 ); CONTEND_EQUALITY( liquid_msb_index(0x20000000), 30 ); CONTEND_EQUALITY( liquid_msb_index(0x40000000), 31 ); CONTEND_EQUALITY( liquid_msb_index(0x80000000), 32 ); } liquid-dsp-1.7.0/src/utility/tests/pack_bytes_autotest.c000066400000000000000000000172601474751757600235030ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST : pack_array // void autotest_pack_array() { // input symbols unsigned int sym_size[9] = {8, 2, 3, 6, 1, 3, 3, 4, 3}; unsigned char input[9] = { 0x81, // 1000 0001 0x03, // 11 0x05, // 101 0x3a, // 11 1010 0x01, // 1 0x07, // 111 0x06, // 110 0x0a, // 1010 0x04 // 10[0] <- last bit is stripped }; // output : 1000 0001 1110 1111 0101 1111 1010 1010 // symbol : 0000 0000 1122 2333 3334 5556 6677 7788 unsigned char output_test[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output[4] = {0xff, 0xff, 0xff, 0xff}; unsigned int k=0; unsigned int i; for (i=0; i<9; i++) { liquid_pack_array(output, 4, k, sym_size[i], input[i]); k += sym_size[i]; } CONTEND_SAME_DATA( output, output_test, 4 ); } // // AUTOTEST : unpack_array // void autotest_unpack_array() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // symbol : 0000 0000 1122 2333 3334 5556 6677 7788 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned int sym_size[9] = {8, 2, 3, 6, 1, 3, 3, 4, 3}; // output syms unsigned char output_test[9] = { 0x81, // 1000 0001 0x03, // 11 0x05, // 101 0x3a, // 11 1010 0x01, // 1 0x07, // 111 0x06, // 110 0x0a, // 1010 0x04 // 10[0] <- last bit is implied }; unsigned char output[9]; unsigned int k=0; unsigned int i; for (i=0; i<9; i++) { liquid_unpack_array(input, 4, k, sym_size[i], &output[i]); k += sym_size[i]; } CONTEND_SAME_DATA( output, output_test, 9 ); } // // AUTOTEST : unpack/pack_array // void autotest_repack_array() { unsigned int n=512; // input/output array size unsigned char src[n]; // original data array unsigned char dst[n]; // repacked data array unsigned int i; // initialize input/output arrays for (i=0; i #include "autotest/autotest.h" #include "liquid.internal.h" // // AUTOTEST : lshift // void autotest_lshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 1110 1111 0101 1111 1010 1010 0000 0000 // output [2] : 0101 1111 1010 1010 0000 0000 0000 0000 // output [3] : 1010 1010 0000 0000 0000 0000 0000 0000 // output [4] : 0000 0000 0000 0000 0000 0000 0000 0000 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0xEF, 0x5F, 0xAA, 0x00}; unsigned char output_test_2[4] = {0x5F, 0xAA, 0x00, 0x00}; unsigned char output_test_3[4] = {0xAA, 0x00, 0x00, 0x00}; unsigned char output_test_4[4] = {0x00, 0x00, 0x00, 0x00}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<5; i++) { memmove(output, input, 4); liquid_lshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; default:; } } } // // AUTOTEST : rshift // void autotest_rshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 0000 0000 1000 0001 1110 1111 0101 1111 // output [2] : 0000 0000 0000 0000 1000 0001 1110 1111 // output [3] : 0000 0000 0000 0000 0000 0000 1000 0001 // output [4] : 0000 0000 0000 0000 0000 0000 0000 0000 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0x00, 0x81, 0xEF, 0x5F}; unsigned char output_test_2[4] = {0x00, 0x00, 0x81, 0xEF}; unsigned char output_test_3[4] = {0x00, 0x00, 0x00, 0x81}; unsigned char output_test_4[4] = {0x00, 0x00, 0x00, 0x00}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<5; i++) { memmove(output, input, 4); liquid_rshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; default:; } } } // // AUTOTEST : lcircshift // void autotest_lcircshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 1110 1111 0101 1111 1010 1010 1000 0001 // output [2] : 0101 1111 1010 1010 1000 0001 1110 1111 // output [3] : 1010 1010 1000 0001 1110 1111 0101 1111 // output [4] : 1000 0001 1110 1111 0101 1111 1010 1010 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0xEF, 0x5F, 0xAA, 0x81}; unsigned char output_test_2[4] = {0x5F, 0xAA, 0x81, 0xEF}; unsigned char output_test_3[4] = {0xAA, 0x81, 0xEF, 0x5F}; unsigned char output_test_4[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<5; i++) { memmove(output, input, 4); liquid_lcircshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; default:; } } } // // AUTOTEST : rcircshift // void autotest_rcircshift() { // input : 1000 0001 1110 1111 0101 1111 1010 1010 // output [0] : 1000 0001 1110 1111 0101 1111 1010 1010 // output [1] : 1010 1010 1000 0001 1110 1111 0101 1111 // output [2] : 0101 1111 1010 1010 1000 0001 1110 1111 // output [3] : 1110 1111 0101 1111 1010 1010 1000 0001 // output [4] : 1000 0001 1110 1111 0101 1111 1010 1010 unsigned char input[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_0[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output_test_1[4] = {0xAA, 0x81, 0xEF, 0x5F}; unsigned char output_test_2[4] = {0x5F, 0xAA, 0x81, 0xEF}; unsigned char output_test_3[4] = {0xEF, 0x5F, 0xAA, 0x81}; unsigned char output_test_4[4] = {0x81, 0xEF, 0x5F, 0xAA}; unsigned char output[4]; // // run tests // unsigned int i; for (i=0; i<5; i++) { memmove(output, input, 4); liquid_rcircshift( output, 4, i); switch (i) { case 0: CONTEND_SAME_DATA( output, output_test_0, 4 ); break; case 1: CONTEND_SAME_DATA( output, output_test_1, 4 ); break; case 2: CONTEND_SAME_DATA( output, output_test_2, 4 ); break; case 3: CONTEND_SAME_DATA( output, output_test_3, 4 ); break; case 4: CONTEND_SAME_DATA( output, output_test_4, 4 ); break; default:; } } } liquid-dsp-1.7.0/src/vector/000077500000000000000000000000001474751757600157125ustar00rootroot00000000000000liquid-dsp-1.7.0/src/vector/src/000077500000000000000000000000001474751757600165015ustar00rootroot00000000000000liquid-dsp-1.7.0/src/vector/src/vector_add.proto.c000066400000000000000000000051501474751757600221220ustar00rootroot00000000000000/* * Copyright (c) 2007 - 2015 Joseph Gaeddert * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ // // Generic vector addition // #include #include #include // basic vector addition, unrolling loop // _x : first array [size: _n x 1] // _y : second array [size: _n x 1] // _n : array lengths // _z : output array pointer [size: _n x 1] void VECTOR(_add)(T * _x, T * _y, unsigned int _n, T * _z) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i #include #include // basic vector multiplication, unrolling loop // _x : first array [size: _n x 1] // _y : second array [size: _n x 1] // _n : array lengths // _z : output array pointer [size: _n x 1] void VECTOR(_mul)(T * _x, T * _y, unsigned int _n, T * _z) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i #include #include #include // compute l2-norm on vector // _x : input array [size: _n x 1] // _n : array length TP VECTOR(_norm)(T * _x, unsigned int _n) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // initialize accumulator TP norm = 0; // compute in groups of 4 // TODO: use generic 'real' and 'conj' functions unsigned int i; for (i=0; i>2)<<2; // scale by inverse; compute in groups of 4 unsigned int i; for (i=0; i #include #include #include #include // compute complex phase rotation: x[i] = exp{ j theta[i] } // _theta : input primitive array [size: _n x 1] // _n : array length // _x : output array pointer [size: _n x 1] void VECTOR(_cexpj)(TP * _theta, unsigned int _n, T * _x) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i 0 ? 1.0 : -1.0; _x[i+1] = _theta[i+1] > 0 ? 1.0 : -1.0; _x[i+2] = _theta[i+2] > 0 ? 1.0 : -1.0; _x[i+3] = _theta[i+3] > 0 ? 1.0 : -1.0; #endif } // clean up remaining for ( ; i<_n; i++) { #if T_COMPLEX _x[i] = cexpf(_Complex_I*_theta[i]); #else _x[i] = _theta[i] > 0 ? 1.0 : -1.0; #endif } } // compute complex phase rotation: x[i] = exp{ j theta[i] } // _x : input array [size: _n x 1] // _n : array length // _theta : output primitive array [size: _n x 1] void VECTOR(_carg)(T * _x, unsigned int _n, TP * _theta) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i 0 ? 0 : M_PI; _theta[i+1] = _x[i+1] > 0 ? 0 : M_PI; _theta[i+2] = _x[i+2] > 0 ? 0 : M_PI; _theta[i+3] = _x[i+3] > 0 ? 0 : M_PI; #endif } // clean up remaining for ( ; i<_n; i++) { #if T_COMPLEX _theta[i] = cargf(_x[i]); #else _theta[i] = _x[i] > 0 ? 0 : M_PI; #endif } } // compute absolute value of each element: y[i] = |x[i]| // _x : input array [size: _n x 1] // _n : array length // _y : output primitive array pointer [size: _n x 1] void VECTOR(_abs)(T * _x, unsigned int _n, TP * _y) { // t = 4*(floor(_n/4)) unsigned int t=(_n>>2)<<2; // compute in groups of 4 unsigned int i; for (i=0; i