├── .github └── workflows │ ├── ci-linux-build.yml │ └── ci-windows-build.yml ├── .gitignore ├── LICENSE ├── README.md ├── SDRReceiver.pro ├── ci-linux-build.sh ├── ci-windows-build.sh ├── gnuradio ├── firfilter.cpp └── firfilter.h ├── halfbanddecimator.cpp ├── halfbanddecimator.h ├── jonti ├── dsp.cpp ├── dsp.h ├── fftrwrapper.cpp ├── fftrwrapper.h ├── fftwrapper.cpp ├── fftwrapper.h ├── sdr.cpp └── sdr.h ├── kiss_fft130 ├── CHANGELOG ├── COPYING ├── README ├── TIPS ├── _kiss_fft_guts.h ├── kiss_fastfir.c ├── kiss_fastfir.h ├── kiss_fastfir_complex.c ├── kiss_fastfir_complex.h ├── kiss_fastfir_real.c ├── kiss_fastfir_real.h ├── kiss_fft.c ├── kiss_fft.h ├── kiss_fftr.c └── kiss_fftr.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── oscillator.cpp ├── oscillator.h ├── qcustomplot.cpp ├── qcustomplot.h ├── sample_ini ├── CBAND_143E.ini ├── sdr_25E.ini ├── sdr_54W_288K.ini ├── sdr_54W_all.ini └── sdr_98W.ini ├── sdrj.cpp ├── sdrj.h ├── vfo.cpp ├── vfo.h ├── zmqpublisher.cpp └── zmqpublisher.h /.github/workflows/ci-linux-build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | os: [ubuntu-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | path: SDRReceiver 16 | # install MSYS2 for windows 17 | - name: if windows install MSYS2 18 | if: ${{ matrix.os == 'windows-latest' }} 19 | uses: msys2/setup-msys2@v2 20 | with: 21 | msystem: MINGW64 22 | update: true 23 | install: git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-zeromq mingw-w64-x86_64-libusb zip p7zip unzip 24 | # build for windows 25 | - name: Windows-CI-Build 26 | if: ${{ matrix.os == 'windows-latest' }} 27 | run: | 28 | echo 'Running in MSYS2!' 29 | ./SDRReceiver/ci-windows-build.sh 30 | shell: msys2 {0} 31 | # build for linux 32 | - name: Linux-CI-Build 33 | if: ${{ matrix.os == 'ubuntu-latest' }} 34 | run: | 35 | echo 'Running in bash!' 36 | chmod +x ./SDRReceiver/ci-linux-build.sh 37 | ./SDRReceiver/ci-linux-build.sh 38 | # upload windows artifacts 39 | - name: Upload windows binary artifacts 40 | if: ${{ matrix.os == 'windows-latest' }} 41 | uses: actions/upload-artifact@v2 42 | with: 43 | name: sdrrece_windows_windows 44 | retention-days: 1 45 | path: | 46 | SDRReceiver/SDRReceiver/release/*.zip 47 | # upload linux artifacts 48 | - name: Upload linux binary artifacts 49 | if: ${{ matrix.os == 'ubuntu-latest' }} 50 | uses: actions/upload-artifact@v2 51 | with: 52 | name: sdrreceiver_linux 53 | retention-days: 1 54 | path: | 55 | sdrreceiver/bin/*.tar.gz 56 | release: 57 | needs: build 58 | runs-on: ubuntu-latest 59 | steps: 60 | # download all artifacts for this workflow 61 | - name: Download all workflow artifacts 62 | uses: actions/download-artifact@v2 63 | # Create a release 64 | - name: Create a release 65 | uses: "marvinpinto/action-automatic-releases@latest" 66 | with: 67 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 68 | automatic_release_tag: "latest" 69 | prerelease: true 70 | title: "Development Build" 71 | files: | 72 | sdrreceiver_linux/*.tar.gz 73 | sdrreceiver_windows/*.zip 74 | -------------------------------------------------------------------------------- /.github/workflows/ci-windows-build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | os: [ubuntu-latest, windows-latest] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | path: SDRReceiver 16 | # install MSYS2 for windows 17 | - name: if windows install MSYS2 18 | if: ${{ matrix.os == 'windows-latest' }} 19 | uses: msys2/setup-msys2@v2 20 | with: 21 | msystem: MINGW64 22 | update: false 23 | install: git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-zeromq mingw-w64-x86_64-libusb zip p7zip unzip 24 | # build for windows 25 | - name: Windows-CI-Build 26 | if: ${{ matrix.os == 'windows-latest' }} 27 | run: | 28 | echo 'Running in MSYS2!' 29 | ./SDRReceiver/ci-windows-build.sh 30 | shell: msys2 {0} 31 | # build for linux 32 | - name: Linux-CI-Build 33 | if: ${{ matrix.os == 'ubuntu-latest' }} 34 | run: | 35 | echo 'Running in bash!' 36 | chmod +x ./SDRReceiver/ci-linux-build.sh 37 | ./SDRReceiver/ci-linux-build.sh 38 | # upload windows artifacts 39 | - name: Upload windows binary artifacts 40 | if: ${{ matrix.os == 'windows-latest' }} 41 | uses: actions/upload-artifact@v2 42 | with: 43 | name: sdrreceiver_windows 44 | retention-days: 90 45 | path: | 46 | SDRReceiver/release/*.zip 47 | # upload linux artifacts 48 | - name: Upload linux binary artifacts 49 | if: ${{ matrix.os == 'ubuntu-latest' }} 50 | uses: actions/upload-artifact@v2 51 | with: 52 | name: sdrreceiver_linux 53 | retention-days: 90 54 | path: | 55 | ./SDRReceiver/bin/*.tar.gz 56 | release: 57 | needs: build 58 | runs-on: ubuntu-latest 59 | steps: 60 | # download all artifacts for this workflow 61 | - name: Download all workflow artifacts 62 | uses: actions/download-artifact@v2 63 | # Create a release 64 | - name: Create a release 65 | uses: "marvinpinto/action-automatic-releases@latest" 66 | with: 67 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 68 | automatic_release_tag: "latest" 69 | prerelease: true 70 | title: "Development Build" 71 | files: | 72 | sdrreceiver_linux/*.tar.gz 73 | sdrreceiver_windows/*.zip 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | .qmake.cache 36 | .qmake.stash 37 | 38 | #ignore build directories and artifacts 39 | /SDRReceiver_*/ 40 | /*.deb 41 | /bin/ 42 | /control 43 | moc_*.h 44 | /SDRReceiver 45 | /release/ 46 | 47 | # qtcreator generated files 48 | *.pro.user* 49 | 50 | # xemacs temporary files 51 | *.flc 52 | 53 | # Vim temporary files 54 | .*.swp 55 | 56 | # Visual Studio generated files 57 | *.ib_pdb_index 58 | *.idb 59 | *.ilk 60 | *.pdb 61 | *.sln 62 | *.suo 63 | *.vcproj 64 | *vcproj.*.*.user 65 | *.ncb 66 | *.sdf 67 | *.opensdf 68 | *.vcxproj 69 | *vcxproj.* 70 | 71 | # MinGW generated files 72 | *.Debug 73 | *.Release 74 | 75 | # Python byte code 76 | *.pyc 77 | 78 | # Binaries 79 | # -------- 80 | *.dll 81 | *.exe 82 | 83 | # other 84 | test_output/* 85 | build-*/ 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jeroen Beijer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project contains a basic SDR Receiver which feeds JAERO with audio from an R820T2 RTL2832U device like the RTL SDR V3. Rather than feeding JAERO with audio via audio cables, this implementation makes use of ZeroMQ as the interface between the SDR and JAERO. This provides a more stable data flow which is significanty less prone to CRC errors in JAERO. 2 | 3 | In addition, the aim of the project is to run at low CPU usage without any bells or whistles. The GUI is very simple and has only basic features to select the RTL device, start the SDR as well as enable or disable the device bias tee. The FFT is purposely slow to reduce CPU usage. You can select individual VFO's in the dropdown menu which should display the approximate spectrum shown in JAERO. 4 | 5 | All settings are made in an ini file. A few examples ini files are included in the project. Further details on the options in the ini file are to follow but be very careful when editing the file, any mistakes may cause the program not to run correctly. 6 | 7 | Note that this SDR requires a JAERO instance of version 1.0.4.13 or higher which has the ZeroMQ audio source options included. 8 | 9 | ![image](https://user-images.githubusercontent.com/31091871/126459963-0726ea9d-3d03-40b8-ae90-45676c3c21b1.png) 10 | 11 | Inmarsat AERO channels are more or less grouped in clusters of lower speed channnels (600/1200) and higher speed channels (10500/8400). The SDR takes advantage of this by grouping these in a "main" VFO which allows the whole group to be mixed down and decimated from the original sample rate down to a much lower rate that still covers all of the channels inside the group. Each channel / sub VFO is then mixed / decimated down to the required frequency and sample rate as well as USB demodulated. The resulting data is transmitted to JAERO via a ZeroMQ PUB/SUB pattern (https://zguide.zeromq.org/). This means that it is possible to connect several JAERO instances to the same SDR VFO output. It also allows you to run the SDR on a different device to where JAERO is running, provided there is network connectivity between the two. The SDR is the ZMQ Publisher and binds to the address specficied in the ini file: 12 | 13 | zmq_address=tcp://*:6003 14 | 15 | Each VFO defined in the ini file should have it own Topic name as shown in the below ini file excerpt 16 | 17 | ![image](https://user-images.githubusercontent.com/31091871/126470644-0c8b4030-8096-4c58-80e9-549bec89e0db.png) 18 | 19 | This topic name would then be matched by the settings in JAERO: 20 | 21 | ![image](https://user-images.githubusercontent.com/31091871/126470450-cf25d78e-f123-4878-8ab8-16693719cc22.png) 22 | 23 | The easiest way to start the SDR is by creating a bat or shell script to pass the ini file name argument, i.e. on windows: 24 | 25 | start SDRReceiver.exe -s ini/SDR_25E.ini 26 | 27 | In order to make this work I have re-used some of Jonti's excellent code from his JDSCA project for handling the RTL callback and data handling. I also used some gnuradio project code for FIR coeffecient calculations. 28 | 29 | The main sample rate for the device is set as follows: 30 | 31 | sample_rate=1536000 32 | 33 | However this should probably not be changed. Except for the older I3 satellite at 54W all channels fit nicely with a 1.536.000 sample rate and it can be decimated down to 48Khz entirely with half band FIR filters. In order to cover the data channels and voice channels around 1546.8 for 54W it is also possible to run at 1.920.000 but obviously this takes a little more CPU and has no obvious benefit for the I4 satellites. A more narrow 288.000 sample rate is also available which might be useful on slower devices or if you are only interested in particular channels. 34 | 35 | The center frequency is chosen so that both the lower speed data channels and higher speed channels as well voice channels are covered: 36 | 37 | center_frequency=1545600000 38 | 39 | Other ini file keys: 40 | set the tuner gain, 496 is the highest for R820T2 devices 41 | 42 | tuner_gain=496 43 | 44 | remove the annoying spike in the center of the spectrum 45 | correct_dc_bias=1 46 | 47 | when changing dongles there may be a slight freqency difference. Use this to tune ALL VFO's up or down by a number of Hz. Use positive values to tune higher, negative values to tune lower 48 | 49 | mix_offset=0 50 | 51 | You should be able to connect to remote RTL that is running via rtl_tcp, it will show in the device drop down when enabled 52 | 53 | remote_rtl=127.0.0.1:1234 54 | 55 | Also the tuner gain by index position can be selected with this key where a value of 28 is the highest gain for an RTL SDR V3 56 | 57 | remote_rtl_gain_idx=28 58 | 59 | The main VFO's are shown in the image above. There is typically no need to change these unless perhaps while setting up a new C Band ini file. The SDR should work for C Band as well but the FFT is quite slow so it is probabaly a good idea to determine the exact frequencies to use via other means. 60 | 61 | The SDR can be autostarted and with the following ini keys: 62 | 63 | auto_start=1 64 | 65 | auto_start_tuner_idx=0 66 | 67 | The latter key being the zero based index of the RTL device to be started as shown in the device dropdown 68 | 69 | On some VFO you may like to low pass the audio prior to sending to jaero, i.e. for the audio channels a 10Khz audio filter could be useful to limit adjecent channel activity. Use the filter_bandwidth ini setting on the vfo to set this. A value of 0 means no filter, a value of 10000 would set a 10Khz hamming windowed low pass filter. 70 | 71 | You may also need to adjust the gain slightly for your setup. Increase or decrease the VFO gain value until you get a green volume light in jaero 72 | 73 | The decoding results in jaero should be similar to what one would get from other SDR's but it becomes possible to run jaero almost free of CRC errors even at high CPU loads. 74 | 75 | 76 | ![image](https://user-images.githubusercontent.com/31091871/126675321-a9fb3c35-ec5b-4b5b-972d-512ac160d65f.png) 77 | 78 | **Updated 17th October 2021** 79 | 80 | Added two new ini keys to auto start based on device serial: 81 | 82 | auto_start=1 83 | 84 | auto_start_tuner_serial=00000001 85 | 86 | #auto_start_tuner_idx = 87 | 88 | Note that the serial option will be checked first before applying the index based key if present (i.e. if you leave both enabled). if you have multiple devices with the same serial it will take the first one it finds in the list of devices. The serial number now also shows in the device list drop down. 89 | 90 | You can now also auto start the bias t by enabling the following key/setting 91 | 92 | auto_start_biast=1 93 | 94 | Also added a quick radio button to disable to the main FFT. I doubt it saves any significant cpu usage but certainly some. Hopefully I will have time to do a little bit more work on this to also make C Band a little easier. 95 | 96 | 97 | -------------------------------------------------------------------------------- /SDRReceiver.pro: -------------------------------------------------------------------------------- 1 | 2 | DEFINES += SDR_VERSION=\\\"v1.0.1\\\" 3 | 4 | QT += core gui network 5 | 6 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport 7 | 8 | TARGET = SDRReceiver 9 | TEMPLATE = app 10 | 11 | INSTALL_PATH = /opt/sdrreceiver 12 | 13 | CONFIG += c++11 14 | 15 | # The following define makes your compiler emit warnings if you use 16 | # any Qt feature that has been marked deprecated (the exact warnings 17 | # depend on your compiler). Please consult the documentation of the 18 | # deprecated API in order to know how to port your code away from it. 19 | DEFINES += QT_DEPRECATED_WARNINGS 20 | 21 | # You can also make your code fail to compile if it uses deprecated APIs. 22 | # In order to do so, uncomment the following line. 23 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 24 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 25 | 26 | SOURCES += \ 27 | jonti/dsp.cpp \ 28 | jonti/fftwrapper.cpp \ 29 | jonti/fftrwrapper.cpp \ 30 | gnuradio//firfilter.cpp \ 31 | halfbanddecimator.cpp \ 32 | kiss_fft130/kiss_fastfir.c \ 33 | kiss_fft130/kiss_fastfir_complex.c \ 34 | kiss_fft130/kiss_fastfir_real.c \ 35 | kiss_fft130/kiss_fft.c \ 36 | kiss_fft130/kiss_fftr.c \ 37 | main.cpp \ 38 | oscillator.cpp \ 39 | qcustomplot.cpp \ 40 | mainwindow.cpp \ 41 | jonti/sdr.cpp \ 42 | sdrj.cpp \ 43 | vfo.cpp \ 44 | zmqpublisher.cpp 45 | 46 | HEADERS += \ 47 | jonti/dsp.h \ 48 | jonti/fftrwrapper.h \ 49 | jonti/fftwrapper.h \ 50 | gnuradio/firfilter.h \ 51 | halfbanddecimator.h \ 52 | kiss_fft130/_kiss_fft_guts.h \ 53 | kiss_fft130/kiss_fastfir.h \ 54 | kiss_fft130/kiss_fastfir_complex.h \ 55 | kiss_fft130/kiss_fastfir_real.h \ 56 | kiss_fft130/kiss_fft.h \ 57 | kiss_fft130/kiss_fftr.h \ 58 | oscillator.h \ 59 | qcustomplot.h \ 60 | mainwindow.h \ 61 | jonti/sdr.h \ 62 | sdrj.h \ 63 | vfo.h \ 64 | zmqpublisher.h 65 | 66 | FORMS += \ 67 | mainwindow.ui 68 | 69 | # Default rules for deployment. 70 | qnx: target.path = /tmp/$${TARGET}/bin 71 | else: unix:!android: target.path = /opt/$${TARGET}/bin 72 | !isEmpty(target.path): INSTALLS += target 73 | 74 | QMAKE_CXXFLAGS_RELEASE -= -O2 75 | QMAKE_CXXFLAGS_RELEASE += -Ofast 76 | 77 | 78 | win32 { 79 | #message("windows") 80 | LIBS += -llibzmq -llibrtlsdr.dll 81 | } else { 82 | #message("not windows") 83 | LIBS += -lzmq -lrtlsdr 84 | } 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /ci-linux-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #The MIT License (MIT) 4 | 5 | #Copyright (c) 2015-2019 Jonathan Olds 6 | 7 | #Permission is hereby granted, free of charge, to any person obtaining a copy 8 | #of this software and associated documentation files (the "Software"), to deal 9 | #in the Software without restriction, including without limitation the rights 10 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | #copies of the Software, and to permit persons to whom the Software is 12 | #furnished to do so, subject to the following conditions: 13 | 14 | #The above copyright notice and this permission notice shall be included in all 15 | #copies or substantial portions of the Software. 16 | 17 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | #SOFTWARE. 24 | 25 | #linux build (for github "ubuntu-latest") 26 | 27 | 28 | #fail on first error 29 | set -e 30 | 31 | #we will need sudo later may as well do a sudo now 32 | if [[ ! $(sudo echo 0) ]]; then exit; fi 33 | 34 | #install dependancies and build tools 35 | sudo apt-get update 36 | sudo apt-get install qt5-default cpputest build-essential qtmultimedia5-dev cmake libvorbis-dev libogg-dev libqt5multimedia5-plugins checkinstall libqcustomplot-dev libqt5svg5-dev libzmq3-dev librtlsdr-dev libusb-dev -y 37 | 38 | #get script path 39 | SCRIPT=$(realpath $0) 40 | SCRIPTPATH=$(dirname $SCRIPT) 41 | 42 | #SDRReceiver 43 | cd $SCRIPTPATH 44 | #needed for github actions 45 | git fetch --prune --unshallow --tags || true 46 | git status > /dev/null 2>&1 47 | PACKAGE_VERSION=1.0 48 | PACKAGE_NAME=SDRReceiver 49 | MAINTAINER=https://github.com/jeroenbeijer 50 | PACKAGE_SOURCE=https://github.com/jeroenbeijer/SDRReceiver 51 | echo "PACKAGE_NAME="$PACKAGE_NAME 52 | echo "PACKAGE_VERSION="$PACKAGE_VERSION 53 | echo "MAINTAINER="$MAINTAINER 54 | echo "PACKAGE_SOURCE="$PACKAGE_SOURCE 55 | 56 | #build for release 57 | #cd SDRReceiver 58 | qmake CONFIG-="CI" 59 | make 60 | make INSTALL_ROOT=$PWD/${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1 install 61 | SDR_INSTALL_PATH=$(cat SDRReceiver.pro | sed -n -e 's/^INSTALL_PATH[|( ).]= //p') 62 | SDR_INSTALL_PATH=${SDR_INSTALL_PATH//$'\r'/} 63 | echo 'SDR_INSTALL_PATH='${SDR_INSTALL_PATH} 64 | 65 | #add control 66 | cat < control 67 | Package: ${PACKAGE_NAME} 68 | Source: ${PACKAGE_SOURCE} 69 | Section: base 70 | Priority: extra 71 | Depends: qt5-default (>= 5.11), qtmultimedia5-dev, libvorbis-dev, libogg-dev, libqt5multimedia5-plugins, libqcustomplot-dev, libqt5svg5-dev, libzmq3-dev, libusb-dev, librtlsdr-dev 72 | Provides: ${PACKAGE_NAME} 73 | Maintainer: ${MAINTAINER} 74 | Version: ${PACKAGE_VERSION%_*} 75 | License: MIT 76 | Architecture: $(dpkg --print-architecture) 77 | Description: SDR Receiver for JAERO 78 | EOT 79 | echo "" >> control 80 | mkdir -p ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1/DEBIAN 81 | cp control ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1/DEBIAN 82 | #add path command 83 | mkdir -p ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1/usr/local/bin 84 | cat < ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1/usr/local/bin/SDRReceiver 85 | #!/bin/bash 86 | /opt/SDRReceiver/bin/SDRReceiver "\$@" 87 | EOT 88 | chmod +x ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1/usr/local/bin/SDRReceiver 89 | 90 | #build and install package 91 | dpkg-deb --build ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1 92 | sudo apt install --reinstall ./${PACKAGE_NAME}*.deb -y 93 | sudo ldconfig 94 | cd .. 95 | 96 | #package 97 | mkdir SDRReceiver/bin 98 | mkdir SDRReceiver/bin/SDRReceiver 99 | cp SDRReceiver/*.deb SDRReceiver/bin/SDRReceiver 100 | cd SDRReceiver/bin 101 | cat < SDRReceiver/install.sh 102 | #!/bin/bash 103 | #installs built packages 104 | sudo apt install ./*.deb 105 | sudo ldconfig 106 | EOT 107 | chmod +x SDRReceiver/install.sh 108 | cat < SDRReceiver/uninstall.sh 109 | #!/bin/bash 110 | #removes built packages 111 | sudo dpkg --remove libacars-dev libcorrect-dev libaeroambe-dev SDRReceiver libzmq3-dev libusb-dev librtlsdr-dev 112 | sudo ldconfig 113 | EOT 114 | chmod +x SDRReceiver/uninstall.sh 115 | cat < SDRReceiver/readme.md 116 | # SDRReceiver ${PACKAGE_VERSION} 117 | 118 | ### OS: $(lsb_release -d | cut -f 2) 119 | ### Build Date: $(date -u) 120 | 121 | Cheers,
122 | ci-linux-build.sh 123 | EOT 124 | #compress 125 | 126 | tar -czvf ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1_linux_$(uname -m).tar.gz SDRReceiver 127 | echo "done" 128 | -------------------------------------------------------------------------------- /ci-windows-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #The MIT License (MIT) 4 | 5 | #Copyright (c) 2015-2019 Jonathan Olds 6 | 7 | #Permission is hereby granted, free of charge, to any person obtaining a copy 8 | #of this software and associated documentation files (the "Software"), to deal 9 | #in the Software without restriction, including without limitation the rights 10 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | #copies of the Software, and to permit persons to whom the Software is 12 | #furnished to do so, subject to the following conditions: 13 | 14 | #The above copyright notice and this permission notice shall be included in all 15 | #copies or substantial portions of the Software. 16 | 17 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | #SOFTWARE. 24 | 25 | #windows build (for github "windows-latest") 26 | #this is for 64bit mingw and msys2 install. all is done on the command line. 27 | 28 | 29 | #fail on first error 30 | set -e 31 | 32 | pacman -S --needed --noconfirm git mingw-w64-x86_64-toolchain autoconf libtool mingw-w64-x86_64-cpputest mingw-w64-x86_64-qt5 mingw-w64-x86_64-cmake mingw-w64-x86_64-libvorbis zip p7zip unzip mingw-w64-x86_64-zeromq mingw-w64-x86_64-libusb 33 | 34 | #get script path 35 | SCRIPT=$(realpath $0) 36 | SCRIPTPATH=$(dirname $SCRIPT) 37 | cd $SCRIPTPATH/.. 38 | 39 | 40 | #rtl-sdr 41 | FOLDER="rtl-sdr" 42 | URL="https://github.com/osmocom/rtl-sdr" 43 | if [ ! -d "$FOLDER" ] ; then 44 | git clone $URL $FOLDER 45 | cd "$FOLDER" 46 | else 47 | cd "$FOLDER" 48 | git pull $URL 49 | fi 50 | mkdir -p build && cd build 51 | cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX:PATH=/mingw64/ .. 52 | mingw32-make 53 | mingw32-make DESTDIR=/../ install 54 | 55 | #SDRReceiver 56 | cd $SCRIPTPATH 57 | #needed for github actions 58 | git fetch --prune --unshallow --tags || true 59 | git status > /dev/null 2>&1 60 | PACKAGE_VERSION=1.0 61 | PACKAGE_NAME=SDRReceiver 62 | MAINTAINER=https://github.com/jeroenbeijer 63 | PACKAGE_SOURCE=https://github.com/jeroenbeijer/SDRReceiver 64 | echo "PACKAGE_NAME="$PACKAGE_NAME 65 | echo "PACKAGE_VERSION="$PACKAGE_VERSION 66 | echo "MAINTAINER="$MAINTAINER 67 | echo "PACKAGE_SOURCE="$PACKAGE_SOURCE 68 | 69 | qmake 70 | mingw32-make 71 | 72 | #package 73 | mkdir release/sdrreceiver 74 | cp release/SDRReceiver.exe release/SDRReceiver/ 75 | cd release/SDRReceiver 76 | windeployqt.exe --no-translations --force SDRReceiver.exe 77 | cp /mingw64/bin/libstdc++-6.dll $PWD 78 | cp /mingw64/bin/libgcc_s_seh-1.dll $PWD 79 | cp /mingw64/bin/libwinpthread-1.dll $PWD 80 | cp /mingw64/bin/zlib1.dll $PWD 81 | cp /mingw64/bin/Qt5PrintSupport.dll $PWD 82 | cp /mingw64/bin/libdouble-conversion.dll $PWD 83 | cp /mingw64/bin/libicuin69.dll $PWD 84 | cp /mingw64/bin/libicuuc69.dll $PWD 85 | cp /mingw64/bin/libpcre2-16-0.dll $PWD 86 | cp /mingw64/bin/libzstd.dll $PWD 87 | cp /mingw64/bin/libharfbuzz-0.dll $PWD 88 | cp /mingw64/bin/libpng16-16.dll $PWD 89 | cp /mingw64/bin/libfreetype-6.dll $PWD 90 | cp /mingw64/bin/libgraphite2.dll $PWD 91 | cp /mingw64/bin/libglib-2.0-0.dll $PWD 92 | cp /mingw64/bin/libicudt69.dll $PWD 93 | cp /mingw64/bin/libbz2-1.dll $PWD 94 | cp /mingw64/bin/libbrotlidec.dll $PWD 95 | cp /mingw64/bin/libintl-8.dll $PWD 96 | cp /mingw64/bin/libpcre-1.dll $PWD 97 | cp /mingw64/bin/libbrotlicommon.dll $PWD 98 | cp /mingw64/bin/libiconv-2.dll $PWD 99 | cp /mingw64/bin/libzmq.dll $PWD 100 | cp /mingw64/bin/librtlsdr.dll $PWD 101 | cp /mingw64/bin/libsodium-23.dll $PWD 102 | cp /mingw64/bin/libusb-1.0.dll $PWD 103 | cp /mingw64/bin/libmd4c.dll $PWD 104 | #add readme 105 | cat < readme.md 106 | # SDRReceiver ${PACKAGE_VERSION} 107 | 108 | ### OS Name: $(systeminfo | sed -n -e 's/^OS Name://p' | awk '{$1=$1;print}') 109 | ### OS Version: $(systeminfo | sed -n -e 's/^OS Version://p' | awk '{$1=$1;print}') 110 | ### System Type: $(systeminfo | sed -n -e 's/^System Type://p' | awk '{$1=$1;print}') 111 | ### Build Date: $(date -u) 112 | 113 | Cheers,
114 | ci-windows-build.sh 115 | EOT 116 | #compress 117 | cd .. 118 | zip -r ${PACKAGE_NAME}_${PACKAGE_VERSION%_*}-1_win_$(uname -m).zip SDRReceiver 119 | -------------------------------------------------------------------------------- /gnuradio/firfilter.cpp: -------------------------------------------------------------------------------- 1 | /*this code comes from gnuradio which is covered by the GNU GENERAL PUBLIC LICENSE 2 | 3 | https://www.gnu.org/licenses/gpl-3.0.en.html */ 4 | 5 | #include "firfilter.h" 6 | #include 7 | #include "math.h" 8 | 9 | 10 | #ifndef M_PI 11 | #define M_PI 3.14159265358979323846264338327950288 12 | #endif 13 | double firfilter::filter(double in) 14 | { 15 | 16 | 17 | double sum = 0; 18 | int i; 19 | for (i = 0; i < M; i++) 20 | { 21 | xv[i] = xv[i+1]; 22 | 23 | } 24 | xv[M] = in; 25 | sum = 0.0; 26 | for (i = 0; i <= M; i++) 27 | { 28 | sum += (coeffs[i] * xv[i]); 29 | 30 | } 31 | return sum; 32 | 33 | 34 | 35 | } 36 | firfilter::firfilter() 37 | { 38 | 39 | xv.resize(241); 40 | M = 240; 41 | 42 | } 43 | 44 | void firfilter::setTaps(QVector taps) 45 | { 46 | 47 | coeffs.resize(taps.length()); 48 | 49 | for(int a = 0; a firfilter::low_pass(double gain, 65 | double sampling_freq, 66 | double cutoff_freq, // Hz center of transition band 67 | double transition_width, // Hz width of transition band 68 | win_type window_type, 69 | double beta) // used only with Kaiser 70 | { 71 | sanity_check_1f(sampling_freq, cutoff_freq, transition_width); 72 | 73 | int ntaps = compute_ntaps(sampling_freq, transition_width, window_type, beta); 74 | 75 | // construct the truncated ideal impulse response 76 | // [sin(x)/x for the low pass case] 77 | 78 | QVector taps(ntaps); 79 | QVector w = QVector::fromStdVector(window(window_type, ntaps)); 80 | 81 | int M = (ntaps - 1) / 2; 82 | double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; 83 | 84 | for (int n = -M; n <= M; n++) { 85 | if (n == 0) 86 | taps[n + M] = fwT0 / M_PI * w[n + M]; 87 | else { 88 | // a little algebra gets this into the more familiar sin(x)/x form 89 | taps[n + M] = sin(n * fwT0) / (n * M_PI) * w[n + M]; 90 | } 91 | } 92 | 93 | // find the factor to normalize the gain, fmax. 94 | // For low-pass, gain @ zero freq = 1.0 95 | 96 | double fmax = taps[0 + M]; 97 | for (int n = 1; n <= M; n++) 98 | fmax += 2 * taps[n + M]; 99 | 100 | gain /= fmax; // normalize 101 | 102 | for (int i = 0; i < ntaps; i++) 103 | taps[i] *= gain; 104 | 105 | return taps; 106 | } 107 | 108 | int firfilter::compute_ntaps(double sampling_freq, 109 | double transition_width, 110 | win_type window_type, 111 | double beta) 112 | { 113 | double a = max_attenuation(window_type, beta); 114 | int ntaps = (int)(a * sampling_freq / (22.0 * transition_width)); 115 | if ((ntaps & 1) == 0) // if even... 116 | ntaps++; // ...make odd 117 | 118 | return ntaps; 119 | } 120 | 121 | 122 | void firfilter::sanity_check_1f(double sampling_freq, 123 | double fa, // cutoff freq 124 | double transition_width) 125 | { 126 | if (sampling_freq <= 0.0) 127 | throw std::out_of_range("firdes check failed: sampling_freq > 0"); 128 | 129 | if (fa <= 0.0 || fa > sampling_freq / 2) 130 | throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); 131 | 132 | if (transition_width <= 0) 133 | throw std::out_of_range("firdes check failed: transition_width > 0"); 134 | } 135 | 136 | std::vector firfilter::window(win_type type, int ntaps) 137 | { 138 | return build(type, ntaps); 139 | } 140 | 141 | double firfilter::max_attenuation(win_type type, double beta) 142 | { 143 | switch (type) { 144 | case (WIN_HAMMING): 145 | return 53; 146 | break; 147 | case (WIN_HANN): 148 | return 44; 149 | break; 150 | case (WIN_BLACKMAN): 151 | return 74; 152 | break; 153 | case (WIN_RECTANGULAR): 154 | return 21; 155 | break; 156 | case (WIN_KAISER): 157 | return (beta / 0.1102 + 8.7); 158 | break; 159 | case (WIN_BLACKMAN_hARRIS): 160 | return 92; 161 | break; 162 | case (WIN_BARTLETT): 163 | return 27; 164 | break; 165 | case (WIN_FLATTOP): 166 | return 93; 167 | break; 168 | default: 169 | throw std::out_of_range("window::max_attenuation: unknown window type provided."); 170 | } 171 | } 172 | 173 | 174 | std::vector firfilter::build(win_type type, int ntaps) 175 | { 176 | switch (type) { 177 | case WIN_HAMMING: 178 | return hamming(ntaps); 179 | case WIN_HANN: 180 | return hann(ntaps); 181 | case WIN_BLACKMAN: 182 | return blackman(ntaps); 183 | case WIN_BLACKMAN_hARRIS: 184 | return blackman_harris(ntaps); 185 | default: 186 | throw std::out_of_range("window::build: type out of range"); 187 | } 188 | } 189 | 190 | std::vector firfilter::blackman_harris(int ntaps, int atten) 191 | { 192 | switch (atten) { 193 | case (61): 194 | return coswindow(ntaps, 0.42323, 0.49755, 0.07922); 195 | case (67): 196 | return coswindow(ntaps, 0.44959, 0.49364, 0.05677); 197 | case (74): 198 | return coswindow(ntaps, 0.40271, 0.49703, 0.09392, 0.00183); 199 | case (92): 200 | return coswindow(ntaps, 0.35875, 0.48829, 0.14128, 0.01168); 201 | default: 202 | throw std::out_of_range("window::blackman_harris: unknown attenuation value " 203 | "(must be 61, 67, 74, or 92)"); 204 | } 205 | } 206 | 207 | std::vector firfilter::blackman(int ntaps) 208 | { 209 | return coswindow(ntaps, 0.42, 0.5, 0.08); 210 | } 211 | 212 | std::vector firfilter::hamming(int ntaps) 213 | { 214 | std::vector taps(ntaps); 215 | float M = static_cast(ntaps - 1); 216 | 217 | for (int n = 0; n < ntaps; n++) 218 | taps[n] = 0.54 - 0.46 * cos((2 * M_PI * n) / M); 219 | return taps; 220 | } 221 | 222 | std::vector firfilter::hann(int ntaps) 223 | { 224 | std::vector taps(ntaps); 225 | float M = static_cast(ntaps - 1); 226 | 227 | for (int n = 0; n < ntaps; n++) 228 | taps[n] = 0.5 - 0.5 * cos((2 * M_PI * n) / M); 229 | return taps; 230 | } 231 | 232 | std::vector firfilter::coswindow(int ntaps, float c0, float c1, float c2) 233 | { 234 | std::vector taps(ntaps); 235 | float M = static_cast(ntaps - 1); 236 | 237 | for (int n = 0; n < ntaps; n++) 238 | taps[n] = c0 - c1 * cosf((2.0f * M_PI * n) / M) + 239 | c2 * cosf((4.0f *M_PI * n) / M); 240 | return taps; 241 | } 242 | 243 | std::vector firfilter::coswindow(int ntaps, float c0, float c1, float c2, float c3) 244 | { 245 | std::vector taps(ntaps); 246 | float M = static_cast(ntaps - 1); 247 | 248 | for (int n = 0; n < ntaps; n++) 249 | taps[n] = c0 - c1 * cosf((2.0f * M_PI * n) / M) + 250 | c2 * cosf((4.0f * M_PI * n) / M) - 251 | c3 * cosf((6.0f * M_PI * n) / M); 252 | return taps; 253 | } 254 | -------------------------------------------------------------------------------- /gnuradio/firfilter.h: -------------------------------------------------------------------------------- 1 | #ifndef FIRFILTER_H 2 | #define FIRFILTER_H 3 | 4 | #include "qvector.h" 5 | 6 | class firfilter 7 | { 8 | public: 9 | 10 | enum win_type { 11 | WIN_NONE = -1, //!< don't use a window 12 | WIN_HAMMING = 0, //!< Hamming window; max attenuation 53 dB 13 | WIN_HANN = 1, //!< Hann window; max attenuation 44 dB 14 | WIN_BLACKMAN = 2, //!< Blackman window; max attenuation 74 dB 15 | WIN_RECTANGULAR = 3, //!< Basic rectangular window 16 | WIN_KAISER = 4, //!< Kaiser window; max attenuation a function of beta, google it 17 | WIN_BLACKMAN_hARRIS = 5, //!< Blackman-harris window 18 | WIN_BLACKMAN_HARRIS = 19 | 5, //!< alias to WIN_BLACKMAN_hARRIS for capitalization consistency 20 | WIN_BARTLETT = 6, //!< Barlett (triangular) window 21 | WIN_FLATTOP = 7, //!< flat top window; useful in FFTs 22 | }; 23 | 24 | firfilter(); 25 | double filter(double in); 26 | void setTaps(QVector taps); 27 | ~firfilter(); 28 | 29 | QVectorlow_pass(double gain, double sampling_freq, double cutoff_freq, double transition_width, win_type window_type,double beta); 30 | 31 | private: 32 | 33 | int M; // The number of taps, the length of the filter 34 | double Fc = 0x0D; // Will be set to cutoffFreq/SAMPLE_RATE; 35 | 36 | QVector xv; // This array holds the delayed values 37 | QVector coeffs; 38 | 39 | std::vector window(win_type type, int ntaps); 40 | void sanity_check_1f(double sampling_freq, double fa, double transition_width); 41 | int compute_ntaps(double sampling_freq,double transition_width, win_type window_type,double beta); 42 | 43 | double max_attenuation(win_type type, double beta); 44 | 45 | std::vector build(win_type type, int ntaps); 46 | std::vector blackman_harris(int ntaps, int atten = 92); 47 | std::vector blackman(int ntaps); 48 | std::vector hamming(int ntaps); 49 | std::vector hann(int ntaps); 50 | std::vector coswindow(int ntaps, float c0, float c1, float c2); 51 | std::vector coswindow(int ntaps, float c0, float c1, float c2, float c3); 52 | 53 | 54 | }; 55 | 56 | #endif // FIRFILTER_H 57 | -------------------------------------------------------------------------------- /halfbanddecimator.cpp: -------------------------------------------------------------------------------- 1 | #include "halfbanddecimator.h" 2 | 3 | HalfBandDecimator::HalfBandDecimator(int taps, int inlen) 4 | { 5 | 6 | fir_i=new FIR(taps, inlen); 7 | fir_q=new FIR(taps, inlen); 8 | 9 | 10 | switch(taps){ 11 | 12 | case 51: 13 | for(int i=0;iFIRSetPoint(i,hbcoeff51[i]); 16 | fir_q->FIRSetPoint(i,hbcoeff51[i]); 17 | } 18 | break; 19 | case 11: 20 | for(int i=0;iFIRSetPoint(i,hbcoeff11[i]); 23 | fir_q->FIRSetPoint(i,hbcoeff11[i]); 24 | } 25 | break; 26 | case 23: 27 | for(int i=0;iFIRSetPoint(i,hbcoeff23[i]); 30 | fir_q->FIRSetPoint(i,hbcoeff23[i]); 31 | } 32 | break; 33 | 34 | } 35 | 36 | } 37 | HalfBandDecimator::~HalfBandDecimator() 38 | { 39 | delete fir_i; 40 | delete fir_q; 41 | } 42 | 43 | void HalfBandDecimator::decimate(const std::vector &in, std::vector &out) 44 | { 45 | int step = 0; 46 | // decimate half band 1 47 | int size = (int)in.size(); 48 | for(int i=0;iFIRUpdateAndProcessHalfBandQueue(in[i].real()), fir_q->FIRUpdateAndProcessHalfBandQueue(in[i].imag())); 56 | out[step]=curr; 57 | 58 | step++; 59 | 60 | }else 61 | { 62 | 63 | fir_i->FIRUpdateQueue(in[i].real()); 64 | fir_q->FIRUpdateQueue(in[i].imag()); 65 | 66 | } 67 | } 68 | 69 | fir_i->FIRQueueBackToFront(); 70 | fir_q->FIRQueueBackToFront(); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /halfbanddecimator.h: -------------------------------------------------------------------------------- 1 | #ifndef HALFBANDDECIMATOR_H 2 | #define HALFBANDDECIMATOR_H 3 | 4 | #include 5 | #include "complex.h" 6 | #include "jonti/dsp.h" 7 | 8 | 9 | typedef std::complex cpx_typef; 10 | 11 | 12 | class HalfBandDecimator 13 | { 14 | 15 | public: 16 | HalfBandDecimator(int taps, int inlen); 17 | ~HalfBandDecimator(); 18 | 19 | 20 | void decimate(const std::vector & in,std::vector & out); 21 | 22 | 23 | private: 24 | 25 | FIR * fir_i; 26 | FIR * fir_q; 27 | 28 | float hbcoeff51[51]{ 29 | 0.0010175926971811044, 0.0, -0.0013058886799502411, 0.0, 0.0020730260200910026, 0.0, -0.0034255790572079265, 0.0, 0.005490505092950141, 0.0, -0.008434405740804745, 0.0, 0.012502602797600649, 0.0, -0.01810260996706492, 0.0, 0.026000146160530365, 0.0, -0.037851497102093665, 0.0, 0.05801218485928863, 0.0, -0.1025751653146947, 0.0, 0.31684426465520726, 0.499509647157934, 0.3168442646552072, 0.0, -0.10257516531469468, 0.0, 0.05801218485928862, 0.0, -0.03785149710209366, 0.0, 0.02600014616053035, 0.0, -0.018102609967064916, 0.0, 0.012502602797600643, 0.0, -0.008434405740804745, 0.0, 0.005490505092950138, 0.0, -0.0034255790572079218, 0.0, 0.0020730260200910026, 0.0, -0.0013058886799502405, 0.0, 0.0010175926971811044 30 | 31 | 32 | }; 33 | 34 | float hbcoeff21[21]{ 35 | 0.0, 0.003619160996209284, 0.0, -0.012238250198266238, 0.0, 0.034315551069916406, 0.0, -0.08582925310376682, 0.0, 0.31058306173328054, 0.49909945900525354, 0.31058306173328054, 0.0, -0.08582925310376682, 0.0, 0.034315551069916406, 0.0, -0.012238250198266238, 0.0, 0.003619160996209284, 0.0 36 | 37 | }; 38 | 39 | float hbcoeff23[23]{ 40 | 41 | -0.00014987651418332164, 42 | 0.0f, 43 | 0.0014748633283609852f, 44 | 0.0f, 45 | -0.0074416944990005314f, 46 | 0.0f, 47 | 0.026163522731980929f, 48 | 0.0f, 49 | -0.077593699116544707f, 50 | 0.0f, 51 | 0.30754683719791986f, 52 | 0.5f, 53 | 0.30754683719791986f, 54 | 0.0f, 55 | -0.077593699116544707f, 56 | 0.0f, 57 | 0.026163522731980929f, 58 | 0.0f, 59 | -0.0074416944990005314f, 60 | 0.0f, 61 | 0.0014748633283609852f, 62 | 0.0f, 63 | -0.00014987651418332164f 64 | }; 65 | 66 | float hbcoeff11[11] = 67 | { 68 | 0.0060431029837374152f, 69 | 0.0f, 70 | -0.049372515458761493f, 71 | 0.0f, 72 | 0.29332944952052842f, 73 | 0.5f, 74 | 0.29332944952052842f, 75 | 0.0f, 76 | -0.049372515458761493f, 77 | 0.0f, 78 | 0.0060431029837374152f 79 | }; 80 | 81 | float hbcoeff15[15] = 82 | { 83 | -0.001442203300285281f, 84 | 0.0f, 85 | 0.013017512802724852f, 86 | 0.0f, 87 | -0.061653278604903369f, 88 | 0.0f, 89 | 0.30007792316024057f, 90 | 0.5f, 91 | 0.30007792316024057f, 92 | 0.0f, 93 | -0.061653278604903369f, 94 | 0.0f, 95 | 0.013017512802724852f, 96 | 0.0f, 97 | -0.001442203300285281f 98 | }; 99 | }; 100 | 101 | 102 | 103 | 104 | #endif // HALFBANDDECIMATOR_H 105 | -------------------------------------------------------------------------------- /jonti/dsp.cpp: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #include "dsp.h" 24 | #include 25 | 26 | //--------------------------------------------------------------------------- 27 | #ifndef M_PI 28 | #define M_PI 3.14159265358979323846264338327950288 29 | #endif 30 | using namespace std; 31 | 32 | FIR::FIR(int _NumberOfPoints, int queuesz) 33 | { 34 | int i; 35 | points=0;buff=0; 36 | 37 | NumberOfPoints=_NumberOfPoints; 38 | buffsize=NumberOfPoints+1; 39 | points=new float[NumberOfPoints]; 40 | for(i=0;i=buffsize)ptr=0;//ptr%=buffsize; 63 | int tptr=ptr; 64 | outsum=0; 65 | for(int i=0;i=buffsize)tptr=0;//tptr%=buffsize; 69 | } 70 | return outsum; 71 | } 72 | 73 | 74 | float FIR::FIRUpdateAndProcessHalfBand(float sig) 75 | { 76 | 77 | buff[ptr]=sig; 78 | ptr++;if(ptr>=buffsize)ptr=0;//ptr%=buffsize; 79 | int tptr=ptr; 80 | outsum=0; 81 | 82 | 83 | for(int i=0;i=buffsize)tptr=0;//tptr%=buffsize; 91 | } 92 | 93 | return outsum; 94 | } 95 | 96 | float FIR::FIRUpdateAndProcessHalfBandQueue(float sig) 97 | { 98 | 99 | queue[queuePtr]=sig; 100 | queuePtr++; 101 | int tptr = queuePtr - NumberOfPoints; 102 | 103 | outsum=0; 104 | 105 | switch(NumberOfPoints) 106 | { 107 | 108 | case 51 : 109 | 110 | outsum += points[0]*(queue[tptr] + queue[tptr + 50]) 111 | + points[2]*(queue[tptr+2] + queue[tptr + 48]) 112 | + points[4]*(queue[tptr+4] + queue[tptr + 46]) 113 | + points[6]*(queue[tptr+6] + queue[tptr + 44]) 114 | + points[8]*(queue[tptr+8] + queue[tptr + 42]) 115 | + points[10]*(queue[tptr+10] + queue[tptr + 40]) 116 | + points[12]*(queue[tptr+12] + queue[tptr + 38]) 117 | + points[14]*(queue[tptr+14] + queue[tptr + 36]) 118 | + points[16]*(queue[tptr+16] + queue[tptr + 34]) 119 | + points[18]*(queue[tptr+18] + queue[tptr + 32]) 120 | + points[20]*(queue[tptr+20] + queue[tptr + 30]) 121 | + points[22]*(queue[tptr+22] + queue[tptr + 28]) 122 | + points[24]*(queue[tptr+24] + queue[tptr + 26]) 123 | + points[25]*(queue[tptr+25]) ; 124 | break; 125 | 126 | case 23: 127 | 128 | outsum += points[0]*(queue[tptr] + queue[tptr + 22]) 129 | + points[2]*(queue[tptr+2] + queue[tptr + 20]) 130 | + points[4]*(queue[tptr+4] + queue[tptr + 18]) 131 | + points[6]*(queue[tptr+6] + queue[tptr + 16]) 132 | + points[8]*(queue[tptr+8] + queue[tptr + 14]) 133 | + points[10]*(queue[tptr+10] + queue[tptr + 12]) 134 | + points[11]*(queue[tptr+11]) ; 135 | break; 136 | 137 | case 11: 138 | 139 | outsum += points[0]*(queue[tptr] + queue[tptr + 10]) 140 | + points[2]*(queue[tptr+2] + queue[tptr + 8]) 141 | + points[4]*(queue[tptr+4] + queue[tptr + 6]) 142 | + points[5]*(queue[tptr+5]) ; 143 | break; 144 | } 145 | 146 | 147 | 148 | return outsum; 149 | } 150 | void FIR::FIRUpdate(float sig) 151 | { 152 | buff[ptr]=sig; 153 | ptr++;ptr%=buffsize; 154 | } 155 | 156 | void FIR::FIRUpdateQueue(float sig) 157 | { 158 | queue[queuePtr]=sig; 159 | queuePtr++; 160 | } 161 | 162 | 163 | void FIR::FIRQueueBackToFront() 164 | { 165 | 166 | //queuePtr points to the next empy slot 167 | if(queuePtr >= NumberOfPoints) 168 | { 169 | std::copy(queue + ((queuePtr-1)-NumberOfPoints), queue + (queuePtr-1), queue); 170 | } 171 | 172 | queuePtr = NumberOfPoints; 173 | } 174 | 175 | 176 | 177 | void FIR::FIRSetPoint(int point, float value) 178 | { 179 | 180 | if((point<0)||(point>=NumberOfPoints))return; 181 | points[point]=value; 182 | } 183 | 184 | FIRHilbert::FIRHilbert(int len, int Fs) 185 | { 186 | int i; 187 | points=0;buff=0; 188 | 189 | NumberOfPoints=len; 190 | 191 | points=new float[len]; 192 | for(i=0;i tempCoeffs(len); 199 | 200 | float sumofsquares = 0; 201 | 202 | for (int n=0; n < len; n++) { 203 | if (n == len/2) { 204 | tempCoeffs[n] = 0; 205 | } else { 206 | tempCoeffs[n] = Fs / (M_PI * (n-len/2) ) * ( 1 - cos(M_PI * (n-len/2) )); 207 | 208 | 209 | } 210 | sumofsquares += tempCoeffs[n]*tempCoeffs[n]; 211 | } 212 | double gain = sqrt(sumofsquares); 213 | 214 | for (int i=0; i < len; i++) { 215 | points[i] = tempCoeffs[len-i-1]/gain; 216 | } 217 | } 218 | double FIRHilbert::FIRUpdateAndProcess(float sig) 219 | { 220 | buff[ptr]=sig; 221 | ptr++;if(ptr>=NumberOfPoints)ptr=0; 222 | int tptr=ptr; 223 | outsum=0; 224 | 225 | for(int i=0;i=NumberOfPoints)tptr=0; 229 | } 230 | return outsum; 231 | } 232 | 233 | FIRHilbert::~FIRHilbert() 234 | { 235 | if(points)delete [] points; 236 | if(buff)delete [] buff; 237 | } 238 | -------------------------------------------------------------------------------- /jonti/dsp.h: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | 24 | #ifndef DSP_F_H 25 | #define DSP_F_H 26 | 27 | #endif // DSP_F_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | class FIR 35 | { 36 | public: 37 | FIR(int _NumberOfPoints, int queuesz); 38 | ~FIR(); 39 | float FIRUpdateAndProcess(float sig); 40 | float FIRUpdateAndProcessHalfBand(float sig); 41 | float FIRUpdateAndProcessHalfBandQueue(float sig); 42 | 43 | void FIRUpdate(float sig); 44 | void FIRUpdateQueue(float sig); 45 | 46 | float FIRUpdateAndProcess(float sig, float FractionOfSampleOffset); 47 | void FIRSetPoint(int point, float value); 48 | 49 | float *points; 50 | float *buff; 51 | int NumberOfPoints; 52 | int buffsize; 53 | int ptr; 54 | float outsum; 55 | 56 | 57 | void FIRQueueBackToFront(); 58 | float * queue; 59 | int queuePtr; 60 | }; 61 | 62 | class FIRHilbert 63 | { 64 | public: 65 | FIRHilbert(int len, int Fs); 66 | ~FIRHilbert(); 67 | double FIRUpdateAndProcess(float sig); 68 | 69 | float *points; 70 | float *buff; 71 | int NumberOfPoints; 72 | int buffsize; 73 | int ptr; 74 | int M; 75 | float outsum; 76 | }; 77 | 78 | 79 | template 80 | class DelayThing 81 | { 82 | public: 83 | DelayThing() 84 | { 85 | setLength(12); 86 | } 87 | void setLength(int length) 88 | { 89 | length++; 90 | assert(length>0); 91 | buffer.resize(length); 92 | buffer_ptr=0; 93 | buffer_sz=buffer.size(); 94 | } 95 | void update(T &data) 96 | { 97 | buffer[buffer_ptr]=data; 98 | buffer_ptr++;buffer_ptr%=buffer_sz; 99 | data=buffer[buffer_ptr]; 100 | } 101 | T update_dont_touch(T data) 102 | { 103 | buffer[buffer_ptr]=data; 104 | buffer_ptr++;buffer_ptr%=buffer_sz; 105 | return buffer.at(buffer_ptr); 106 | } 107 | int findmaxpos(T &maxval) 108 | { 109 | int maxpos=0; 110 | maxval=buffer[buffer_ptr]; 111 | for(int i=0;imaxval) 114 | { 115 | maxval=buffer[buffer_ptr]; 116 | maxpos=i; 117 | } 118 | buffer_ptr++;buffer_ptr%=buffer_sz; 119 | } 120 | return maxpos; 121 | } 122 | private: 123 | QVector buffer; 124 | int buffer_ptr; 125 | int buffer_sz; 126 | }; 127 | -------------------------------------------------------------------------------- /jonti/fftrwrapper.cpp: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #include "fftrwrapper.h" 24 | #include 25 | 26 | template 27 | FFTrWrapper::FFTrWrapper(int _nfft,bool inverse) 28 | { 29 | nfft=_nfft; 30 | cfg = kiss_fftr_alloc(nfft, inverse, NULL, NULL); 31 | privatescalar.resize(nfft); 32 | privatecomplex.resize(nfft); 33 | } 34 | 35 | template 36 | FFTrWrapper::~FFTrWrapper() 37 | { 38 | free(cfg); 39 | 40 | } 41 | 42 | template 43 | void FFTrWrapper::transform(const QVector &in, QVector< std::complex > &out) 44 | { 45 | assert(in.size()==out.size()); 46 | assert(in.size()==nfft); 47 | for(int i=0;i((double)privatecomplex[i].r,(double)privatecomplex[i].i); 55 | } 56 | } 57 | 58 | template 59 | void FFTrWrapper::transform(const QVector< std::complex > &in, QVector &out) 60 | { 61 | assert(in.size()==out.size()); 62 | assert(in.size()==nfft); 63 | for(int i=0;i; 76 | template class FFTrWrapper; 77 | -------------------------------------------------------------------------------- /jonti/fftrwrapper.h: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #ifndef FFTRWRAPPER_H 24 | #define FFTRWRAPPER_H 25 | 26 | #include 27 | #include 28 | #include "kiss_fft130/kiss_fftr.h" 29 | 30 | //underlying fft still uses the type in the kiss_fft_type in the c stuff 31 | template 32 | class FFTrWrapper 33 | { 34 | public: 35 | FFTrWrapper(int nfft,bool inverse); 36 | ~FFTrWrapper(); 37 | void transform(const QVector &in, QVector< std::complex > &out); 38 | void transform(const QVector< std::complex > &in, QVector &out); 39 | private: 40 | kiss_fftr_cfg cfg; 41 | QVector privatescalar; 42 | QVector privatecomplex; 43 | int nfft; 44 | }; 45 | 46 | #endif // FFTRWRAPPER_H 47 | -------------------------------------------------------------------------------- /jonti/fftwrapper.cpp: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #include "fftwrapper.h" 24 | #include 25 | 26 | template 27 | FFTWrapper::FFTWrapper(int _nfft, bool inverse) 28 | { 29 | nfft=_nfft; 30 | cfg = kiss_fft_alloc(nfft, inverse, NULL, NULL); 31 | privatein.resize(nfft); 32 | privateout.resize(nfft); 33 | } 34 | 35 | template 36 | FFTWrapper::~FFTWrapper() 37 | { 38 | free(cfg); 39 | } 40 | 41 | template 42 | void FFTWrapper::transform(const QVector< std::complex > &in, QVector< std::complex > &out) 43 | { 44 | assert(in.size()==out.size()); 45 | assert(in.size()==nfft); 46 | for(int i=0;i((double)privateout[i].r,(double)privateout[i].i); 55 | } 56 | } 57 | 58 | template class FFTWrapper; 59 | template class FFTWrapper; 60 | -------------------------------------------------------------------------------- /jonti/fftwrapper.h: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #ifndef FFTWRAPPER_H 24 | #define FFTWRAPPER_H 25 | 26 | #include 27 | #include 28 | #include "kiss_fft130/kiss_fft.h" 29 | 30 | //underlying fft still uses the type in the kiss_fft_type in the c stuff 31 | template 32 | class FFTWrapper 33 | { 34 | public: 35 | FFTWrapper(int nfft,bool inverse); 36 | ~FFTWrapper(); 37 | void transform(const QVector< std::complex > &in, QVector< std::complex > &out); 38 | private: 39 | kiss_fft_cfg cfg; 40 | QVector privatein; 41 | QVector privateout; 42 | int nfft; 43 | }; 44 | 45 | #endif // FFTWRAPPER_H 46 | -------------------------------------------------------------------------------- /jonti/sdr.cpp: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Jonathan Olds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.*/ 22 | 23 | #include "sdr.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "qvector.h" 30 | 31 | sdr::sdr(QObject *parent) : QObject(parent) 32 | { 33 | 34 | rtldev = NULL; 35 | 36 | do_demod_dispatcher_cancel=false; 37 | buffers_head_ptr=0; 38 | buffers_tail_ptr=0; 39 | buffers_used=0; 40 | 41 | active = false; 42 | 43 | floats.resize(256); 44 | const float scale = 1.0;// /127.0; 45 | 46 | for (int i = 0; i < 256; i++) 47 | { 48 | floats[i] = (i - 127)*scale; 49 | } 50 | 51 | 52 | } 53 | 54 | sdr::~sdr() 55 | { 56 | 57 | 58 | } 59 | 60 | bool sdr::OpenRtl(int device_idx) 61 | { 62 | 63 | int open_res = rtlsdr_open(&rtldev,device_idx); 64 | if (open_res != 0) 65 | { 66 | return false; 67 | } 68 | 69 | return true; 70 | 71 | } 72 | 73 | void sdr::StartRtl(int samplerate, int frequency, int buflen, int gain) 74 | { 75 | 76 | do_demod_dispatcher_cancel=false; 77 | active=false; 78 | buffers_head_ptr=0; 79 | buffers_tail_ptr=0; 80 | buffers_used=0; 81 | 82 | 83 | //reset buffer and go 84 | rtlsdr_reset_buffer(rtldev); 85 | future_demod_dispatcher = QtConcurrent::run(this,&sdr::demod_dispatcher); 86 | 87 | rtlsdr_set_sample_rate(rtldev, samplerate); 88 | rtlsdr_set_center_freq(rtldev, frequency); 89 | rtlsdr_set_tuner_gain_mode(rtldev,1); 90 | rtlsdr_set_tuner_gain(rtldev, gain); 91 | rtlsdr_set_agc_mode(rtldev,0); 92 | 93 | future_rtlsdr_callback = QtConcurrent::run(rtlsdr_read_async, rtldev,(rtlsdr_read_async_cb_t)rtlsdr_callback_dispatcher, this,0,buflen);//16384*2); 94 | 95 | active = true; 96 | 97 | } 98 | 99 | 100 | void sdr::rtlsdr_callback(unsigned char *buf, uint32_t len) 101 | { 102 | 103 | //check if buffers have room for one more 104 | buffers_mut.lock(); 105 | if(buffers_used>=N_BUFFERS) 106 | { 107 | qDebug()<<"Dropped RTL buffer!!"; 108 | buffers_mut.unlock(); 109 | return; 110 | } 111 | buffers_mut.unlock(); 112 | 113 | //cycle buffers 114 | buffers_head_ptr%=N_BUFFERS; 115 | 116 | //resize buffer if needed 117 | buffers[buffers_head_ptr].resize(len); 118 | 119 | float *buffptr=buffers[buffers_head_ptr].data(); 120 | 121 | 122 | for(uint32_t i=0;i 28 | #include "complex.h" 29 | #include "jonti/fftrwrapper.h" 30 | #include "qmutex.h" 31 | #include "QWaitCondition" 32 | #include 33 | 34 | extern "C" { 35 | #include "rtl-sdr.h" 36 | } 37 | 38 | class sdr : public QObject 39 | { 40 | 41 | Q_OBJECT 42 | 43 | public: 44 | 45 | sdr(QObject *parent = 0); 46 | bool OpenRtl(int device_idx); 47 | bool StopAndCloseRtl(); 48 | QStringList deviceNames(); 49 | void StartRtl(int sample_rate, int frequency, int buflen, int gain = 496); 50 | 51 | ~sdr(); 52 | rtlsdr_dev_t *rtldev; 53 | bool active; 54 | QVector floats; 55 | 56 | 57 | signals: 58 | 59 | void audio_signal_out(const float *inputBuffer, int size); 60 | 61 | 62 | public slots: 63 | 64 | private: 65 | 66 | bool StopRtl(); 67 | 68 | 69 | //thread to send audio to demodulator 70 | bool demod_dispatcher(); 71 | 72 | //thread to process the data from the RTL dongle 73 | void rtlsdr_callback(unsigned char *buf, uint32_t len); 74 | 75 | static void rtlsdr_callback_dispatcher(unsigned char *buf, uint32_t len, void *ctx) 76 | { 77 | sdr *inst=(sdr*)ctx; 78 | inst->rtlsdr_callback(buf,len); 79 | } 80 | 81 | //how we talk to the demod_dispatcher thread 82 | QFuture future_demod_dispatcher; 83 | bool do_demod_dispatcher_cancel; 84 | 85 | //how we talk to the rtl_callack thread 86 | QFuture future_rtlsdr_callback; 87 | 88 | //For returning data from the rtl_callback thread to the demod_dispatcher thread 89 | #define N_BUFFERS 20 90 | 91 | QWaitCondition buffers_not_empty; 92 | QMutex buffers_mut; 93 | 94 | std::vector buffers[N_BUFFERS]; 95 | int buffers_size_valid[N_BUFFERS]; 96 | 97 | int buffers_head_ptr=0; 98 | int buffers_tail_ptr=0; 99 | int buffers_used=0; 100 | }; 101 | 102 | 103 | #endif // SDR_H 104 | -------------------------------------------------------------------------------- /kiss_fft130/CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.3.0 2012-07-18 2 | removed non-standard malloc.h from kiss_fft.h 3 | 4 | moved -lm to end of link line 5 | 6 | checked various return values 7 | 8 | converted python Numeric code to NumPy 9 | 10 | fixed test of int32_t on 64 bit OS 11 | 12 | added padding in a couple of places to allow SIMD alignment of structs 13 | 14 | 1.2.9 2010-05-27 15 | threadsafe ( including OpenMP ) 16 | 17 | first edition of kissfft.hh the C++ template fft engine 18 | 19 | 1.2.8 20 | Changed memory.h to string.h -- apparently more standard 21 | 22 | Added openmp extensions. This can have fairly linear speedups for larger FFT sizes. 23 | 24 | 1.2.7 25 | Shrank the real-fft memory footprint. Thanks to Galen Seitz. 26 | 27 | 1.2.6 (Nov 14, 2006) The "thanks to GenArts" release. 28 | Added multi-dimensional real-optimized FFT, see tools/kiss_fftndr 29 | Thanks go to GenArts, Inc. for sponsoring the development. 30 | 31 | 1.2.5 (June 27, 2006) The "release for no good reason" release. 32 | Changed some harmless code to make some compilers' warnings go away. 33 | Added some more digits to pi -- why not. 34 | Added kiss_fft_next_fast_size() function to help people decide how much to pad. 35 | Changed multidimensional test from 8 dimensions to only 3 to avoid testing 36 | problems with fixed point (sorry Buckaroo Banzai). 37 | 38 | 1.2.4 (Oct 27, 2005) The "oops, inverse fixed point real fft was borked" release. 39 | Fixed scaling bug for inverse fixed point real fft -- also fixed test code that should've been failing. 40 | Thanks to Jean-Marc Valin for bug report. 41 | 42 | Use sys/types.h for more portable types than short,int,long => int16_t,int32_t,int64_t 43 | If your system does not have these, you may need to define them -- but at least it breaks in a 44 | loud and easily fixable way -- unlike silently using the wrong size type. 45 | 46 | Hopefully tools/psdpng.c is fixed -- thanks to Steve Kellog for pointing out the weirdness. 47 | 48 | 1.2.3 (June 25, 2005) The "you want to use WHAT as a sample" release. 49 | Added ability to use 32 bit fixed point samples -- requires a 64 bit intermediate result, a la 'long long' 50 | 51 | Added ability to do 4 FFTs in parallel by using SSE SIMD instructions. This is accomplished by 52 | using the __m128 (vector of 4 floats) as kiss_fft_scalar. Define USE_SIMD to use this. 53 | 54 | I know, I know ... this is drifting a bit from the "kiss" principle, but the speed advantages 55 | make it worth it for some. Also recent gcc makes it SOO easy to use vectors of 4 floats like a POD type. 56 | 57 | 1.2.2 (May 6, 2005) The Matthew release 58 | Replaced fixed point division with multiply&shift. Thanks to Jean-Marc Valin for 59 | discussions regarding. Considerable speedup for fixed-point. 60 | 61 | Corrected overflow protection in real fft routines when using fixed point. 62 | Finder's Credit goes to Robert Oschler of robodance for pointing me at the bug. 63 | This also led to the CHECK_OVERFLOW_OP macro. 64 | 65 | 1.2.1 (April 4, 2004) 66 | compiles cleanly with just about every -W warning flag under the sun 67 | 68 | reorganized kiss_fft_state so it could be read-only/const. This may be useful for embedded systems 69 | that are willing to predeclare twiddle factors, factorization. 70 | 71 | Fixed C_MUL,S_MUL on 16-bit platforms. 72 | 73 | tmpbuf will only be allocated if input & output buffers are same 74 | scratchbuf will only be allocated for ffts that are not multiples of 2,3,5 75 | 76 | NOTE: The tmpbuf,scratchbuf changes may require synchronization code for multi-threaded apps. 77 | 78 | 79 | 1.2 (Feb 23, 2004) 80 | interface change -- cfg object is forward declaration of struct instead of void* 81 | This maintains type saftey and lets the compiler warn/error about stupid mistakes. 82 | (prompted by suggestion from Erik de Castro Lopo) 83 | 84 | small speed improvements 85 | 86 | added psdpng.c -- sample utility that will create png spectrum "waterfalls" from an input file 87 | ( not terribly useful yet) 88 | 89 | 1.1.1 (Feb 1, 2004 ) 90 | minor bug fix -- only affects odd rank, in-place, multi-dimensional FFTs 91 | 92 | 1.1 : (Jan 30,2004) 93 | split sample_code/ into test/ and tools/ 94 | 95 | Removed 2-D fft and added N-D fft (arbitrary) 96 | 97 | modified fftutil.c to allow multi-d FFTs 98 | 99 | Modified core fft routine to allow an input stride via kiss_fft_stride() 100 | (eased support of multi-D ffts) 101 | 102 | Added fast convolution filtering (FIR filtering using overlap-scrap method, with tail scrap) 103 | 104 | Add kfc.[ch]: the KISS FFT Cache. It takes care of allocs for you ( suggested by Oscar Lesta ). 105 | 106 | 1.0.1 (Dec 15, 2003) 107 | fixed bug that occurred when nfft==1. Thanks to Steven Johnson. 108 | 109 | 1.0 : (Dec 14, 2003) 110 | changed kiss_fft function from using a single buffer, to two buffers. 111 | If the same buffer pointer is supplied for both in and out, kiss will 112 | manage the buffer copies. 113 | 114 | added kiss_fft2d and kiss_fftr as separate source files (declarations in kiss_fft.h ) 115 | 116 | 0.4 :(Nov 4,2003) optimized for radix 2,3,4,5 117 | 118 | 0.3 :(Oct 28, 2003) woops, version 2 didn't actually factor out any radices other than 2. 119 | Thanks to Steven Johnson for finding this one. 120 | 121 | 0.2 :(Oct 27, 2003) added mixed radix, only radix 2,4 optimized versions 122 | 123 | 0.1 :(May 19 2003) initial release, radix 2 only 124 | -------------------------------------------------------------------------------- /kiss_fft130/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2003-2010 Mark Borgerding 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /kiss_fft130/README: -------------------------------------------------------------------------------- 1 | KISS FFT - A mixed-radix Fast Fourier Transform based up on the principle, 2 | "Keep It Simple, Stupid." 3 | 4 | There are many great fft libraries already around. Kiss FFT is not trying 5 | to be better than any of them. It only attempts to be a reasonably efficient, 6 | moderately useful FFT that can use fixed or floating data types and can be 7 | incorporated into someone's C program in a few minutes with trivial licensing. 8 | 9 | USAGE: 10 | 11 | The basic usage for 1-d complex FFT is: 12 | 13 | #include "kiss_fft.h" 14 | 15 | kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 ); 16 | 17 | while ... 18 | 19 | ... // put kth sample in cx_in[k].r and cx_in[k].i 20 | 21 | kiss_fft( cfg , cx_in , cx_out ); 22 | 23 | ... // transformed. DC is in cx_out[0].r and cx_out[0].i 24 | 25 | free(cfg); 26 | 27 | Note: frequency-domain data is stored from dc up to 2pi. 28 | so cx_out[0] is the dc bin of the FFT 29 | and cx_out[nfft/2] is the Nyquist bin (if exists) 30 | 31 | Declarations are in "kiss_fft.h", along with a brief description of the 32 | functions you'll need to use. 33 | 34 | Code definitions for 1d complex FFTs are in kiss_fft.c. 35 | 36 | You can do other cool stuff with the extras you'll find in tools/ 37 | 38 | * multi-dimensional FFTs 39 | * real-optimized FFTs (returns the positive half-spectrum: (nfft/2+1) complex frequency bins) 40 | * fast convolution FIR filtering (not available for fixed point) 41 | * spectrum image creation 42 | 43 | The core fft and most tools/ code can be compiled to use float, double, 44 | Q15 short or Q31 samples. The default is float. 45 | 46 | 47 | BACKGROUND: 48 | 49 | I started coding this because I couldn't find a fixed point FFT that didn't 50 | use assembly code. I started with floating point numbers so I could get the 51 | theory straight before working on fixed point issues. In the end, I had a 52 | little bit of code that could be recompiled easily to do ffts with short, float 53 | or double (other types should be easy too). 54 | 55 | Once I got my FFT working, I was curious about the speed compared to 56 | a well respected and highly optimized fft library. I don't want to criticize 57 | this great library, so let's call it FFT_BRANDX. 58 | During this process, I learned: 59 | 60 | 1. FFT_BRANDX has more than 100K lines of code. The core of kiss_fft is about 500 lines (cpx 1-d). 61 | 2. It took me an embarrassingly long time to get FFT_BRANDX working. 62 | 3. A simple program using FFT_BRANDX is 522KB. A similar program using kiss_fft is 18KB (without optimizing for size). 63 | 4. FFT_BRANDX is roughly twice as fast as KISS FFT in default mode. 64 | 65 | It is wonderful that free, highly optimized libraries like FFT_BRANDX exist. 66 | But such libraries carry a huge burden of complexity necessary to extract every 67 | last bit of performance. 68 | 69 | Sometimes simpler is better, even if it's not better. 70 | 71 | FREQUENTLY ASKED QUESTIONS: 72 | Q: Can I use kissfft in a project with a ___ license? 73 | A: Yes. See LICENSE below. 74 | 75 | Q: Why don't I get the output I expect? 76 | A: The two most common causes of this are 77 | 1) scaling : is there a constant multiplier between what you got and what you want? 78 | 2) mixed build environment -- all code must be compiled with same preprocessor 79 | definitions for FIXED_POINT and kiss_fft_scalar 80 | 81 | Q: Will you write/debug my code for me? 82 | A: Probably not unless you pay me. I am happy to answer pointed and topical questions, but 83 | I may refer you to a book, a forum, or some other resource. 84 | 85 | 86 | PERFORMANCE: 87 | (on Athlon XP 2100+, with gcc 2.96, float data type) 88 | 89 | Kiss performed 10000 1024-pt cpx ffts in .63 s of cpu time. 90 | For comparison, it took md5sum twice as long to process the same amount of data. 91 | 92 | Transforming 5 minutes of CD quality audio takes less than a second (nfft=1024). 93 | 94 | DO NOT: 95 | ... use Kiss if you need the Fastest Fourier Transform in the World 96 | ... ask me to add features that will bloat the code 97 | 98 | UNDER THE HOOD: 99 | 100 | Kiss FFT uses a time decimation, mixed-radix, out-of-place FFT. If you give it an input buffer 101 | and output buffer that are the same, a temporary buffer will be created to hold the data. 102 | 103 | No static data is used. The core routines of kiss_fft are thread-safe (but not all of the tools directory). 104 | 105 | No scaling is done for the floating point version (for speed). 106 | Scaling is done both ways for the fixed-point version (for overflow prevention). 107 | 108 | Optimized butterflies are used for factors 2,3,4, and 5. 109 | 110 | The real (i.e. not complex) optimization code only works for even length ffts. It does two half-length 111 | FFTs in parallel (packed into real&imag), and then combines them via twiddling. The result is 112 | nfft/2+1 complex frequency bins from DC to Nyquist. If you don't know what this means, search the web. 113 | 114 | The fast convolution filtering uses the overlap-scrap method, slightly 115 | modified to put the scrap at the tail. 116 | 117 | LICENSE: 118 | Revised BSD License, see COPYING for verbiage. 119 | Basically, "free to use&change, give credit where due, no guarantees" 120 | Note this license is compatible with GPL at one end of the spectrum and closed, commercial software at 121 | the other end. See http://www.fsf.org/licensing/licenses 122 | 123 | A commercial license is available which removes the requirement for attribution. Contact me for details. 124 | 125 | 126 | TODO: 127 | *) Add real optimization for odd length FFTs 128 | *) Document/revisit the input/output fft scaling 129 | *) Make doc describing the overlap (tail) scrap fast convolution filtering in kiss_fastfir.c 130 | *) Test all the ./tools/ code with fixed point (kiss_fastfir.c doesn't work, maybe others) 131 | 132 | AUTHOR: 133 | Mark Borgerding 134 | Mark@Borgerding.net 135 | -------------------------------------------------------------------------------- /kiss_fft130/TIPS: -------------------------------------------------------------------------------- 1 | Speed: 2 | * If you want to use multiple cores, then compile with -openmp or -fopenmp (see your compiler docs). 3 | Realize that larger FFTs will reap more benefit than smaller FFTs. This generally uses more CPU time, but 4 | less wall time. 5 | 6 | * experiment with compiler flags 7 | Special thanks to Oscar Lesta. He suggested some compiler flags 8 | for gcc that make a big difference. They shave 10-15% off 9 | execution time on some systems. Try some combination of: 10 | -march=pentiumpro 11 | -ffast-math 12 | -fomit-frame-pointer 13 | 14 | * If the input data has no imaginary component, use the kiss_fftr code under tools/. 15 | Real ffts are roughly twice as fast as complex. 16 | 17 | * If you can rearrange your code to do 4 FFTs in parallel and you are on a recent Intel or AMD machine, 18 | then you might want to experiment with the USE_SIMD code. See README.simd 19 | 20 | 21 | Reducing code size: 22 | * remove some of the butterflies. There are currently butterflies optimized for radices 23 | 2,3,4,5. It is worth mentioning that you can still use FFT sizes that contain 24 | other factors, they just won't be quite as fast. You can decide for yourself 25 | whether to keep radix 2 or 4. If you do some work in this area, let me 26 | know what you find. 27 | 28 | * For platforms where ROM/code space is more plentiful than RAM, 29 | consider creating a hardcoded kiss_fft_state. In other words, decide which 30 | FFT size(s) you want and make a structure with the correct factors and twiddles. 31 | 32 | * Frank van der Hulst offered numerous suggestions for smaller code size and correct operation 33 | on embedded targets. "I'm happy to help anyone who is trying to implement KISSFFT on a micro" 34 | 35 | Some of these were rolled into the mainline code base: 36 | - using long casts to promote intermediate results of short*short multiplication 37 | - delaying allocation of buffers that are sometimes unused. 38 | In some cases, it may be desirable to limit capability in order to better suit the target: 39 | - predefining the twiddle tables for the desired fft size. 40 | -------------------------------------------------------------------------------- /kiss_fft130/_kiss_fft_guts.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FASTFIR_GUTS_H 2 | #define KISS_FASTFIR_GUTS_H 3 | /* 4 | Copyright (c) 2003-2010, Mark Borgerding 5 | 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 12 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | */ 16 | 17 | /* kiss_fft.h 18 | defines kiss_fft_scalar as either short or a float type 19 | and defines 20 | typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ 21 | #include "kiss_fft.h" 22 | #include 23 | 24 | #define MAXFACTORS 32 25 | /* e.g. an fft of length 128 has 4 factors 26 | as far as kissfft is concerned 27 | 4*4*4*2 28 | */ 29 | 30 | struct kiss_fft_state{ 31 | int nfft; 32 | int inverse; 33 | int factors[2*MAXFACTORS]; 34 | kiss_fft_cpx twiddles[1]; 35 | }; 36 | 37 | /* 38 | Explanation of macros dealing with complex math: 39 | 40 | C_MUL(m,a,b) : m = a*b 41 | C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise 42 | C_SUB( res, a,b) : res = a - b 43 | C_SUBFROM( res , a) : res -= a 44 | C_ADDTO( res , a) : res += a 45 | * */ 46 | #ifdef FIXED_POINT 47 | #if (FIXED_POINT==32) 48 | # define FRACBITS 31 49 | # define SAMPPROD int64_t 50 | #define SAMP_MAX 2147483647 51 | #else 52 | # define FRACBITS 15 53 | # define SAMPPROD int32_t 54 | #define SAMP_MAX 32767 55 | #endif 56 | 57 | #define SAMP_MIN -SAMP_MAX 58 | 59 | #if defined(CHECK_OVERFLOW) 60 | # define CHECK_OVERFLOW_OP(a,op,b) \ 61 | if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ 62 | fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } 63 | #endif 64 | 65 | 66 | # define smul(a,b) ( (SAMPPROD)(a)*(b) ) 67 | # define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) 68 | 69 | # define S_MUL(a,b) sround( smul(a,b) ) 70 | 71 | # define C_MUL(m,a,b) \ 72 | do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ 73 | (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) 74 | 75 | # define DIVSCALAR(x,k) \ 76 | (x) = sround( smul( x, SAMP_MAX/k ) ) 77 | 78 | # define C_FIXDIV(c,div) \ 79 | do { DIVSCALAR( (c).r , div); \ 80 | DIVSCALAR( (c).i , div); }while (0) 81 | 82 | # define C_MULBYSCALAR( c, s ) \ 83 | do{ (c).r = sround( smul( (c).r , s ) ) ;\ 84 | (c).i = sround( smul( (c).i , s ) ) ; }while(0) 85 | 86 | #else /* not FIXED_POINT*/ 87 | 88 | # define S_MUL(a,b) ( (a)*(b) ) 89 | #define C_MUL(m,a,b) \ 90 | do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ 91 | (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) 92 | # define C_FIXDIV(c,div) /* NOOP */ 93 | # define C_MULBYSCALAR( c, s ) \ 94 | do{ (c).r *= (s);\ 95 | (c).i *= (s); }while(0) 96 | #endif 97 | 98 | #ifndef CHECK_OVERFLOW_OP 99 | # define CHECK_OVERFLOW_OP(a,op,b) /* noop */ 100 | #endif 101 | 102 | #define C_ADD( res, a,b)\ 103 | do { \ 104 | CHECK_OVERFLOW_OP((a).r,+,(b).r)\ 105 | CHECK_OVERFLOW_OP((a).i,+,(b).i)\ 106 | (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ 107 | }while(0) 108 | #define C_SUB( res, a,b)\ 109 | do { \ 110 | CHECK_OVERFLOW_OP((a).r,-,(b).r)\ 111 | CHECK_OVERFLOW_OP((a).i,-,(b).i)\ 112 | (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ 113 | }while(0) 114 | #define C_ADDTO( res , a)\ 115 | do { \ 116 | CHECK_OVERFLOW_OP((res).r,+,(a).r)\ 117 | CHECK_OVERFLOW_OP((res).i,+,(a).i)\ 118 | (res).r += (a).r; (res).i += (a).i;\ 119 | }while(0) 120 | 121 | #define C_SUBFROM( res , a)\ 122 | do {\ 123 | CHECK_OVERFLOW_OP((res).r,-,(a).r)\ 124 | CHECK_OVERFLOW_OP((res).i,-,(a).i)\ 125 | (res).r -= (a).r; (res).i -= (a).i; \ 126 | }while(0) 127 | 128 | 129 | #ifdef FIXED_POINT 130 | # define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase)) 131 | # define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase)) 132 | # define HALF_OF(x) ((x)>>1) 133 | #elif defined(USE_SIMD) 134 | # define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) 135 | # define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) 136 | # define HALF_OF(x) ((x)*_mm_set1_ps(.5)) 137 | #else 138 | # define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) 139 | # define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) 140 | # define HALF_OF(x) ((x)*.5) 141 | #endif 142 | 143 | #define kf_cexp(x,phase) \ 144 | do{ \ 145 | (x)->r = KISS_FFT_COS(phase);\ 146 | (x)->i = KISS_FFT_SIN(phase);\ 147 | }while(0) 148 | 149 | 150 | /* a debugging function */ 151 | #define pcpx(c)\ 152 | fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) 153 | 154 | 155 | #ifdef KISS_FFT_USE_ALLOCA 156 | // define this to allow use of alloca instead of malloc for temporary buffers 157 | // Temporary buffers are used in two case: 158 | // 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5 159 | // 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform. 160 | #include 161 | #define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes) 162 | #define KISS_FFT_TMP_FREE(ptr) 163 | #else 164 | #define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) 165 | #define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) 166 | #endif 167 | 168 | #endif //KISS_FASTFIR_GUTS_H 169 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "kiss_fastfir.h" 16 | 17 | 18 | 19 | //static int verbose=0; 20 | 21 | 22 | kiss_fastfir_cfg kiss_fastfir_alloc( 23 | const kffsamp_t * imp_resp,size_t n_imp_resp, 24 | size_t *pnfft, /* if <= 0, an appropriate size will be chosen */ 25 | void * mem,size_t*lenmem) 26 | { 27 | kiss_fastfir_cfg st = NULL; 28 | size_t len_fftcfg,len_ifftcfg; 29 | size_t memneeded = sizeof(struct kiss_fastfir_state); 30 | char * ptr; 31 | size_t i; 32 | size_t nfft=0; 33 | float scale; 34 | int n_freq_bins; 35 | if (pnfft) 36 | nfft=*pnfft; 37 | 38 | if (nfft<=0) { 39 | /* determine fft size as next power of two at least 2x 40 | the impulse response length*/ 41 | i=n_imp_resp-1; 42 | nfft=2; 43 | do{ 44 | nfft<<=1; 45 | }while (i>>=1); 46 | #ifdef MIN_FFT_LEN 47 | if ( nfft < MIN_FFT_LEN ) 48 | nfft=MIN_FFT_LEN; 49 | #endif 50 | } 51 | if (pnfft) 52 | *pnfft = nfft; 53 | 54 | #ifdef REAL_FASTFIR 55 | n_freq_bins = nfft/2 + 1; 56 | #else 57 | n_freq_bins = nfft; 58 | #endif 59 | /*fftcfg*/ 60 | FFT_ALLOC (nfft, 0, NULL, &len_fftcfg); 61 | memneeded += len_fftcfg; 62 | /*ifftcfg*/ 63 | FFT_ALLOC (nfft, 1, NULL, &len_ifftcfg); 64 | memneeded += len_ifftcfg; 65 | /* tmpbuf */ 66 | memneeded += sizeof(kffsamp_t) * nfft; 67 | /* fir_freq_resp */ 68 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 69 | /* freqbuf */ 70 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 71 | 72 | if (lenmem == NULL) { 73 | st = (kiss_fastfir_cfg) malloc (memneeded); 74 | } else { 75 | if (*lenmem >= memneeded) 76 | st = (kiss_fastfir_cfg) mem; 77 | *lenmem = memneeded; 78 | } 79 | if (!st) 80 | return NULL; 81 | 82 | st->nfft = nfft; 83 | st->ngood = nfft - n_imp_resp + 1; 84 | st->n_freq_bins = n_freq_bins; 85 | ptr=(char*)(st+1); 86 | 87 | st->fftcfg = (kfcfg_t)ptr; 88 | ptr += len_fftcfg; 89 | 90 | st->ifftcfg = (kfcfg_t)ptr; 91 | ptr += len_ifftcfg; 92 | 93 | st->tmpbuf = (kffsamp_t*)ptr; 94 | ptr += sizeof(kffsamp_t) * nfft; 95 | 96 | st->freqbuf = (kiss_fft_cpx*)ptr; 97 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 98 | 99 | st->fir_freq_resp = (kiss_fft_cpx*)ptr; 100 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 101 | 102 | FFT_ALLOC (nfft,0,st->fftcfg , &len_fftcfg); 103 | FFT_ALLOC (nfft,1,st->ifftcfg , &len_ifftcfg); 104 | 105 | memset(st->tmpbuf,0,sizeof(kffsamp_t)*nfft); 106 | /*zero pad in the middle to left-rotate the impulse response 107 | This puts the scrap samples at the end of the inverse fft'd buffer */ 108 | st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ]; 109 | for (i=0;itmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ]; 111 | } 112 | 113 | FFTFWD(st->fftcfg,st->tmpbuf,st->fir_freq_resp); 114 | 115 | /* TODO: this won't work for fixed point */ 116 | scale = 1.0 / st->nfft; 117 | 118 | for ( i=0; i < st->n_freq_bins; ++i ) { 119 | #ifdef USE_SIMD 120 | st->fir_freq_resp[i].r *= _mm_set1_ps(scale); 121 | st->fir_freq_resp[i].i *= _mm_set1_ps(scale); 122 | #else 123 | st->fir_freq_resp[i].r *= scale; 124 | st->fir_freq_resp[i].i *= scale; 125 | #endif 126 | } 127 | return st; 128 | } 129 | 130 | static void fastconv1buf(const kiss_fastfir_cfg st,const kffsamp_t * in,kffsamp_t * out) 131 | { 132 | size_t i; 133 | /* multiply the frequency response of the input signal by 134 | that of the fir filter*/ 135 | FFTFWD( st->fftcfg, in , st->freqbuf ); 136 | for ( i=0; in_freq_bins; ++i ) { 137 | kiss_fft_cpx tmpsamp; 138 | C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]); 139 | st->freqbuf[i] = tmpsamp; 140 | } 141 | 142 | /* perform the inverse fft*/ 143 | FFTINV(st->ifftcfg,st->freqbuf,out); 144 | } 145 | 146 | /* n : the size of inbuf and outbuf in samples 147 | return value: the number of samples completely processed 148 | n-retval samples should be copied to the front of the next input buffer */ 149 | static size_t kff_nocopy( 150 | kiss_fastfir_cfg st, 151 | const kffsamp_t * inbuf, 152 | kffsamp_t * outbuf, 153 | size_t n) 154 | { 155 | size_t norig=n; 156 | while (n >= st->nfft ) { 157 | fastconv1buf(st,inbuf,outbuf); 158 | inbuf += st->ngood; 159 | outbuf += st->ngood; 160 | n -= st->ngood; 161 | } 162 | return norig - n; 163 | } 164 | 165 | static 166 | size_t kff_flush(kiss_fastfir_cfg st,const kffsamp_t * inbuf,kffsamp_t * outbuf,size_t n) 167 | { 168 | size_t zpad=0,ntmp; 169 | 170 | ntmp = kff_nocopy(st,inbuf,outbuf,n); 171 | n -= ntmp; 172 | inbuf += ntmp; 173 | outbuf += ntmp; 174 | 175 | zpad = st->nfft - n; 176 | memset(st->tmpbuf,0,sizeof(kffsamp_t)*st->nfft ); 177 | memcpy(st->tmpbuf,inbuf,sizeof(kffsamp_t)*n ); 178 | 179 | fastconv1buf(st,st->tmpbuf,st->tmpbuf); 180 | 181 | memcpy(outbuf,st->tmpbuf,sizeof(kffsamp_t)*( st->ngood - zpad )); 182 | return ntmp + st->ngood - zpad; 183 | } 184 | 185 | size_t kiss_fastfir( 186 | kiss_fastfir_cfg vst, 187 | kffsamp_t * inbuf, 188 | kffsamp_t * outbuf, 189 | size_t n_new, 190 | size_t *offset) 191 | { 192 | size_t ntot = n_new + *offset; 193 | if (n_new==0) { 194 | return kff_flush(vst,inbuf,outbuf,ntot); 195 | }else{ 196 | size_t nwritten = kff_nocopy(vst,inbuf,outbuf,ntot); 197 | *offset = ntot - nwritten; 198 | /*save the unused or underused samples at the front of the input buffer */ 199 | if(nwritten>0)memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kffsamp_t) ); 200 | return nwritten; 201 | } 202 | } 203 | 204 | #ifdef FAST_FILT_UTIL 205 | #include 206 | #include 207 | #include 208 | #include 209 | 210 | static 211 | void direct_file_filter( 212 | FILE * fin, 213 | FILE * fout, 214 | const kffsamp_t * imp_resp, 215 | size_t n_imp_resp) 216 | { 217 | size_t nlag = n_imp_resp - 1; 218 | 219 | const kffsamp_t *tmph; 220 | kffsamp_t *buf, *circbuf; 221 | kffsamp_t outval; 222 | size_t nread; 223 | size_t nbuf; 224 | size_t oldestlag = 0; 225 | size_t k, tap; 226 | #ifndef REAL_FASTFIR 227 | kffsamp_t tmp; 228 | #endif 229 | 230 | nbuf = 4096; 231 | buf = (kffsamp_t *) malloc ( sizeof (kffsamp_t) * nbuf); 232 | circbuf = (kffsamp_t *) malloc (sizeof (kffsamp_t) * nlag); 233 | if (!circbuf || !buf) { 234 | perror("circbuf allocation"); 235 | exit(1); 236 | } 237 | 238 | if ( fread (circbuf, sizeof (kffsamp_t), nlag, fin) != nlag ) { 239 | perror ("insufficient data to overcome transient"); 240 | exit (1); 241 | } 242 | 243 | do { 244 | nread = fread (buf, sizeof (kffsamp_t), nbuf, fin); 245 | if (nread <= 0) 246 | break; 247 | 248 | for (k = 0; k < nread; ++k) { 249 | tmph = imp_resp+nlag; 250 | #ifdef REAL_FASTFIR 251 | # ifdef USE_SIMD 252 | outval = _mm_set1_ps(0); 253 | #else 254 | outval = 0; 255 | #endif 256 | for (tap = oldestlag; tap < nlag; ++tap) 257 | outval += circbuf[tap] * *tmph--; 258 | for (tap = 0; tap < oldestlag; ++tap) 259 | outval += circbuf[tap] * *tmph--; 260 | outval += buf[k] * *tmph; 261 | #else 262 | # ifdef USE_SIMD 263 | outval.r = outval.i = _mm_set1_ps(0); 264 | #else 265 | outval.r = outval.i = 0; 266 | #endif 267 | for (tap = oldestlag; tap < nlag; ++tap){ 268 | C_MUL(tmp,circbuf[tap],*tmph); 269 | --tmph; 270 | C_ADDTO(outval,tmp); 271 | } 272 | 273 | for (tap = 0; tap < oldestlag; ++tap) { 274 | C_MUL(tmp,circbuf[tap],*tmph); 275 | --tmph; 276 | C_ADDTO(outval,tmp); 277 | } 278 | C_MUL(tmp,buf[k],*tmph); 279 | C_ADDTO(outval,tmp); 280 | #endif 281 | 282 | circbuf[oldestlag++] = buf[k]; 283 | buf[k] = outval; 284 | 285 | if (oldestlag == nlag) 286 | oldestlag = 0; 287 | } 288 | 289 | if (fwrite (buf, sizeof (buf[0]), nread, fout) != nread) { 290 | perror ("short write"); 291 | exit (1); 292 | } 293 | } while (nread); 294 | free (buf); 295 | free (circbuf); 296 | } 297 | 298 | static 299 | void do_file_filter( 300 | FILE * fin, 301 | FILE * fout, 302 | const kffsamp_t * imp_resp, 303 | size_t n_imp_resp, 304 | size_t nfft ) 305 | { 306 | int fdout; 307 | size_t n_samps_buf; 308 | 309 | kiss_fastfir_cfg cfg; 310 | kffsamp_t *inbuf,*outbuf; 311 | int nread,nwrite; 312 | size_t idx_inbuf; 313 | 314 | fdout = fileno(fout); 315 | 316 | cfg=kiss_fastfir_alloc(imp_resp,n_imp_resp,&nfft,0,0); 317 | 318 | /* use length to minimize buffer shift*/ 319 | n_samps_buf = 8*4096/sizeof(kffsamp_t); 320 | n_samps_buf = nfft + 4*(nfft-n_imp_resp+1); 321 | 322 | if (verbose) fprintf(stderr,"bufsize=%d\n",(int)(sizeof(kffsamp_t)*n_samps_buf) ); 323 | 324 | 325 | /*allocate space and initialize pointers */ 326 | inbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf); 327 | outbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf); 328 | 329 | idx_inbuf=0; 330 | do{ 331 | /* start reading at inbuf[idx_inbuf] */ 332 | nread = fread( inbuf + idx_inbuf, sizeof(kffsamp_t), n_samps_buf - idx_inbuf,fin ); 333 | 334 | /* If nread==0, then this is a flush. 335 | The total number of samples in input is idx_inbuf + nread . */ 336 | nwrite = kiss_fastfir(cfg, inbuf, outbuf,nread,&idx_inbuf) * sizeof(kffsamp_t); 337 | /* kiss_fastfir moved any unused samples to the front of inbuf and updated idx_inbuf */ 338 | 339 | if ( write(fdout, outbuf, nwrite) != nwrite ) { 340 | perror("short write"); 341 | exit(1); 342 | } 343 | }while ( nread ); 344 | free(cfg); 345 | free(inbuf); 346 | free(outbuf); 347 | } 348 | 349 | int main(int argc,char**argv) 350 | { 351 | kffsamp_t * h; 352 | int use_direct=0; 353 | size_t nh,nfft=0; 354 | FILE *fin=stdin; 355 | FILE *fout=stdout; 356 | FILE *filtfile=NULL; 357 | while (1) { 358 | int c=getopt(argc,argv,"n:h:i:o:vd"); 359 | if (c==-1) break; 360 | switch (c) { 361 | case 'v': 362 | verbose=1; 363 | break; 364 | case 'n': 365 | nfft=atoi(optarg); 366 | break; 367 | case 'i': 368 | fin = fopen(optarg,"rb"); 369 | if (fin==NULL) { 370 | perror(optarg); 371 | exit(1); 372 | } 373 | break; 374 | case 'o': 375 | fout = fopen(optarg,"w+b"); 376 | if (fout==NULL) { 377 | perror(optarg); 378 | exit(1); 379 | } 380 | break; 381 | case 'h': 382 | filtfile = fopen(optarg,"rb"); 383 | if (filtfile==NULL) { 384 | perror(optarg); 385 | exit(1); 386 | } 387 | break; 388 | case 'd': 389 | use_direct=1; 390 | break; 391 | case '?': 392 | fprintf(stderr,"usage options:\n" 393 | "\t-n nfft: fft size to use\n" 394 | "\t-d : use direct FIR filtering, not fast convolution\n" 395 | "\t-i filename: input file\n" 396 | "\t-o filename: output(filtered) file\n" 397 | "\t-n nfft: fft size to use\n" 398 | "\t-h filename: impulse response\n"); 399 | exit (1); 400 | default:fprintf(stderr,"bad %c\n",c);break; 401 | } 402 | } 403 | if (filtfile==NULL) { 404 | fprintf(stderr,"You must supply the FIR coeffs via -h\n"); 405 | exit(1); 406 | } 407 | fseek(filtfile,0,SEEK_END); 408 | nh = ftell(filtfile) / sizeof(kffsamp_t); 409 | if (verbose) fprintf(stderr,"%d samples in FIR filter\n",(int)nh); 410 | h = (kffsamp_t*)malloc(sizeof(kffsamp_t)*nh); 411 | fseek(filtfile,0,SEEK_SET); 412 | if (fread(h,sizeof(kffsamp_t),nh,filtfile) != nh) 413 | fprintf(stderr,"short read on filter file\n"); 414 | 415 | fclose(filtfile); 416 | 417 | if (use_direct) 418 | direct_file_filter( fin, fout, h,nh); 419 | else 420 | do_file_filter( fin, fout, h,nh,nfft); 421 | 422 | if (fout!=stdout) fclose(fout); 423 | if (fin!=stdin) fclose(fin); 424 | 425 | return 0; 426 | } 427 | #endif 428 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FASTFIR_H 2 | #define KISS_FASTFIR_H 3 | //moved header stuff from kiss_fastfir.c to here. crazy why it wasnt here in the first place 4 | //jonti 2015 5 | // 6 | 7 | #include "_kiss_fft_guts.h" 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* 14 | Some definitions that allow real or complex filtering 15 | */ 16 | #ifdef REAL_FASTFIR 17 | #define MIN_FFT_LEN 2048 18 | #include "kiss_fftr.h" 19 | typedef kiss_fft_scalar kffsamp_t; 20 | typedef kiss_fftr_cfg kfcfg_t; 21 | #define FFT_ALLOC kiss_fftr_alloc 22 | #define FFTFWD kiss_fftr 23 | #define FFTINV kiss_fftri 24 | #else 25 | #define MIN_FFT_LEN 1024 26 | typedef kiss_fft_cpx kffsamp_t; 27 | typedef kiss_fft_cfg kfcfg_t; 28 | #define FFT_ALLOC kiss_fft_alloc 29 | #define FFTFWD kiss_fft 30 | #define FFTINV kiss_fft 31 | #endif 32 | 33 | typedef struct kiss_fastfir_state *kiss_fastfir_cfg; 34 | 35 | 36 | 37 | kiss_fastfir_cfg kiss_fastfir_alloc(const kffsamp_t * imp_resp,size_t n_imp_resp, 38 | size_t * nfft,void * mem,size_t*lenmem); 39 | 40 | /* see do_file_filter for usage */ 41 | size_t kiss_fastfir( kiss_fastfir_cfg cfg, kffsamp_t * inbuf, kffsamp_t * outbuf, size_t n, size_t *offset); 42 | 43 | 44 | struct kiss_fastfir_state{ 45 | size_t nfft; 46 | size_t ngood; 47 | kfcfg_t fftcfg; 48 | kfcfg_t ifftcfg; 49 | kiss_fft_cpx * fir_freq_resp; 50 | kiss_fft_cpx * freqbuf; 51 | size_t n_freq_bins; 52 | kffsamp_t * tmpbuf; 53 | }; 54 | 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | #endif // KISS_FASTFIR_H 60 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir_complex.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "kiss_fastfir_complex.h" 16 | 17 | 18 | //TODO bring kissfft into the world of complex 19 | 20 | //static int verbose=0; 21 | 22 | 23 | kiss_fastfir_cfg_complex kiss_fastfir_alloc_complex( 24 | const kiss_fft_cpx * imp_resp,size_t n_imp_resp, 25 | size_t *pnfft, /* if <= 0, an appropriate size will be chosen */ 26 | void * mem,size_t*lenmem) 27 | { 28 | kiss_fastfir_cfg_complex st = NULL; 29 | size_t len_fftcfg,len_ifftcfg; 30 | size_t memneeded = sizeof(struct kiss_fastfir_state_complex); 31 | char * ptr; 32 | size_t i; 33 | size_t nfft=0; 34 | float scale; 35 | int n_freq_bins; 36 | if (pnfft) 37 | nfft=*pnfft; 38 | 39 | if (nfft<=0) { 40 | /* determine fft size as next power of two at least 2x 41 | the impulse response length*/ 42 | i=n_imp_resp-1; 43 | nfft=2; 44 | do{ 45 | nfft<<=1; 46 | }while (i>>=1); 47 | #ifdef MIN_FFT_LEN_COMPLEX 48 | if ( nfft < MIN_FFT_LEN_COMPLEX ) 49 | nfft=MIN_FFT_LEN_COMPLEX; 50 | #endif 51 | } 52 | if (pnfft) 53 | *pnfft = nfft; 54 | 55 | n_freq_bins = nfft; 56 | 57 | /*fftcfg*/ 58 | kiss_fft_alloc (nfft, 0, NULL, &len_fftcfg); 59 | memneeded += len_fftcfg; 60 | /*ifftcfg*/ 61 | kiss_fft_alloc (nfft, 1, NULL, &len_ifftcfg); 62 | memneeded += len_ifftcfg; 63 | /* tmpbuf */ 64 | memneeded += sizeof(kiss_fft_cpx) * nfft; 65 | /* fir_freq_resp */ 66 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 67 | /* freqbuf */ 68 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 69 | 70 | if (lenmem == NULL) { 71 | st = (kiss_fastfir_cfg_complex) malloc (memneeded); 72 | } else { 73 | if (*lenmem >= memneeded) 74 | st = (kiss_fastfir_cfg_complex) mem; 75 | *lenmem = memneeded; 76 | } 77 | if (!st) 78 | return NULL; 79 | 80 | st->nfft = nfft; 81 | st->ngood = nfft - n_imp_resp + 1; 82 | st->n_freq_bins = n_freq_bins; 83 | ptr=(char*)(st+1); 84 | 85 | st->fftcfg = (kiss_fft_cfg)ptr; 86 | ptr += len_fftcfg; 87 | 88 | st->ifftcfg = (kiss_fft_cfg)ptr; 89 | ptr += len_ifftcfg; 90 | 91 | st->tmpbuf = (kiss_fft_cpx*)ptr; 92 | ptr += sizeof(kiss_fft_cpx) * nfft; 93 | 94 | st->freqbuf = (kiss_fft_cpx*)ptr; 95 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 96 | 97 | st->fir_freq_resp = (kiss_fft_cpx*)ptr; 98 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 99 | 100 | kiss_fft_alloc (nfft,0,st->fftcfg , &len_fftcfg); 101 | kiss_fft_alloc (nfft,1,st->ifftcfg , &len_ifftcfg); 102 | 103 | memset(st->tmpbuf,0,sizeof(kiss_fft_cpx)*nfft); 104 | /*zero pad in the middle to left-rotate the impulse response 105 | This puts the scrap samples at the end of the inverse fft'd buffer */ 106 | st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ]; 107 | for (i=0;itmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ]; 109 | } 110 | 111 | kiss_fft(st->fftcfg,st->tmpbuf,st->fir_freq_resp); 112 | 113 | /* TODO: this won't work for fixed point */ 114 | scale = 1.0 / st->nfft; 115 | 116 | for ( i=0; i < st->n_freq_bins; ++i ) { 117 | #ifdef USE_SIMD 118 | st->fir_freq_resp[i].r *= _mm_set1_ps(scale); 119 | st->fir_freq_resp[i].i *= _mm_set1_ps(scale); 120 | #else 121 | st->fir_freq_resp[i].r *= scale; 122 | st->fir_freq_resp[i].i *= scale; 123 | #endif 124 | } 125 | return st; 126 | } 127 | 128 | static void fastconv1buf_complex(const kiss_fastfir_cfg_complex st,const kiss_fft_cpx * in,kiss_fft_cpx * out) 129 | { 130 | size_t i; 131 | /* multiply the frequency response of the input signal by 132 | that of the fir filter*/ 133 | kiss_fft( st->fftcfg, in , st->freqbuf ); 134 | for ( i=0; in_freq_bins; ++i ) { 135 | kiss_fft_cpx tmpsamp; 136 | C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]); 137 | st->freqbuf[i] = tmpsamp; 138 | } 139 | 140 | /* perform the inverse fft*/ 141 | kiss_fft(st->ifftcfg,st->freqbuf,out); 142 | } 143 | 144 | /* n : the size of inbuf and outbuf in samples 145 | return value: the number of samples completely processed 146 | n-retval samples should be copied to the front of the next input buffer */ 147 | static size_t kff_nocopy_complex( 148 | kiss_fastfir_cfg_complex st, 149 | const kiss_fft_cpx * inbuf, 150 | kiss_fft_cpx * outbuf, 151 | size_t n) 152 | { 153 | size_t norig=n; 154 | while (n >= st->nfft ) { 155 | fastconv1buf_complex(st,inbuf,outbuf); 156 | inbuf += st->ngood; 157 | outbuf += st->ngood; 158 | n -= st->ngood; 159 | } 160 | return norig - n; 161 | } 162 | 163 | static 164 | size_t kff_flush_complex(kiss_fastfir_cfg_complex st,const kiss_fft_cpx * inbuf,kiss_fft_cpx * outbuf,size_t n) 165 | { 166 | size_t zpad=0,ntmp; 167 | 168 | ntmp = kff_nocopy_complex(st,inbuf,outbuf,n); 169 | n -= ntmp; 170 | inbuf += ntmp; 171 | outbuf += ntmp; 172 | 173 | zpad = st->nfft - n; 174 | memset(st->tmpbuf,0,sizeof(kiss_fft_cpx)*st->nfft ); 175 | memcpy(st->tmpbuf,inbuf,sizeof(kiss_fft_cpx)*n ); 176 | 177 | fastconv1buf_complex(st,st->tmpbuf,st->tmpbuf); 178 | 179 | memcpy(outbuf,st->tmpbuf,sizeof(kiss_fft_cpx)*( st->ngood - zpad )); 180 | return ntmp + st->ngood - zpad; 181 | } 182 | 183 | size_t kiss_fastfir_complex( 184 | kiss_fastfir_cfg_complex vst, 185 | kiss_fft_cpx * inbuf, 186 | kiss_fft_cpx * outbuf, 187 | size_t n_new, 188 | size_t *offset) 189 | { 190 | size_t ntot = n_new + *offset; 191 | if (n_new==0) { 192 | return kff_flush_complex(vst,inbuf,outbuf,ntot); 193 | }else{ 194 | size_t nwritten = kff_nocopy_complex(vst,inbuf,outbuf,ntot); 195 | *offset = ntot - nwritten; 196 | /*save the unused or underused samples at the front of the input buffer */ 197 | if(nwritten>0)memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kiss_fft_cpx) ); 198 | return nwritten; 199 | } 200 | } 201 | 202 | 203 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir_complex.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FASTFIR_COMPLEX_H 2 | #define KISS_FASTFIR_COMPLEX_H 3 | //moved header stuff from kiss_fastfir.c to here. crazy why it wasnt here in the first place 4 | //jonti 2015 5 | // 6 | //made this complex fir so we can have both complex and real fast fir without having to choose one 7 | //jonti 2017 8 | 9 | #include "_kiss_fft_guts.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define MIN_FFT_LEN_COMPLEX 1024 16 | 17 | typedef struct kiss_fastfir_state_complex *kiss_fastfir_cfg_complex; 18 | 19 | kiss_fastfir_cfg_complex kiss_fastfir_alloc_complex(const kiss_fft_cpx * imp_resp,size_t n_imp_resp, 20 | size_t * nfft,void * mem,size_t*lenmem); 21 | 22 | /* see do_file_filter for usage */ 23 | size_t kiss_fastfir_complex( kiss_fastfir_cfg_complex cfg, kiss_fft_cpx * inbuf, kiss_fft_cpx * outbuf, size_t n, size_t *offset); 24 | 25 | 26 | struct kiss_fastfir_state_complex{ 27 | size_t nfft; 28 | size_t ngood; 29 | kiss_fft_cfg fftcfg; 30 | kiss_fft_cfg ifftcfg; 31 | kiss_fft_cpx * fir_freq_resp; 32 | kiss_fft_cpx * freqbuf; 33 | size_t n_freq_bins; 34 | kiss_fft_cpx * tmpbuf; 35 | }; 36 | 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | #endif // KISS_FASTFIR_COMPLEX_H 42 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir_real.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "kiss_fastfir_real.h" 16 | 17 | 18 | 19 | //static int verbose=0; 20 | 21 | 22 | kiss_fastfir_cfg_real kiss_fastfir_alloc_real( 23 | const kiss_fft_scalar * imp_resp,size_t n_imp_resp, 24 | size_t *pnfft, /* if <= 0, an appropriate size will be chosen */ 25 | void * mem,size_t*lenmem) 26 | { 27 | kiss_fastfir_cfg_real st = NULL; 28 | size_t len_fftcfg,len_ifftcfg; 29 | size_t memneeded = sizeof(struct kiss_fastfir_state_real); 30 | char * ptr; 31 | size_t i; 32 | size_t nfft=0; 33 | float scale; 34 | int n_freq_bins; 35 | if (pnfft) 36 | nfft=*pnfft; 37 | 38 | if (nfft<=0) { 39 | /* determine fft size as next power of two at least 2x 40 | the impulse response length*/ 41 | i=n_imp_resp-1; 42 | nfft=2; 43 | do{ 44 | nfft<<=1; 45 | }while (i>>=1); 46 | #ifdef MIN_FFT_LEN_REAL 47 | if ( nfft < MIN_FFT_LEN_REAL ) 48 | nfft=MIN_FFT_LEN_REAL; 49 | #endif 50 | } 51 | if (pnfft) 52 | *pnfft = nfft; 53 | 54 | n_freq_bins = nfft/2 + 1; 55 | 56 | /*fftcfg*/ 57 | kiss_fftr_alloc (nfft, 0, NULL, &len_fftcfg); 58 | memneeded += len_fftcfg; 59 | /*ifftcfg*/ 60 | kiss_fftr_alloc (nfft, 1, NULL, &len_ifftcfg); 61 | memneeded += len_ifftcfg; 62 | /* tmpbuf */ 63 | memneeded += sizeof(kiss_fft_scalar) * nfft; 64 | /* fir_freq_resp */ 65 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 66 | /* freqbuf */ 67 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 68 | 69 | if (lenmem == NULL) { 70 | st = (kiss_fastfir_cfg_real) malloc (memneeded); 71 | } else { 72 | if (*lenmem >= memneeded) 73 | st = (kiss_fastfir_cfg_real) mem; 74 | *lenmem = memneeded; 75 | } 76 | if (!st) 77 | return NULL; 78 | 79 | st->nfft = nfft; 80 | st->ngood = nfft - n_imp_resp + 1; 81 | st->n_freq_bins = n_freq_bins; 82 | ptr=(char*)(st+1); 83 | 84 | st->fftcfg = (kiss_fftr_cfg)ptr; 85 | ptr += len_fftcfg; 86 | 87 | st->ifftcfg = (kiss_fftr_cfg)ptr; 88 | ptr += len_ifftcfg; 89 | 90 | st->tmpbuf = (kiss_fft_scalar*)ptr; 91 | ptr += sizeof(kiss_fft_scalar) * nfft; 92 | 93 | st->freqbuf = (kiss_fft_cpx*)ptr; 94 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 95 | 96 | st->fir_freq_resp = (kiss_fft_cpx*)ptr; 97 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 98 | 99 | kiss_fftr_alloc (nfft,0,st->fftcfg , &len_fftcfg); 100 | kiss_fftr_alloc (nfft,1,st->ifftcfg , &len_ifftcfg); 101 | 102 | memset(st->tmpbuf,0,sizeof(kiss_fft_scalar)*nfft); 103 | /*zero pad in the middle to left-rotate the impulse response 104 | This puts the scrap samples at the end of the inverse fft'd buffer */ 105 | st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ]; 106 | for (i=0;itmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ]; 108 | } 109 | 110 | kiss_fftr(st->fftcfg,st->tmpbuf,st->fir_freq_resp); 111 | 112 | /* TODO: this won't work for fixed point */ 113 | scale = 1.0 / st->nfft; 114 | 115 | for ( i=0; i < st->n_freq_bins; ++i ) { 116 | #ifdef USE_SIMD 117 | st->fir_freq_resp[i].r *= _mm_set1_ps(scale); 118 | st->fir_freq_resp[i].i *= _mm_set1_ps(scale); 119 | #else 120 | st->fir_freq_resp[i].r *= scale; 121 | st->fir_freq_resp[i].i *= scale; 122 | #endif 123 | } 124 | return st; 125 | } 126 | 127 | static void fastconv1buf_real(const kiss_fastfir_cfg_real st,const kiss_fft_scalar * in,kiss_fft_scalar * out) 128 | { 129 | size_t i; 130 | /* multiply the frequency response of the input signal by 131 | that of the fir filter*/ 132 | kiss_fftr( st->fftcfg, in , st->freqbuf ); 133 | for ( i=0; in_freq_bins; ++i ) { 134 | kiss_fft_cpx tmpsamp; 135 | C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]); 136 | st->freqbuf[i] = tmpsamp; 137 | } 138 | 139 | /* perform the inverse fft*/ 140 | kiss_fftri(st->ifftcfg,st->freqbuf,out); 141 | } 142 | 143 | /* n : the size of inbuf and outbuf in samples 144 | return value: the number of samples completely processed 145 | n-retval samples should be copied to the front of the next input buffer */ 146 | static size_t kff_nocopy_real( 147 | kiss_fastfir_cfg_real st, 148 | const kiss_fft_scalar * inbuf, 149 | kiss_fft_scalar * outbuf, 150 | size_t n) 151 | { 152 | size_t norig=n; 153 | while (n >= st->nfft ) { 154 | fastconv1buf_real(st,inbuf,outbuf); 155 | inbuf += st->ngood; 156 | outbuf += st->ngood; 157 | n -= st->ngood; 158 | } 159 | return norig - n; 160 | } 161 | 162 | static 163 | size_t kff_flush_real(kiss_fastfir_cfg_real st,const kiss_fft_scalar * inbuf,kiss_fft_scalar * outbuf,size_t n) 164 | { 165 | size_t zpad=0,ntmp; 166 | 167 | ntmp = kff_nocopy_real(st,inbuf,outbuf,n); 168 | n -= ntmp; 169 | inbuf += ntmp; 170 | outbuf += ntmp; 171 | 172 | zpad = st->nfft - n; 173 | memset(st->tmpbuf,0,sizeof(kiss_fft_scalar)*st->nfft ); 174 | memcpy(st->tmpbuf,inbuf,sizeof(kiss_fft_scalar)*n ); 175 | 176 | fastconv1buf_real(st,st->tmpbuf,st->tmpbuf); 177 | 178 | memcpy(outbuf,st->tmpbuf,sizeof(kiss_fft_scalar)*( st->ngood - zpad )); 179 | return ntmp + st->ngood - zpad; 180 | } 181 | 182 | size_t kiss_fastfir_real( 183 | kiss_fastfir_cfg_real vst, 184 | kiss_fft_scalar * inbuf, 185 | kiss_fft_scalar * outbuf, 186 | size_t n_new, 187 | size_t *offset) 188 | { 189 | size_t ntot = n_new + *offset; 190 | if (n_new==0) { 191 | return kff_flush_real(vst,inbuf,outbuf,ntot); 192 | }else{ 193 | size_t nwritten = kff_nocopy_real(vst,inbuf,outbuf,ntot); 194 | *offset = ntot - nwritten; 195 | /*save the unused or underused samples at the front of the input buffer */ 196 | if(nwritten>0)memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kiss_fft_scalar) ); 197 | return nwritten; 198 | } 199 | } 200 | 201 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fastfir_real.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FASTFIR_REAL_H 2 | #define KISS_FASTFIR_REAL_H 3 | //moved header stuff from kiss_fastfir.c to here. crazy why it wasnt here in the first place 4 | //jonti 2015 5 | // 6 | //made this real fir so we can have both complex and real fast fir without having to choose one 7 | //jonti 2017 8 | 9 | #include "_kiss_fft_guts.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define MIN_FFT_LEN_REAL 2048 16 | #include "kiss_fftr.h" 17 | 18 | typedef struct kiss_fastfir_state_real *kiss_fastfir_cfg_real; 19 | 20 | kiss_fastfir_cfg_real kiss_fastfir_alloc_real(const kiss_fft_scalar * imp_resp,size_t n_imp_resp, 21 | size_t * nfft,void * mem,size_t*lenmem); 22 | 23 | /* see do_file_filter for usage */ 24 | size_t kiss_fastfir_real( kiss_fastfir_cfg_real cfg, kiss_fft_scalar * inbuf, kiss_fft_scalar * outbuf, size_t n, size_t *offset); 25 | 26 | 27 | struct kiss_fastfir_state_real{ 28 | size_t nfft; 29 | size_t ngood; 30 | kiss_fftr_cfg fftcfg; 31 | kiss_fftr_cfg ifftcfg; 32 | kiss_fft_cpx * fir_freq_resp; 33 | kiss_fft_cpx * freqbuf; 34 | size_t n_freq_bins; 35 | kiss_fft_scalar * tmpbuf; 36 | }; 37 | 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | #endif // KISS_FASTFIR_REAL_H 43 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fft.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2010, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | 16 | #include "_kiss_fft_guts.h" 17 | /* The guts header contains all the multiplication and addition macros that are defined for 18 | fixed or floating point complex numbers. It also delares the kf_ internal functions. 19 | */ 20 | 21 | static void kf_bfly2( 22 | kiss_fft_cpx * Fout, 23 | const size_t fstride, 24 | const kiss_fft_cfg st, 25 | int m 26 | ) 27 | { 28 | kiss_fft_cpx * Fout2; 29 | kiss_fft_cpx * tw1 = st->twiddles; 30 | kiss_fft_cpx t; 31 | Fout2 = Fout + m; 32 | do{ 33 | C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); 34 | 35 | C_MUL (t, *Fout2 , *tw1); 36 | tw1 += fstride; 37 | C_SUB( *Fout2 , *Fout , t ); 38 | C_ADDTO( *Fout , t ); 39 | ++Fout2; 40 | ++Fout; 41 | }while (--m); 42 | } 43 | 44 | static void kf_bfly4( 45 | kiss_fft_cpx * Fout, 46 | const size_t fstride, 47 | const kiss_fft_cfg st, 48 | const size_t m 49 | ) 50 | { 51 | kiss_fft_cpx *tw1,*tw2,*tw3; 52 | kiss_fft_cpx scratch[6]; 53 | size_t k=m; 54 | const size_t m2=2*m; 55 | const size_t m3=3*m; 56 | 57 | 58 | tw3 = tw2 = tw1 = st->twiddles; 59 | 60 | do { 61 | C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); 62 | 63 | C_MUL(scratch[0],Fout[m] , *tw1 ); 64 | C_MUL(scratch[1],Fout[m2] , *tw2 ); 65 | C_MUL(scratch[2],Fout[m3] , *tw3 ); 66 | 67 | C_SUB( scratch[5] , *Fout, scratch[1] ); 68 | C_ADDTO(*Fout, scratch[1]); 69 | C_ADD( scratch[3] , scratch[0] , scratch[2] ); 70 | C_SUB( scratch[4] , scratch[0] , scratch[2] ); 71 | C_SUB( Fout[m2], *Fout, scratch[3] ); 72 | tw1 += fstride; 73 | tw2 += fstride*2; 74 | tw3 += fstride*3; 75 | C_ADDTO( *Fout , scratch[3] ); 76 | 77 | if(st->inverse) { 78 | Fout[m].r = scratch[5].r - scratch[4].i; 79 | Fout[m].i = scratch[5].i + scratch[4].r; 80 | Fout[m3].r = scratch[5].r + scratch[4].i; 81 | Fout[m3].i = scratch[5].i - scratch[4].r; 82 | }else{ 83 | Fout[m].r = scratch[5].r + scratch[4].i; 84 | Fout[m].i = scratch[5].i - scratch[4].r; 85 | Fout[m3].r = scratch[5].r - scratch[4].i; 86 | Fout[m3].i = scratch[5].i + scratch[4].r; 87 | } 88 | ++Fout; 89 | }while(--k); 90 | } 91 | 92 | static void kf_bfly3( 93 | kiss_fft_cpx * Fout, 94 | const size_t fstride, 95 | const kiss_fft_cfg st, 96 | size_t m 97 | ) 98 | { 99 | size_t k=m; 100 | const size_t m2 = 2*m; 101 | kiss_fft_cpx *tw1,*tw2; 102 | kiss_fft_cpx scratch[5]; 103 | kiss_fft_cpx epi3; 104 | epi3 = st->twiddles[fstride*m]; 105 | 106 | tw1=tw2=st->twiddles; 107 | 108 | do{ 109 | C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); 110 | 111 | C_MUL(scratch[1],Fout[m] , *tw1); 112 | C_MUL(scratch[2],Fout[m2] , *tw2); 113 | 114 | C_ADD(scratch[3],scratch[1],scratch[2]); 115 | C_SUB(scratch[0],scratch[1],scratch[2]); 116 | tw1 += fstride; 117 | tw2 += fstride*2; 118 | 119 | Fout[m].r = Fout->r - HALF_OF(scratch[3].r); 120 | Fout[m].i = Fout->i - HALF_OF(scratch[3].i); 121 | 122 | C_MULBYSCALAR( scratch[0] , epi3.i ); 123 | 124 | C_ADDTO(*Fout,scratch[3]); 125 | 126 | Fout[m2].r = Fout[m].r + scratch[0].i; 127 | Fout[m2].i = Fout[m].i - scratch[0].r; 128 | 129 | Fout[m].r -= scratch[0].i; 130 | Fout[m].i += scratch[0].r; 131 | 132 | ++Fout; 133 | }while(--k); 134 | } 135 | 136 | static void kf_bfly5( 137 | kiss_fft_cpx * Fout, 138 | const size_t fstride, 139 | const kiss_fft_cfg st, 140 | int m 141 | ) 142 | { 143 | kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; 144 | int u; 145 | kiss_fft_cpx scratch[13]; 146 | kiss_fft_cpx * twiddles = st->twiddles; 147 | kiss_fft_cpx *tw; 148 | kiss_fft_cpx ya,yb; 149 | ya = twiddles[fstride*m]; 150 | yb = twiddles[fstride*2*m]; 151 | 152 | Fout0=Fout; 153 | Fout1=Fout0+m; 154 | Fout2=Fout0+2*m; 155 | Fout3=Fout0+3*m; 156 | Fout4=Fout0+4*m; 157 | 158 | tw=st->twiddles; 159 | for ( u=0; ur += scratch[7].r + scratch[8].r; 174 | Fout0->i += scratch[7].i + scratch[8].i; 175 | 176 | scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); 177 | scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); 178 | 179 | scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); 180 | scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); 181 | 182 | C_SUB(*Fout1,scratch[5],scratch[6]); 183 | C_ADD(*Fout4,scratch[5],scratch[6]); 184 | 185 | scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); 186 | scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); 187 | scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); 188 | scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); 189 | 190 | C_ADD(*Fout2,scratch[11],scratch[12]); 191 | C_SUB(*Fout3,scratch[11],scratch[12]); 192 | 193 | ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; 194 | } 195 | } 196 | 197 | /* perform the butterfly for one stage of a mixed radix FFT */ 198 | static void kf_bfly_generic( 199 | kiss_fft_cpx * Fout, 200 | const size_t fstride, 201 | const kiss_fft_cfg st, 202 | int m, 203 | int p 204 | ) 205 | { 206 | int u,k,q1,q; 207 | kiss_fft_cpx * twiddles = st->twiddles; 208 | kiss_fft_cpx t; 209 | int Norig = st->nfft; 210 | 211 | kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); 212 | 213 | for ( u=0; u=Norig) twidx-=Norig; 228 | C_MUL(t,scratch[q] , twiddles[twidx] ); 229 | C_ADDTO( Fout[ k ] ,t); 230 | } 231 | k += m; 232 | } 233 | } 234 | KISS_FFT_TMP_FREE(scratch); 235 | } 236 | 237 | static 238 | void kf_work( 239 | kiss_fft_cpx * Fout, 240 | const kiss_fft_cpx * f, 241 | const size_t fstride, 242 | int in_stride, 243 | int * factors, 244 | const kiss_fft_cfg st 245 | ) 246 | { 247 | kiss_fft_cpx * Fout_beg=Fout; 248 | const int p=*factors++; /* the radix */ 249 | const int m=*factors++; /* stage's fft length/p */ 250 | const kiss_fft_cpx * Fout_end = Fout + p*m; 251 | 252 | #ifdef _OPENMP 253 | // use openmp extensions at the 254 | // top-level (not recursive) 255 | if (fstride==1 && p<=5) 256 | { 257 | int k; 258 | 259 | // execute the p different work units in different threads 260 | # pragma omp parallel for 261 | for (k=0;k floor_sqrt) 324 | p = n; /* no more factors, skip to end */ 325 | } 326 | n /= p; 327 | *facbuf++ = p; 328 | *facbuf++ = n; 329 | } while (n > 1); 330 | } 331 | 332 | /* 333 | * 334 | * User-callable function to allocate all necessary storage space for the fft. 335 | * 336 | * The return value is a contiguous block of memory, allocated with malloc. As such, 337 | * It can be freed with free(), rather than a kiss_fft-specific function. 338 | * */ 339 | kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) 340 | { 341 | kiss_fft_cfg st=NULL; 342 | size_t memneeded = sizeof(struct kiss_fft_state) 343 | + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ 344 | 345 | if ( lenmem==NULL ) { 346 | st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); 347 | }else{ 348 | if (mem != NULL && *lenmem >= memneeded) 349 | st = (kiss_fft_cfg)mem; 350 | *lenmem = memneeded; 351 | } 352 | if (st) { 353 | int i; 354 | st->nfft=nfft; 355 | st->inverse = inverse_fft; 356 | 357 | for (i=0;iinverse) 361 | phase *= -1; 362 | kf_cexp(st->twiddles+i, phase ); 363 | } 364 | 365 | kf_factor(nfft,st->factors); 366 | } 367 | return st; 368 | } 369 | 370 | 371 | void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) 372 | { 373 | if (fin == fout) { 374 | //NOTE: this is not really an in-place FFT algorithm. 375 | //It just performs an out-of-place FFT into a temp buffer 376 | kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); 377 | kf_work(tmpbuf,fin,1,in_stride, st->factors,st); 378 | memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); 379 | KISS_FFT_TMP_FREE(tmpbuf); 380 | }else{ 381 | kf_work( fout, fin, 1,in_stride, st->factors,st ); 382 | } 383 | } 384 | 385 | void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) 386 | { 387 | kiss_fft_stride(cfg,fin,fout,1); 388 | } 389 | 390 | 391 | void kiss_fft_cleanup(void) 392 | { 393 | // nothing needed any more 394 | } 395 | 396 | int kiss_fft_next_fast_size(int n) 397 | { 398 | while(1) { 399 | int m=n; 400 | while ( (m%2) == 0 ) m/=2; 401 | while ( (m%3) == 0 ) m/=3; 402 | while ( (m%5) == 0 ) m/=5; 403 | if (m<=1) 404 | break; /* n is completely factorable by twos, threes, and fives */ 405 | n++; 406 | } 407 | return n; 408 | } 409 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fft.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FFT_H 2 | #define KISS_FFT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* 14 | ATTENTION! 15 | If you would like a : 16 | -- a utility that will handle the caching of fft objects 17 | -- real-only (no imaginary time component ) FFT 18 | -- a multi-dimensional FFT 19 | -- a command-line utility to perform ffts 20 | -- a command-line utility to perform fast-convolution filtering 21 | 22 | Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c 23 | in the tools/ directory. 24 | */ 25 | 26 | #ifdef USE_SIMD 27 | # include 28 | # define kiss_fft_scalar __m128 29 | #define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) 30 | #define KISS_FFT_FREE _mm_free 31 | #else 32 | #define KISS_FFT_MALLOC malloc 33 | #define KISS_FFT_FREE free 34 | #endif 35 | 36 | 37 | #ifdef FIXED_POINT 38 | #include 39 | # if (FIXED_POINT == 32) 40 | # define kiss_fft_scalar int32_t 41 | # else 42 | # define kiss_fft_scalar int16_t 43 | # endif 44 | #else 45 | # ifndef kiss_fft_scalar 46 | /* default is float */ 47 | # define kiss_fft_scalar float 48 | # endif 49 | #endif 50 | 51 | typedef struct { 52 | kiss_fft_scalar r; 53 | kiss_fft_scalar i; 54 | }kiss_fft_cpx; 55 | 56 | typedef struct kiss_fft_state* kiss_fft_cfg; 57 | 58 | /* 59 | * kiss_fft_alloc 60 | * 61 | * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. 62 | * 63 | * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); 64 | * 65 | * The return value from fft_alloc is a cfg buffer used internally 66 | * by the fft routine or NULL. 67 | * 68 | * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. 69 | * The returned value should be free()d when done to avoid memory leaks. 70 | * 71 | * The state can be placed in a user supplied buffer 'mem': 72 | * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, 73 | * then the function places the cfg in mem and the size used in *lenmem 74 | * and returns mem. 75 | * 76 | * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), 77 | * then the function returns NULL and places the minimum cfg 78 | * buffer size in *lenmem. 79 | * */ 80 | 81 | kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); 82 | 83 | /* 84 | * kiss_fft(cfg,in_out_buf) 85 | * 86 | * Perform an FFT on a complex input buffer. 87 | * for a forward FFT, 88 | * fin should be f[0] , f[1] , ... ,f[nfft-1] 89 | * fout will be F[0] , F[1] , ... ,F[nfft-1] 90 | * Note that each element is complex and can be accessed like 91 | f[k].r and f[k].i 92 | * */ 93 | void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); 94 | 95 | /* 96 | A more generic version of the above function. It reads its input from every Nth sample. 97 | * */ 98 | void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); 99 | 100 | /* If kiss_fft_alloc allocated a buffer, it is one contiguous 101 | buffer and can be simply free()d when no longer needed*/ 102 | #define kiss_fft_free free 103 | 104 | /* 105 | Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up 106 | your compiler output to call this before you exit. 107 | */ 108 | void kiss_fft_cleanup(void); 109 | 110 | 111 | /* 112 | * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) 113 | */ 114 | int kiss_fft_next_fast_size(int n); 115 | 116 | /* for real ffts, we need an even size */ 117 | #define kiss_fftr_next_fast_size_real(n) \ 118 | (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fftr.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "kiss_fftr.h" 16 | #include "_kiss_fft_guts.h" 17 | 18 | struct kiss_fftr_state{ 19 | kiss_fft_cfg substate; 20 | kiss_fft_cpx * tmpbuf; 21 | kiss_fft_cpx * super_twiddles; 22 | #ifdef USE_SIMD 23 | void * pad; 24 | #endif 25 | }; 26 | 27 | kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) 28 | { 29 | int i; 30 | kiss_fftr_cfg st = NULL; 31 | size_t subsize, memneeded; 32 | 33 | if (nfft & 1) { 34 | fprintf(stderr,"Real FFT optimization must be even.\n"); 35 | return NULL; 36 | } 37 | nfft >>= 1; 38 | 39 | kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); 40 | memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2); 41 | 42 | if (lenmem == NULL) { 43 | st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); 44 | } else { 45 | if (*lenmem >= memneeded) 46 | st = (kiss_fftr_cfg) mem; 47 | *lenmem = memneeded; 48 | } 49 | if (!st) 50 | return NULL; 51 | 52 | st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ 53 | st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); 54 | st->super_twiddles = st->tmpbuf + nfft; 55 | kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); 56 | 57 | for (i = 0; i < nfft/2; ++i) { 58 | double phase = 59 | -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); 60 | if (inverse_fft) 61 | phase *= -1; 62 | kf_cexp (st->super_twiddles+i,phase); 63 | } 64 | return st; 65 | } 66 | 67 | void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) 68 | { 69 | /* input buffer timedata is stored row-wise */ 70 | int k,ncfft; 71 | kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; 72 | 73 | if ( st->substate->inverse) { 74 | fprintf(stderr,"kiss fft usage error: improper alloc\n"); 75 | exit(1); 76 | } 77 | 78 | ncfft = st->substate->nfft; 79 | 80 | /*perform the parallel fft of two real signals packed in real,imag*/ 81 | kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); 82 | /* The real part of the DC element of the frequency spectrum in st->tmpbuf 83 | * contains the sum of the even-numbered elements of the input time sequence 84 | * The imag part is the sum of the odd-numbered elements 85 | * 86 | * The sum of tdc.r and tdc.i is the sum of the input time sequence. 87 | * yielding DC of input time sequence 88 | * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... 89 | * yielding Nyquist bin of input time sequence 90 | */ 91 | 92 | tdc.r = st->tmpbuf[0].r; 93 | tdc.i = st->tmpbuf[0].i; 94 | C_FIXDIV(tdc,2); 95 | CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); 96 | CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); 97 | freqdata[0].r = tdc.r + tdc.i; 98 | freqdata[ncfft].r = tdc.r - tdc.i; 99 | #ifdef USE_SIMD 100 | freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); 101 | #else 102 | freqdata[ncfft].i = freqdata[0].i = 0; 103 | #endif 104 | 105 | for ( k=1;k <= ncfft/2 ; ++k ) { 106 | fpk = st->tmpbuf[k]; 107 | fpnk.r = st->tmpbuf[ncfft-k].r; 108 | fpnk.i = - st->tmpbuf[ncfft-k].i; 109 | C_FIXDIV(fpk,2); 110 | C_FIXDIV(fpnk,2); 111 | 112 | C_ADD( f1k, fpk , fpnk ); 113 | C_SUB( f2k, fpk , fpnk ); 114 | C_MUL( tw , f2k , st->super_twiddles[k-1]); 115 | 116 | freqdata[k].r = HALF_OF(f1k.r + tw.r); 117 | freqdata[k].i = HALF_OF(f1k.i + tw.i); 118 | freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); 119 | freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); 120 | } 121 | } 122 | 123 | void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) 124 | { 125 | /* input buffer timedata is stored row-wise */ 126 | int k, ncfft; 127 | 128 | if (st->substate->inverse == 0) { 129 | fprintf (stderr, "kiss fft usage error: improper alloc\n"); 130 | exit (1); 131 | } 132 | 133 | ncfft = st->substate->nfft; 134 | 135 | st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; 136 | st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; 137 | C_FIXDIV(st->tmpbuf[0],2); 138 | 139 | for (k = 1; k <= ncfft / 2; ++k) { 140 | kiss_fft_cpx fk, fnkc, fek, fok, tmp; 141 | fk = freqdata[k]; 142 | fnkc.r = freqdata[ncfft - k].r; 143 | fnkc.i = -freqdata[ncfft - k].i; 144 | C_FIXDIV( fk , 2 ); 145 | C_FIXDIV( fnkc , 2 ); 146 | 147 | C_ADD (fek, fk, fnkc); 148 | C_SUB (tmp, fk, fnkc); 149 | C_MUL (fok, tmp, st->super_twiddles[k-1]); 150 | C_ADD (st->tmpbuf[k], fek, fok); 151 | C_SUB (st->tmpbuf[ncfft - k], fek, fok); 152 | #ifdef USE_SIMD 153 | st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); 154 | #else 155 | st->tmpbuf[ncfft - k].i *= -1; 156 | #endif 157 | } 158 | kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); 159 | } 160 | -------------------------------------------------------------------------------- /kiss_fft130/kiss_fftr.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FTR_H 2 | #define KISS_FTR_H 3 | 4 | #include "kiss_fft.h" 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | 10 | /* 11 | 12 | Real optimized version can save about 45% cpu time vs. complex fft of a real seq. 13 | 14 | 15 | 16 | */ 17 | 18 | typedef struct kiss_fftr_state *kiss_fftr_cfg; 19 | 20 | 21 | kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); 22 | /* 23 | nfft must be even 24 | 25 | If you don't care to allocate space, use mem = lenmem = NULL 26 | */ 27 | 28 | 29 | void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); 30 | /* 31 | input timedata has nfft scalar points 32 | output freqdata has nfft/2+1 complex points 33 | */ 34 | 35 | void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); 36 | /* 37 | input freqdata has nfft/2+1 complex points 38 | output timedata has nfft scalar points 39 | */ 40 | 41 | #define kiss_fftr_free free 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | #endif 47 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | QString MainWindow::settings_filename; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | QApplication a(argc, argv); 12 | 13 | QApplication::setApplicationName("SDRReceiver"); 14 | QApplication::setApplicationVersion("1.0"); 15 | 16 | QCommandLineParser cmdparser; 17 | cmdparser.setApplicationDescription("SDR Receiver for JAERO"); 18 | cmdparser.addHelpOption(); 19 | cmdparser.addVersionOption(); 20 | 21 | // ini file option (-s) 22 | QCommandLineOption settingsnameoption(QStringList() << "s" << "settings-filename",QApplication::translate("main", "Run with setting file name ."),QApplication::translate("main", "name")); 23 | settingsnameoption.setDefaultValue(""); 24 | cmdparser.addOption(settingsnameoption); 25 | cmdparser.process(a); 26 | 27 | if(a.arguments().size()<=1) 28 | { 29 | fprintf(stderr, "%s\n", qPrintable(QCoreApplication::translate("main", "Error: Must specify an argument."))); 30 | cmdparser.showHelp(1); 31 | } 32 | 33 | MainWindow::settings_filename=cmdparser.value(settingsnameoption); 34 | MainWindow w; 35 | w.setWindowTitle("SDRReceiver - " + MainWindow::settings_filename ); 36 | w.show(); 37 | return a.exec(); 38 | } 39 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | #include 4 | #include 5 | #include 6 | 7 | MainWindow::MainWindow(QWidget *parent) 8 | : QMainWindow(parent) 9 | , ui(new Ui::MainWindow) 10 | { 11 | 12 | biasT = false; 13 | tuner_gain = 496; 14 | bool dc = false; 15 | usb = false; 16 | enableFFT=true; 17 | 18 | QFileInfo fileinfo(settings_filename); 19 | if(!fileinfo.exists()||!fileinfo.isFile()) 20 | { 21 | QMessageBox msgBox; 22 | msgBox.setText("Given settings ini file doesn't exist"); 23 | msgBox.exec(); 24 | exit(1); 25 | } 26 | 27 | QSettings settings(settings_filename, QSettings::IniFormat); 28 | 29 | Fs = settings.value("sample_rate").toInt(); 30 | 31 | if(Fs == 0) 32 | { 33 | QMessageBox msgBox; 34 | msgBox.setText("sample_rate ini file key not found or equal to zero, check ini file name and key values"); 35 | msgBox.exec(); 36 | exit(1); 37 | } 38 | 39 | if(!supportedRTLSDRSampleRates.contains(Fs)) 40 | { 41 | QMessageBox msgBox; 42 | QString tmpstr;for(int i=0;i 0) 71 | { 72 | 73 | buflen = int((2*Fs)/5); 74 | bufsplit = 5; 75 | } 76 | else 77 | { 78 | 79 | buflen = int((2*Fs)/4); 80 | } 81 | 82 | 83 | if(gain > 0) 84 | { 85 | 86 | tuner_gain=gain; 87 | } 88 | if(remote_gain_idx > 0) 89 | { 90 | 91 | tuner_gain_idx=remote_gain_idx; 92 | } 93 | 94 | QString zmq_address = settings.value("zmq_address").toString(); 95 | 96 | dc = settings.value("correct_dc_bias").toString() == "1" ? true : false; 97 | 98 | int msize = settings.beginReadArray("main_vfos"); 99 | 100 | // Read main vfos 101 | for (int i = 0; i < msize; ++i) { 102 | 103 | settings.setArrayIndex(i); 104 | 105 | vfo * pVFO = new vfo(); 106 | int vfo_freq = settings.value("frequency").toInt(); 107 | int vfo_out_rate = settings.value("out_rate").toInt(); 108 | 109 | QString output_connect = settings.value("zmq_address").toString(); 110 | QString out_topic = settings.value("zmq_topic").toString(); 111 | 112 | int compscale = settings.value("compress_scale").toInt(); 113 | 114 | if(compscale > 0) 115 | { 116 | 117 | pVFO->setScaleComp(compscale); 118 | } 119 | 120 | if(output_connect != "" && out_topic != "") 121 | { 122 | 123 | pVFO->setZmqAddress(output_connect); 124 | pVFO->setZmqTopic(out_topic); 125 | 126 | } 127 | 128 | 129 | pVFO->setFs(Fs); 130 | pVFO->setDecimationCount(Fs/vfo_out_rate == 1 ? 0 : int(log2(Fs/vfo_out_rate))); 131 | pVFO->setMixerFreq(center_frequency - vfo_freq); 132 | pVFO->setDemodUSB(false); 133 | pVFO->setCompressonStyle(1); 134 | pVFO->init(buflen/2, false); 135 | pVFO->setVFOs(&VFOsub[i]); 136 | VFOmain.push_back(pVFO); 137 | 138 | } 139 | 140 | settings.endArray(); 141 | int size = settings.beginReadArray("vfos"); 142 | nVFO = size; 143 | vfo_str.push_back("Main"); 144 | 145 | // read regular vfos 146 | for (int i = 0; i < size; ++i) { 147 | 148 | settings.setArrayIndex(i); 149 | 150 | vfo * pVFO = new vfo(); 151 | int vfo_freq = settings.value("frequency").toInt() + mix_offset; 152 | int data_rate = settings.value("data_rate").toInt(); 153 | int out_rate = settings.value("out_rate").toInt(); 154 | 155 | if(out_rate == 0 && data_rate > 0) 156 | { 157 | 158 | switch(data_rate){ 159 | 160 | case 600: 161 | out_rate = 12000; 162 | break; 163 | case 1200: 164 | out_rate = 24000; 165 | break; 166 | default: 167 | out_rate = 48000; 168 | break; 169 | 170 | } 171 | } 172 | 173 | int filterbw=settings.value("filter_bandwidth").toInt(); 174 | int main_vfo_freq = 0; 175 | int main_vfo_out_rate = Fs; 176 | int main_idx = 0; 177 | 178 | // find main VFO 179 | for(int a = 0; agetMixerFreq())-vfo_freq); 183 | if(diff < VFOmain.at(a)->getOutRate() && !VFOmain.at(a)->getDemodUSB() ) 184 | { 185 | main_idx=a; 186 | main_vfo_freq=VFOmain.at(a)->getMixerFreq(); 187 | main_vfo_out_rate=VFOmain.at(a)->getOutRate(); 188 | break; 189 | } 190 | 191 | } 192 | 193 | pVFO->setZmqTopic(settings.value("topic").toString()); 194 | pVFO->setZmqAddress(zmq_address); 195 | 196 | int lateDecimate = 0; 197 | if((main_vfo_out_rate/48000)==5) 198 | { 199 | 200 | pVFO->setDecimationCount(int(log2(main_vfo_out_rate/(5*out_rate)))); 201 | lateDecimate=5; 202 | 203 | } 204 | else if((main_vfo_out_rate/48000)==6) 205 | { 206 | 207 | pVFO->setDecimationCount(int(log2(main_vfo_out_rate/(6*out_rate)))); 208 | lateDecimate=6; 209 | 210 | } 211 | 212 | else 213 | { 214 | pVFO->setDecimationCount(int(log2(Fs/out_rate))-int(log2(Fs/main_vfo_out_rate))); 215 | 216 | } 217 | 218 | pVFO->setFilterBandwidth(filterbw); 219 | pVFO->setGain((float)settings.value("gain").toFloat()/100); 220 | pVFO->setMixerFreq((center_frequency-main_vfo_freq) - vfo_freq); 221 | pVFO->setFs(main_vfo_out_rate); 222 | pVFO->setCompressonStyle(1); 223 | pVFO->init(main_vfo_out_rate/bufsplit,true, lateDecimate); 224 | 225 | VFOsub[main_idx].push_back(pVFO); 226 | 227 | connect(pVFO, SIGNAL(fftData(const std::vector&)), this, SLOT(fftHandlerSlot(const std::vector&))); 228 | connect(this, SIGNAL(fftVFOSlot(QString)), pVFO, SLOT(fftVFOSlot(QString))); 229 | 230 | vfo_str.push_back(settings.value("topic").toString()); 231 | 232 | 233 | } 234 | 235 | settings.endArray(); 236 | radio = new sdrj(this); 237 | 238 | radio->setVFOs(&VFOmain); 239 | radio->setDCCorrection(dc); 240 | 241 | Fs2 = Fs; 242 | 243 | nFFT = 8192; 244 | 245 | fftr = new FFTr(nFFT,false); 246 | fft = new FFT(nFFT, false); 247 | 248 | out.resize(nFFT); 249 | in.resize(nFFT); 250 | inr.resize(nFFT); 251 | pwr.resize(nFFT); 252 | smooth_pwr.resize(nFFT-10); 253 | 254 | 255 | qRegisterMetaType< QVector >("const QVector&"); 256 | qRegisterMetaType< QVector >("const std::vector&"); 257 | qRegisterMetaType< QVector >("const std::vector&"); 258 | 259 | connect(radio, SIGNAL(fftData(const std::vector&)), this, SLOT(fftHandlerSlot(const std::vector&)),Qt::UniqueConnection); 260 | connect(radio, SIGNAL(audio_signal_out(const float *, int )),radio,SLOT(demodData(const float*,int))); 261 | connect(this, SIGNAL(fftVFOSlot(QString)), radio, SLOT(fftVFOSlot(QString))); 262 | 263 | ui->setupUi(this); 264 | ui->biasTee->setText("Enable BiasTee"); 265 | ui->processFile->setVisible(false); 266 | 267 | ui->spinBox->setRange(center_frequency-100000,center_frequency+100000 ); 268 | ui->spinBox->setValue(center_frequency); 269 | ui->spinBox->setSingleStep(200); 270 | 271 | MainWindow::makePlot(); 272 | 273 | QStringList devices = radio->deviceNames(); 274 | ui->comboSDRs->addItems(devices); 275 | 276 | if(remote_rtl != "") 277 | { 278 | ui->comboSDRs->addItem(remote_rtl); 279 | 280 | } 281 | 282 | ui->comboVFO->addItems(vfo_str); 283 | 284 | hann_window.resize(nFFT); 285 | for(int i=0;i 0) 294 | { 295 | int index = radio->indexBySerial(auto_start_tuner_serial.toStdString().c_str()); 296 | 297 | switch(index){ 298 | 299 | case -1 :{ 300 | QMessageBox msgBoxDev1; 301 | msgBoxDev1.setText("Auto start device serial number from ini file is null"); 302 | msgBoxDev1.exec(); 303 | break; 304 | } 305 | case -2 : { 306 | QMessageBox msgBoxDev2; 307 | msgBoxDev2.setText("No devices found for auto start by device serial"); 308 | msgBoxDev2.exec(); 309 | break; 310 | } 311 | case -3 : { 312 | QMessageBox msgBoxDev3; 313 | msgBoxDev3.setText("No matching devices found for auto start by device serial: " +auto_start_tuner_serial ) ; 314 | msgBoxDev3.exec(); 315 | break; 316 | } 317 | 318 | default: 319 | auto_start_tuner_idx = index; 320 | break; 321 | } 322 | 323 | } 324 | 325 | ui->comboSDRs->setCurrentIndex(auto_start_tuner_idx); 326 | 327 | bool result = on_startSDR_clicked(); 328 | 329 | if(auto_start_biast == 1 && result){ 330 | 331 | on_biasTee_clicked(); 332 | } 333 | if(disableFFT == 1) { 334 | on_radioFFT_clicked(false); 335 | ui->radioFFT->setChecked(false); 336 | } else { 337 | ui->radioFFT->setChecked(true); 338 | } 339 | 340 | }else{ 341 | 342 | ui->startSDR->setEnabled(true); 343 | ui->stopSDR->setEnabled(false); 344 | 345 | if(disableFFT == 1) { 346 | ui->radioFFT->setChecked(false); 347 | } else { 348 | ui->radioFFT->setChecked(true); 349 | } 350 | } 351 | 352 | } 353 | 354 | MainWindow::~MainWindow() 355 | { 356 | if(radio) 357 | { 358 | radio->StopAndCloseRtl(); 359 | 360 | } 361 | delete ui; 362 | 363 | delete fft; 364 | delete fftr; 365 | delete radio; 366 | } 367 | 368 | void MainWindow::makePlot() 369 | { 370 | 371 | 372 | ui->spectrum->addGraph(); 373 | 374 | 375 | ui->spectrum->xAxis->setLabel("X"); 376 | ui->spectrum->yAxis->setLabel("Y"); 377 | 378 | spec_freq_vals.resize(nFFT-10); 379 | 380 | double hzperbin=Fs2/nFFT; 381 | for(int i=0;ispectrum->xAxis->setRange(0,Fs); 388 | 389 | ui->spectrum->graph()->setLineStyle(QCPGraph::lsLine); 390 | ui->spectrum->graph()->setPen(QPen(QPen(Qt::blue))); 391 | ui->spectrum->graph()->setBrush(QBrush(QColor(0, 0, 255, 20))); 392 | 393 | QSharedPointer textTicker(new QCPAxisTickerText); 394 | double start = (center_frequency-(Fs/2))/1000; 395 | int step = (Fs/5)/1000; 396 | 397 | for(int a = 1; a < 6; a++) 398 | { 399 | start+=step; 400 | textTicker->addTick(1000*a*step, QString::number(start/1000)); 401 | } 402 | ui->spectrum->xAxis->setTicker(textTicker); 403 | 404 | ui->spectrum->xAxis->setNumberFormat("gb"); 405 | ui->spectrum->xAxis->setLabel("Frequency"); 406 | ui->spectrum->yAxis->setRange(0,100); 407 | ui->spectrum->yAxis->setLabel("Power"); 408 | 409 | } 410 | 411 | void MainWindow::fftHandlerSlot(const std::vector &data) 412 | { 413 | double maxval = 0; 414 | double aveval = 0; 415 | 416 | int lenth = (int)data.size(); 417 | 418 | for(int a = 0; atransform(inr, out); 428 | 429 | for(int i=0;i= pwr.size()){ 435 | b = b - pwr.size(); 436 | } 437 | 438 | double val = 0; 439 | val = sqrt(out[i].imag()*out[i].imag() + out[i].real()*out[i].real()); 440 | 441 | pwr[b]= pwr[b]*0.95+0.05*10*log10(fmax(100000.0*abs((1.0/nFFT)*val),1)); 442 | 443 | if(pwr[b]>maxval) 444 | { 445 | maxval=pwr[b]; 446 | } 447 | aveval+=pwr[b]; 448 | } 449 | 450 | for(int i=0;ispectrum->graph(0)->setData(spec_freq_vals,smooth_pwr); 468 | 469 | 470 | }else 471 | { 472 | 473 | ui->spectrum->graph(0)->setData(spec_freq_vals.mid(0,(nFFT-10)/2),smooth_pwr.mid((nFFT-10)/2, (nFFT-10)/2)); 474 | } 475 | ui->spectrum->yAxis->setRange(aveval-2, ui->spectrum->yAxis->range().upper*0.5+0.5*(maxval+1)); 476 | 477 | ui->spectrum->replot(); 478 | } 479 | 480 | 481 | 482 | void MainWindow::on_stopSDR_clicked() 483 | { 484 | 485 | radio->StopAndCloseRtl(); 486 | 487 | ui->startSDR->setEnabled(true); 488 | ui->stopSDR->setEnabled(false); 489 | 490 | 491 | } 492 | 493 | bool MainWindow::on_startSDR_clicked() 494 | { 495 | 496 | bool result = false; 497 | bool remote = ui->comboSDRs->currentText().contains(":") ? true : false; 498 | 499 | if(remote) 500 | { 501 | 502 | result = radio->start_tcp_rtl(ui->comboSDRs->currentText(),Fs, center_frequency, tuner_gain_idx ); 503 | 504 | } 505 | 506 | else{ 507 | 508 | result = radio->OpenRtl(ui->comboSDRs->currentIndex()); 509 | 510 | } 511 | if(!result) 512 | { 513 | 514 | QMessageBox msgBox; 515 | msgBox.setText("Could not open the selected device, check if it is use"); 516 | msgBox.exec(); 517 | } 518 | else if(!remote) 519 | { 520 | radio->StartRtl(Fs,center_frequency, buflen, tuner_gain); 521 | } 522 | 523 | if(result) 524 | { 525 | 526 | ui->startSDR->setEnabled(false); 527 | ui->stopSDR->setEnabled(true); 528 | } 529 | 530 | return result; 531 | } 532 | 533 | 534 | void MainWindow::on_processFile_clicked() 535 | { 536 | //radio->process_file(Fs); 537 | } 538 | 539 | void MainWindow::on_comboVFO_currentIndexChanged(const QString &arg1) 540 | { 541 | emit fftVFOSlot(arg1); 542 | for(int i=0;ispectrum->xAxis->setTickLabels(false); 556 | ui->spectrum->xAxis->setRange(0,Fs/2); 557 | 558 | }else 559 | { 560 | usb = false; 561 | ui->spectrum->xAxis->setTickLabels(true); 562 | ui->spectrum->xAxis->setRange(0,Fs); 563 | } 564 | 565 | 566 | } 567 | 568 | 569 | 570 | void MainWindow::on_spinBox_valueChanged(int arg1) 571 | { 572 | if(radio != 0 && arg1 != center_frequency) 573 | { 574 | 575 | int result = radio->setCenterFreq(arg1); 576 | 577 | if(result == 0) 578 | { 579 | center_frequency = arg1; 580 | } 581 | } 582 | 583 | } 584 | 585 | 586 | 587 | void MainWindow::on_biasTee_clicked() 588 | { 589 | 590 | bool remote = ui->comboSDRs->currentText().contains(":") ? true : false; 591 | 592 | if(!remote) 593 | { 594 | 595 | if(biasT) 596 | { 597 | 598 | ui->biasTee->setText("Enable BiasTee"); 599 | radio->biasTee(0, ui->comboSDRs->currentIndex()); 600 | biasT = false; 601 | }else 602 | { 603 | ui->biasTee->setText("Disable BiasTee"); 604 | radio->biasTee(1, ui->comboSDRs->currentIndex()); 605 | biasT = true; 606 | 607 | } 608 | }else{ 609 | QMessageBox msgBox; 610 | msgBox.setText("Remote device selected, bias tee not supported"); 611 | msgBox.exec(); 612 | } 613 | 614 | } 615 | 616 | void MainWindow::on_radioFFT_clicked(bool checked) 617 | { 618 | if(checked){ 619 | connect(radio, SIGNAL(fftData(const std::vector&)), this, SLOT(fftHandlerSlot(const std::vector&)),Qt::UniqueConnection); 620 | 621 | }else{ 622 | disconnect(radio, SIGNAL(fftData(const std::vector&)), this, SLOT(fftHandlerSlot(const std::vector&))); 623 | 624 | } 625 | 626 | } 627 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | #include "jonti/fftrwrapper.h" 7 | #include "jonti/fftwrapper.h" 8 | #include "sdrj.h" 9 | 10 | typedef FFTrWrapper FFTr; 11 | typedef FFTWrapper FFT; 12 | 13 | const int MAXVFO=50; 14 | 15 | QT_BEGIN_NAMESPACE 16 | namespace Ui { class MainWindow; } 17 | QT_END_NAMESPACE 18 | 19 | class MainWindow : public QMainWindow 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | MainWindow(QWidget *parent = nullptr); 25 | ~MainWindow(); 26 | 27 | static QString settings_filename; 28 | 29 | const QList supportedRTLSDRSampleRates={288000,1536000,1920000}; 30 | 31 | signals: 32 | 33 | void fftData(const std::vector &data); 34 | void fftVFOSlot(QString topic); 35 | 36 | public slots: 37 | void fftHandlerSlot(const std::vector& data); 38 | 39 | private slots: 40 | void makePlot(); 41 | void on_stopSDR_clicked(); 42 | bool on_startSDR_clicked(); 43 | void on_processFile_clicked(); 44 | void on_comboVFO_currentIndexChanged(const QString &arg1); 45 | void on_spinBox_valueChanged(int arg1); 46 | void on_biasTee_clicked(); 47 | void on_radioFFT_clicked(bool checked); 48 | 49 | private: 50 | Ui::MainWindow *ui; 51 | 52 | sdrj * radio; 53 | 54 | QVector spec_freq_vals; 55 | QVector hann_window; 56 | 57 | FFTr *fftr; 58 | FFT* fft; 59 | 60 | QVector in; 61 | QVector inr; 62 | QVector out; 63 | 64 | int N; 65 | int nFFT; 66 | 67 | int Fs; 68 | int Fs2; 69 | int buflen; 70 | 71 | QVector pwr; 72 | QVector smooth_pwr; 73 | 74 | int counter; 75 | 76 | int nVFO; 77 | int center_frequency; 78 | int tuner_gain; 79 | int tuner_gain_idx; 80 | 81 | QVector VFOs; 82 | QVector VFOsub[3]; 83 | QVector VFOmain; 84 | 85 | QString remote_rtl; 86 | 87 | bool biasT; 88 | bool usb; 89 | bool enableFFT; 90 | 91 | 92 | 93 | }; 94 | #endif // MAINWINDOW_H 95 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | SDRReceiver 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Start SDR 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 0 36 | 0 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Stop SDR 45 | 46 | 47 | 48 | 49 | 50 | 51 | BiasTee 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Process File 62 | 63 | 64 | 65 | 66 | 67 | 68 | Main FFT Enabled 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 0 78 | 0 79 | 800 80 | 21 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | QCustomPlot 89 | QWidget 90 |
qcustomplot.h
91 | 1 92 |
93 |
94 | 95 | 96 |
97 | -------------------------------------------------------------------------------- /oscillator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oscillator.h" 3 | 4 | Oscillator::Oscillator(double sampleRate, double Frequency) 5 | { 6 | 7 | _frequency = Frequency; 8 | _sampleRate = sampleRate; 9 | double anglePerSample = 2.0 * M_PI * _frequency / _sampleRate; 10 | 11 | _rotation = cpx_typef((float)cos(anglePerSample), (float)sin(anglePerSample)); 12 | 13 | _vector = cpx_typef(1.0f,0); 14 | 15 | length = (int)sampleRate; 16 | 17 | 18 | queue = new cpx_typef[length]; 19 | 20 | for(int i=0;i 4 | 5 | #ifndef M_PI 6 | #define M_PI 3.14159265358979323846264338327950288 7 | #endif 8 | 9 | typedef std::complex cpx_typef; 10 | 11 | 12 | class Oscillator 13 | { 14 | 15 | private: 16 | cpx_typef _rotation; 17 | double _sampleRate; 18 | double _frequency; 19 | 20 | cpx_typef * queue; 21 | int queuePtr; 22 | int length; 23 | 24 | public: 25 | Oscillator(double sampleRate, double Frequency); 26 | void tick(); 27 | cpx_typef _vector; 28 | ~Oscillator(); 29 | }; 30 | 31 | #endif // OSCILLATOR_H 32 | -------------------------------------------------------------------------------- /sample_ini/CBAND_143E.ini: -------------------------------------------------------------------------------- 1 | sample_rate=1536000 2 | center_frequency=1546200000 3 | zmq_address=tcp://*:6003 4 | 5 | #remote_rtl=127.0.0.1:1234 6 | 7 | #valid tuner gains r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 }; 8 | tuner_gain=496 9 | correct_dc_bias=1 10 | mix_offset=0 11 | 12 | #auto_start=1 13 | #auto_start_tuner_idx=0 14 | 15 | 16 | [main_vfos] 17 | size=3 18 | 1\frequency=1545800000 19 | 1\out_rate=384000 20 | 2\frequency=1546300000 21 | 2\out_rate=192000 22 | 3\frequency=1546635000 23 | 3\out_rate=384000 24 | 25 | #VFO's in frequency order from lowest to highest, first 7 are 10500. 26 | 27 | [vfos] 28 | size=17 29 | 30 | 1\frequency=1545670000 31 | 1\gain=5 32 | 1\filter_bandwidth=15000 33 | 1\out_rate=48000 34 | 1\topic=VFC01 35 | 36 | 2\frequency=1545775000 37 | 2\gain=5 38 | 2\filter_bandwidth=15000 39 | 2\out_rate=48000 40 | 2\topic=VFC02 41 | 42 | 3\frequency=1545917500 43 | 3\gain=5 44 | 3\filter_bandwidth=15000 45 | 3\out_rate=48000 46 | 3\topic=VFC03 47 | 48 | 4\frequency=1546262450 49 | 4\gain=5 50 | 4\filter_bandwidth=15000 51 | 4\out_rate=48000 52 | 4\topic=VFC04 53 | 54 | 5\frequency=1546277350 55 | 5\gain=5 56 | 5\filter_bandwidth=15000 57 | 5\out_rate=48000 58 | 5\topic=VFC05 59 | 60 | 6\frequency=1546292500 61 | 6\gain=5 62 | 6\filter_bandwidth=15000 63 | 6\out_rate=48000 64 | 6\topic=VFC06 65 | 66 | 7\frequency=1546307500 67 | 7\gain=5 68 | 7\filter_bandwidth=15000 69 | 7\out_rate=48000 70 | 7\topic=VFC07 71 | 72 | 8\frequency=1546515550 73 | 8\gain=5 74 | 8\filter_bandwidth=3000 75 | 8\out_rate=48000 76 | 8\topic=VFC08 77 | 78 | 9\frequency=1546555600 79 | 9\gain=5 80 | 9\filter_bandwidth=3000 81 | 9\out_rate=48000 82 | 9\topic=VFC09 83 | 84 | 10\frequency=1546681000 85 | 10\gain=5 86 | 10\filter_bandwidth=3000 87 | 10\out_rate=48000 88 | 10\topic=VFC10 89 | 90 | 11\frequency=1546705700 91 | 11\gain=5 92 | 11\filter_bandwidth=3000 93 | 11\out_rate=48000 94 | 11\topic=VFC11 95 | 96 | 12\frequency=1546733240 97 | 12\gain=5 98 | 12\filter_bandwidth=3000 99 | 12\out_rate=48000 100 | 12\topic=VFC12 101 | 102 | 13\frequency=1546735700 103 | 13\gain=5 104 | 13\filter_bandwidth=3000 105 | 13\out_rate=48000 106 | 13\topic=VFC13 107 | 108 | 14\frequency=1546738050 109 | 14\gain=5 110 | 14\filter_bandwidth=3000 111 | 14\out_rate=48000 112 | 14\topic=VFC14 113 | 114 | 15\frequency=1546750500 115 | 15\gain=5 116 | 15\filter_bandwidth=3000 117 | 15\out_rate=48000 118 | 15\topic=VFC15 119 | 120 | 16\frequency=1546753150 121 | 16\gain=5 122 | 16\filter_bandwidth=3000 123 | 16\out_rate=48000 124 | 16\topic=VFC16 125 | 126 | 17\frequency=1546755850 127 | 17\gain=5 128 | 17\filter_bandwidth=3000 129 | 17\out_rate=48000 130 | 17\topic=VFC17 131 | 132 | -------------------------------------------------------------------------------- /sample_ini/sdr_25E.ini: -------------------------------------------------------------------------------- 1 | sample_rate=1536000 2 | center_frequency=1545600000 3 | zmq_address=tcp://*:6003 4 | 5 | #auto_start=1 6 | #auto_start_tuner_idx=0 7 | 8 | #remote_rtl=127.0.0.1:1234 9 | 10 | #valid tuner gains r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 }; 11 | tuner_gain=496 12 | correct_dc_bias=1 13 | mix_offset=0 14 | 15 | 16 | [main_vfos] 17 | size=2 18 | 1\frequency=1545116000 19 | 1\out_rate=384000 20 | 2\frequency=1546096000 21 | 2\out_rate=192000 22 | 23 | [vfos] 24 | size=27 25 | 1\frequency=1545005146 26 | 1\gain=5 27 | 1\filter_bandwidth=4000 28 | 1\data_rate=600 29 | 1\fiter_bandwidth=0 30 | 1\topic=VFO01 31 | 2\frequency=1545214573 32 | 2\gain=5 33 | 2\data_rate=600 34 | 2\fiter_bandwidth=0 35 | 2\topic=VFO02 36 | 3\frequency=1545219706 37 | 3\gain=5 38 | 3\data_rate=600 39 | 3\fiter_bandwidth=0 40 | 3\topic=VFO03 41 | 4\frequency=1545224996 42 | 4\gain=5 43 | 4\data_rate=600 44 | 4\fiter_bandwidth=0 45 | 4\topic=VFO04 46 | 5\frequency=1545114134 47 | 5\gain=5 48 | 5\data_rate=600 49 | 5\fiter_bandwidth=0 50 | 5\topic=VFO05 51 | 6\frequency=1545119063 52 | 6\gain=5 53 | 6\data_rate=600 54 | 6\fiter_bandwidth=0 55 | 6\topic=VFO06 56 | 7\frequency=1545124261 57 | 7\gain=5 58 | 7\data_rate=1200 59 | 7\fiter_bandwidth=0 60 | 7\topic=VFO07 61 | 8\frequency=1545129563 62 | 8\gain=5 63 | 8\data_rate=600 64 | 8\fiter_bandwidth=0 65 | 8\topic=VFO08 66 | 9\frequency=1545159288 67 | 9\gain=5 68 | 9\data_rate=600 69 | 9\fiter_bandwidth=0 70 | 9\topic=VFO09 71 | 10\frequency=1545164682 72 | 10\gain=5 73 | 10\data_rate=600 74 | 10\fiter_bandwidth=0 75 | 10\topic=VFO10 76 | 11\frequency=1545183905 77 | 11\gain=5 78 | 11\data_rate=600 79 | 11\fiter_bandwidth=0 80 | 11\topic=VFO11 81 | 12\frequency=1545189244 82 | 12\gain=5 83 | 12\data_rate=600 84 | 12\fiter_bandwidth=0 85 | 12\topic=VFO12 86 | 13\frequency=1546005300 87 | 13\gain=5 88 | 13\data_rate=10500 89 | 13\fiter_bandwidth=0 90 | 13\topic=VFO13 91 | 14\frequency=1546019800 92 | 14\gain=5 93 | 14\data_rate=10500 94 | 14\fiter_bandwidth=0 95 | 14\topic=VFO14 96 | 15\frequency=1546034700 97 | 15\gain=5 98 | 15\data_rate=10500 99 | 15\fiter_bandwidth=0 100 | 15\topic=VFO15 101 | 16\frequency=1546084600 102 | 16\gain=5 103 | 16\data_rate=10500 104 | 16\fiter_bandwidth=0 105 | 16\topic=VFO16 106 | 17\frequency=1546099900 107 | 17\gain=5 108 | 17\data_rate=10500 109 | 17\fiter_bandwidth=0 110 | 17\topic=VFO17 111 | 18\frequency=1546114200 112 | 18\gain=5 113 | 18\data_rate=10500 114 | 18\fiter_bandwidth=0 115 | 18\topic=VFO18 116 | 19\frequency=1546137300 117 | 19\gain=5 118 | 19\data_rate=8400 119 | 19\filter_bandwidth=10000 120 | 19\topic=VFO19 121 | 20\frequency=1546142500 122 | 20\gain=3 123 | 20\data_rate=8400 124 | 20\filter_bandwidth=10000 125 | 20\topic=VFO20 126 | 21\frequency=1546147700 127 | 21\gain=3 128 | 21\data_rate=8400 129 | 21\filter_bandwidth=10000 130 | 21\topic=VFO21 131 | 22\frequency=1546152300 132 | 22\gain=3 133 | 22\data_rate=8400 134 | 22\filter_bandwidth=10000 135 | 22\topic=VFO22 136 | 23\frequency=1546157500 137 | 23\gain=3 138 | 23\data_rate=8400 139 | 23\filter_bandwidth=10000 140 | 23\topic=VFO23 141 | 24\frequency=1546162600 142 | 24\gain=3 143 | 24\data_rate=8400 144 | 24\filter_bandwidth=10000 145 | 24\topic=VFO24 146 | 25\frequency=1546168300 147 | 25\gain=3 148 | 25\data_rate=8400 149 | 25\filter_bandwidth=10000 150 | 25\topic=VFO25 151 | 26\frequency=1546173430 152 | 26\gain=3 153 | 26\data_rate=8400 154 | 26\filter_bandwidth=10000 155 | 26\topic=VFO26 156 | 27\frequency=1546178430 157 | 27\gain=3 158 | 27\data_rate=8400 159 | 27\filter_bandwidth=10000 160 | 27\topic=VFO27 161 | -------------------------------------------------------------------------------- /sample_ini/sdr_54W_288K.ini: -------------------------------------------------------------------------------- 1 | sample_rate=288000 2 | 3 | #depending on which channels you want 4 | #center_frequency=1545100000 5 | center_frequency=1546100000 6 | 7 | zmq_address=tcp://*:6004 8 | mix_offset=0 9 | 10 | #auto_start=1 11 | #auto_start_tuner_idx = 12 | 13 | [main_vfos] 14 | # for the low lband data channels 15 | #size=1 16 | #1\frequency=1545120000 17 | #1\out_rate=288000 18 | 19 | # for the lband 10500 data channels 20 | size=1 21 | 1\frequency=1546100000 22 | 1\out_rate=288000 23 | 24 | 25 | 26 | #[vfos] 27 | #size=4 28 | #1\frequency=1545014429 29 | #1\gain=4 30 | #1\data_rate=600 31 | #1\filter_bandwidth=0 32 | #1\topic=VFO41 33 | #2\frequency=1545029412 34 | #2\gain=4 35 | #2\data_rate=600 36 | #2\filter_bandwidth=0 37 | #2\topic=VFO42 38 | #3\frequency=1545134635 39 | #3\gain=4 40 | #3\data_rate=600 41 | #3\filter_bandwidth=0 42 | #3\topic=VFO43 43 | #4\frequency=1545194731 44 | #4\gain=4 45 | #4\data_rate=600 46 | #4\filter_bandwidth=0 47 | #4\topic=VFO44 48 | 49 | [vfos] 50 | size=2 51 | 1\frequency=1546045422 52 | 1\gain=4 53 | 1\data_rate=10500 54 | 1\filter_bandwidth=0 55 | 1\topic=VFO51 56 | 2\frequency=1546061717 57 | 2\gain=4 58 | 2\data_rate=10500 59 | 2\filter_bandwidth=0 60 | 2\topic=VFO52 -------------------------------------------------------------------------------- /sample_ini/sdr_54W_all.ini: -------------------------------------------------------------------------------- 1 | sample_rate=1920000 2 | center_frequency=1545939000 3 | zmq_address=tcp://*:6004 4 | mix_offset=0 5 | 6 | auto_start=1 7 | auto_start_tuner_idx = 1 8 | 9 | [main_vfos] 10 | size=3 11 | 1\frequency=1545120000 12 | 1\out_rate=240000 13 | 2\frequency=1546120000 14 | 2\out_rate=240000 15 | 3\frequency=1546850000 16 | 3\out_rate=240000 17 | 18 | 19 | [vfos] 20 | size=14 21 | 1\frequency=1545014429 22 | 1\gain=4 23 | 1\data_rate=600 24 | 1\filter_bandwidth=0 25 | 1\topic=VFO41 26 | 2\frequency=1545029412 27 | 2\gain=4 28 | 2\data_rate=600 29 | 2\filter_bandwidth=0 30 | 2\topic=VFO42 31 | 3\frequency=1545134635 32 | 3\gain=4 33 | 3\data_rate=600 34 | 3\filter_bandwidth=0 35 | 3\topic=VFO43 36 | 4\frequency=1545194731 37 | 4\gain=4 38 | 4\data_rate=600 39 | 4\filter_bandwidth=0 40 | 4\topic=VFO44 41 | 42 | 5\frequency=1546045422 43 | 5\gain=4 44 | 5\data_rate=10500 45 | 5\filter_bandwidth=0 46 | 5\topic=VFO51 47 | 6\frequency=1546061717 48 | 6\gain=4 49 | 6\data_rate=10500 50 | 6\filter_bandwidth=0 51 | 6\topic=VFO52 52 | 53 | 7\frequency=1546817935 54 | 7\gain=4 55 | 7\data_rate=8400 56 | 7\filter_bandwidth=10000 57 | 7\topic=VFO54 58 | 8\frequency=1546823426 59 | 8\gain=4 60 | 8\data_rate=8400 61 | 8\filter_bandwidth=10000 62 | 8\topic=VFO55 63 | 9\frequency=1546828110 64 | 9\gain=4 65 | 9\data_rate=8400 66 | 9\filter_bandwidth=10000 67 | 9\topic=VFO56 68 | 10\frequency=1546833112 69 | 10\gain=4 70 | 10\data_rate=8400 71 | 10\filter_bandwidth=10000 72 | 10\topic=VFO57 73 | 11\frequency=1546838105 74 | 11\gain=4 75 | 11\data_rate=8400 76 | 11\filter_bandwidth=10000 77 | 11\topic=VFO58 78 | 12\frequency=1546842770 79 | 12\gain=4 80 | 12\data_rate=8400 81 | 12\filter_bandwidth=10000 82 | 12\topic=VFO59 83 | 13\frequency=1546848155 84 | 13\gain=4 85 | 13\data_rate=8400 86 | 13\filter_bandwidth=10000 87 | 13\topic=VFO60 88 | 14\frequency=1546853237 89 | 14\gain=4 90 | 14\data_rate=8400 91 | 14\filter_bandwidth=10000 92 | 14\topic=VFO61 93 | 94 | 95 | -------------------------------------------------------------------------------- /sample_ini/sdr_98W.ini: -------------------------------------------------------------------------------- 1 | #Main sample rate, do not change basically 2 | sample_rate=1536000 3 | #Tuning freq for the dongle, probably no reason to modify 4 | center_frequency=1545600000 5 | #This is the address ZMQ will band to for sending audio to jaero 6 | zmq_address=tcp://*:6003 7 | #Enable this to remove the annoying spike in the middle of the spectrum 8 | correct_dc_bias=1 9 | 10 | #valid tuner gains r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 }; 11 | tuner_gain=496 12 | 13 | #to raise or lower the center frequency of each VFO set a value here, i.e. -1000 to lower each VFO with 1000hz or 2000 to increase by 2000 hz. Useful when swichting dongles for instance. 14 | mix_offset=0 15 | 16 | #to start the SDR automatically set to 1 17 | #auto_start=0 18 | #auto_start_tuner_idx=0 19 | 20 | #typically not needed to modify the below block. It is used to mix down the lower data rate and higher rate channels into into different chunks to improve decimatation performance 21 | [main_vfos] 22 | size=2 23 | 1\frequency=1545116000 24 | 1\out_rate=384000 25 | 2\frequency=1546096000 26 | 2\out_rate=192000 27 | #Actual VFO's. When adding more just increase the size value on top. Ensure to keep the numbering sequence and formatting of variables, the application will probably crash otherwise 28 | [vfos] 29 | size=27 30 | 1\frequency=1545101000 31 | 1\gain=5 32 | 1\data_rate=600 33 | 1\filter_bandwidth=0 34 | 1\topic=VFO01 35 | 2\frequency=1545051000 36 | 2\gain=5 37 | 2\data_rate=600 38 | 2\filter_bandwidth=0 39 | 2\topic=VFO02 40 | 3\frequency=1545061000 41 | 3\gain=5 42 | 3\data_rate=600 43 | 3\filter_bandwidth=0 44 | 3\topic=VFO03 45 | 4\frequency=1545171000 46 | 4\gain=5 47 | 4\data_rate=600 48 | 4\filter_bandwidth=0 49 | 4\topic=VFO04 50 | 5\frequency=1545176000 51 | 5\gain=5 52 | 5\data_rate=600 53 | 5\filter_bandwidth=0 54 | 5\topic=VFO05 55 | 6\frequency=1545076000 56 | 6\gain=5 57 | 6\data_rate=1200 58 | 6\filter_bandwidth=0 59 | 6\topic=VFO06 60 | 7\frequency=1545021000 61 | 7\gain=5 62 | 7\data_rate=600 63 | 7\filter_bandwidth=0 64 | 7\topic=VFO07 65 | 8\frequency=1545066000 66 | 8\gain=5 67 | 8\data_rate=600 68 | 8\filter_bandwidth=0 69 | 8\topic=VFO08 70 | 9\frequency=1545081000 71 | 9\gain=5 72 | 9\data_rate=600 73 | 9\filter_bandwidth=0 74 | 9\topic=VFO09 75 | 10\frequency=1545086000 76 | 10\gain=5 77 | 10\data_rate=600 78 | 10\filter_bandwidth=0 79 | 10\topic=VFO10 80 | 11\frequency=1545091000 81 | 11\gain=5 82 | 11\data_rate=600 83 | 11\filter_bandwidth=0 84 | 11\topic=VFO11 85 | 12\frequency=1545111000 86 | 12\gain=5 87 | 12\data_rate=600 88 | 12\filter_bandwidth=0 89 | 12\topic=VFO12 90 | #10500 channels 91 | 13\frequency=1545995000 92 | 13\gain=3 93 | 13\data_rate=10500 94 | 13\filter_bandwidth=0 95 | 13\topic=VFO13 96 | 14\frequency=1546010000 97 | 14\gain=3 98 | 14\data_rate=10500 99 | 14\filter_bandwidth=0 100 | 14\topic=VFO14 101 | 15\frequency=1546055000 102 | 15\gain=3 103 | 15\data_rate=10500 104 | 15\filter_bandwidth=0 105 | 15\topic=VFO15 106 | 16\frequency=1546070000 107 | 16\gain=3 108 | 16\data_rate=10500 109 | 16\filter_bandwidth=0 110 | 16\topic=VFO16 111 | #adio channels 112 | 17\frequency=1546135300 113 | 17\gain=5 114 | 17\data_rate=8400 115 | 17\filter_bandwidth=10000 116 | 17\topic=VFO17 117 | 18\frequency=1546140500 118 | 18\gain=3 119 | 18\data_rate=8400 120 | 18\filter_bandwidth=10000 121 | 18\topic=VFO18 122 | 19\frequency=1546145700 123 | 19\gain=3 124 | 19\data_rate=8400 125 | 19\filter_bandwidth=10000 126 | 19\topic=VFO19 127 | 20\frequency=1546150300 128 | 20\gain=3 129 | 20\data_rate=8400 130 | 20\filter_bandwidth=10000 131 | 20\topic=VFO20 132 | 21\frequency=1546155500 133 | 21\gain=3 134 | 21\data_rate=8400 135 | 21\filter_bandwidth=10000 136 | 21\topic=VFO21 137 | 22\frequency=1546160600 138 | 22\gain=3 139 | 22\data_rate=8400 140 | 22\filter_bandwidth=10000 141 | 22\topic=VFO22 142 | 23\frequency=1546166300 143 | 23\gain=3 144 | 23\data_rate=8400 145 | 23\filter_bandwidth=10000 146 | 23\topic=VFO23 147 | 24\frequency=1546171430 148 | 24\gain=3 149 | 24\data_rate=8400 150 | 24\filter_bandwidth=10000 151 | 24\topic=VFO24 152 | 25\frequency=1546176430 153 | 25\gain=3 154 | 25\data_rate=8400 155 | 25\filter_bandwidth=10000 156 | 25\topic=VFO25 157 | 26\frequency=1546181430 158 | 26\gain=3 159 | 26\data_rate=8400 160 | 26\filter_bandwidth=10000 161 | 26\topic=VFO26 162 | 27\frequency=1546186430 163 | 27\gain=3 164 | 27\data_rate=8400 165 | 27\filter_bandwidth=10000 166 | 27\topic=VFO27 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /sdrj.cpp: -------------------------------------------------------------------------------- 1 | #include "sdrj.h" 2 | 3 | 4 | sdrj::sdrj(QObject *parent) 5 | { 6 | 7 | 8 | tcp_active = false; 9 | count = 0; 10 | avecpt = 0; 11 | val = 0.000001; 12 | one = 1.0; 13 | correctDC = false; 14 | 15 | tcpSocket = 0; 16 | 17 | 18 | } 19 | sdrj::~sdrj() 20 | { 21 | for(int a = 0; alength(); a++) 22 | { 23 | vfo * pvfo = mpVFOs->at(a); 24 | delete pvfo; 25 | } 26 | 27 | 28 | } 29 | 30 | 31 | bool sdrj::start_tcp_rtl(QString device_address, int samplerate, int frequency, int gain) 32 | { 33 | 34 | bool result = false; 35 | tcpSocket = new QTcpSocket(this); 36 | 37 | connect(tcpSocket, SIGNAL(connected()),this, SLOT(connected())); 38 | connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(disconnected())); 39 | connect(tcpSocket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64))); 40 | connect(tcpSocket, SIGNAL(readyRead()),this, SLOT(readyRead())); 41 | 42 | 43 | tcpFloats.resize((samplerate/4)*2); 44 | 45 | tcpData.resize(tcpFloats.size()); 46 | 47 | tcpSocket->connectToHost(device_address.split(":")[0], device_address.split(":")[1].toInt()); 48 | 49 | if(!tcpSocket->waitForConnected(5000)) 50 | { 51 | qDebug() << "Error: " << tcpSocket->errorString(); 52 | 53 | } 54 | else{ 55 | 56 | uint agc_mode = 0; 57 | uint gain_mode = 1; 58 | 59 | 60 | sendCommand(CMD_SET_AGC_MODE, static_cast(static_cast(&agc_mode))); 61 | sendCommand(CMD_SET_TUNER_GAIN_MODE, static_cast(static_cast(&gain_mode))); 62 | sendCommand(CMD_SET_TUNER_GAIN_INDEX,static_cast(static_cast(&gain))); 63 | 64 | sendCommand(CMD_SET_SAMPLE_RATE, static_cast(static_cast(&samplerate))); 65 | sendCommand(CMD_SET_FREQ, static_cast(static_cast(&frequency))); 66 | 67 | result = true; 68 | 69 | tcp_active=true; 70 | } 71 | 72 | 73 | return result; 74 | } 75 | 76 | 77 | void sdrj::setVFOs(QVector * vfos) 78 | { 79 | 80 | mpVFOs = vfos; 81 | 82 | } 83 | 84 | void sdrj::fftVFOSlot(QString topic) 85 | { 86 | 87 | if(topic.compare("Main") ==0) 88 | { 89 | 90 | emitFFT = true; 91 | 92 | count = 0; 93 | } 94 | else 95 | { 96 | emitFFT = false; 97 | 98 | count = 0; 99 | } 100 | 101 | } 102 | void sdrj::setDCCorrection(bool correct) 103 | { 104 | 105 | correctDC = correct; 106 | } 107 | 108 | void sdrj::connected() 109 | { 110 | qDebug() << "connected..."; 111 | 112 | } 113 | 114 | void sdrj::disconnected() 115 | { 116 | 117 | 118 | } 119 | 120 | void sdrj::bytesWritten(qint64 bytes) 121 | { 122 | qDebug() << bytes << " bytes written..."; 123 | } 124 | 125 | void sdrj::readyRead() 126 | { 127 | // read the data from the socket 128 | qint64 avail = tcpSocket->bytesAvailable(); 129 | 130 | if(avail == 12) 131 | { 132 | 133 | 134 | int _tunerType = 0; 135 | int _tunerGainCount = 0; 136 | 137 | QByteArray buffer = tcpSocket->readAll(); 138 | 139 | if (buffer[0] != 'R' || buffer[1] != 'T' || buffer[2] != 'L' || buffer[3] != '0') 140 | { 141 | return; 142 | } 143 | _tunerType = (uint)(buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7]); 144 | _tunerGainCount = (uint)(buffer[8] << 24 | buffer[9] << 16 | buffer[10] << 8 | buffer[11]); 145 | 146 | qDebug() << "Tuner type " << _tunerType << " gain count " << _tunerGainCount; 147 | 148 | } 149 | else if (avail >=tcpFloats.size() ) 150 | { 151 | 152 | 153 | tcpData = tcpSocket->read(tcpFloats.size()); 154 | unsigned char* buff = (unsigned char*)tcpData.data(); 155 | for(int i=0;iwrite(cmdBuff); 187 | return true; 188 | } 189 | 190 | int sdrj::setCenterFreq(int freq) 191 | { 192 | 193 | if(active) 194 | { 195 | return rtlsdr_set_center_freq(rtldev, freq); 196 | }else 197 | { 198 | return -1; 199 | } 200 | } 201 | 202 | int sdrj::biasTee(int on, int device_idx) 203 | { 204 | 205 | if(rtldev == NULL ) 206 | { 207 | int open_res = rtlsdr_open(&rtldev,device_idx); 208 | 209 | if (open_res != 0) 210 | { 211 | return 0; 212 | } 213 | 214 | int t_res = rtlsdr_set_bias_tee(rtldev, on); 215 | 216 | rtlsdr_close(rtldev); 217 | rtldev = 0; 218 | 219 | if(t_res != 0) 220 | { 221 | return 0; 222 | } 223 | 224 | }else 225 | { 226 | 227 | int t_res = rtlsdr_set_bias_tee(rtldev, on); 228 | 229 | if(t_res != 0) 230 | { 231 | return 0; 232 | } 233 | 234 | } 235 | 236 | 237 | return 1; 238 | } 239 | 240 | 241 | bool sdrj::StopAndCloseRtl() 242 | { 243 | bool result=sdr::StopAndCloseRtl(); 244 | 245 | if(tcp_active) 246 | { 247 | 248 | if(tcpSocket) 249 | { 250 | 251 | tcpSocket->disconnect(); 252 | tcpSocket->disconnectFromHost(); 253 | tcpSocket->deleteLater(); 254 | tcpSocket = 0; 255 | 256 | } 257 | } 258 | 259 | 260 | tcp_active=false; 261 | 262 | 263 | return result; 264 | } 265 | 266 | void sdrj::demodData(const float* data,int len) 267 | { 268 | 269 | samples.resize(len/2); 270 | 271 | for(int i=0;ilength(); a++) 289 | { 290 | vfo * pvfo = mpVFOs->at(a); 291 | 292 | pvfo->process(samples); 293 | 294 | } 295 | 296 | int fftnt = 4; 297 | 298 | if(count == fftnt && emitFFT) 299 | { 300 | emit fftData(samples); 301 | count=0; 302 | } 303 | count++; 304 | 305 | } 306 | int sdrj::indexBySerial(const char *serial) 307 | { 308 | 309 | return(rtlsdr_get_index_by_serial(serial)); 310 | 311 | } 312 | -------------------------------------------------------------------------------- /sdrj.h: -------------------------------------------------------------------------------- 1 | #ifndef SDRJ_H 2 | #define SDRJ_H 3 | 4 | #include "jonti/sdr.h" 5 | #include "vfo.h" 6 | 7 | typedef std::complex cpx_type; 8 | typedef std::complex cpx_typef; 9 | 10 | const char CMD_SET_FREQ = 0x1; 11 | const char CMD_SET_SAMPLE_RATE = 0x2; 12 | const char CMD_SET_TUNER_GAIN_MODE = 0x3; 13 | const char CMD_SET_GAIN = 0x4; 14 | const char CMD_SET_FREQ_COR = 0x5; 15 | const char CMD_SET_AGC_MODE = 0x8; 16 | const char CMD_SET_TUNER_GAIN_INDEX = 0xd; 17 | 18 | class sdrj : public sdr 19 | { 20 | 21 | Q_OBJECT 22 | 23 | public: 24 | 25 | ~sdrj(); 26 | explicit sdrj(QObject *parent = 0); 27 | 28 | void process_file(int sample_rate); 29 | void setDCCorrection(bool correct); 30 | int setCenterFreq(int freq); 31 | void setVFOs(QVector *pVFOs); 32 | int biasTee(int on, int device_idx); 33 | bool start_tcp_rtl(QString device_address, int sample_rate, int frequency, int gain = 496); 34 | bool StopAndCloseRtl(); 35 | int indexBySerial(const char *serial); 36 | 37 | 38 | signals: 39 | 40 | void fftData(const std::vector &data); 41 | 42 | public slots: 43 | 44 | void demodData(const float*,int); 45 | void fftVFOSlot(QString topic); 46 | 47 | // socket stuff 48 | void connected(); 49 | void disconnected(); 50 | void bytesWritten(qint64 bytes); 51 | void readyRead(); 52 | 53 | private: 54 | 55 | bool sendCommand(char cmd, char* val); 56 | bool tcp_active; 57 | std::vector samples; 58 | int count; 59 | QVector * mpVFOs; 60 | cpx_typef avecpt; 61 | 62 | float val; 63 | float one; 64 | 65 | bool emitFFT; 66 | bool correctDC; 67 | 68 | QTcpSocket *tcpSocket = nullptr; 69 | 70 | QByteArray tcpData; 71 | 72 | QVector tcpFloats; 73 | 74 | 75 | }; 76 | 77 | #endif // SDRJ_H 78 | -------------------------------------------------------------------------------- /vfo.cpp: -------------------------------------------------------------------------------- 1 | #include "vfo.h" 2 | #include "gnuradio/firfilter.h" 3 | #include "iostream" 4 | 5 | ZmqPublisher vfo::bind_publisher; 6 | vfo::vfo(QObject *parent) : QObject(parent) 7 | { 8 | 9 | gain = 0.01; 10 | 11 | avecpt = 0; 12 | val = 0.000001; 13 | one = 1.0; 14 | 15 | demodUSB = true; 16 | filterAudio = false; 17 | filterbw = 0; 18 | offsetbw = 0; 19 | mpVFOs = 0; 20 | 21 | laststageDecimate = false; 22 | discard = 0; 23 | emitFFT = false; 24 | scalecomp = 1; 25 | fir_decI = NULL; 26 | fir_decQ = NULL; 27 | osc_mix = NULL; 28 | osc_bfo = NULL; 29 | philbert = NULL; 30 | fir_usb = NULL; 31 | } 32 | 33 | 34 | vfo::~vfo() 35 | { 36 | 37 | for(int a = 0; alength() > 0 ) 52 | { 53 | for(int a = 0; a length(); a++) 54 | { 55 | delete mpVFOs->at(a); 56 | } 57 | } 58 | 59 | } 60 | void vfo::init(int samplesPerBuffer, bool bind, int lateDecimate) 61 | { 62 | 63 | firfilter filt; 64 | osc_mix = new Oscillator(Fs, mixer_freq); 65 | 66 | int targetRate = Fs/(pow(2,decimateCount)); 67 | int samplesOut = samplesPerBuffer/(pow(2,decimateCount)); 68 | 69 | // samples per buffer should be multiple of 12000 otherwise we need to do one last decimation 4/5 70 | if(demodUSB && lateDecimate >0) 71 | { 72 | laststageDecimate = true; 73 | discard = lateDecimate-1; 74 | 75 | targetRate = (targetRate/lateDecimate); 76 | samplesOut = (samplesOut/lateDecimate); 77 | 78 | int firlen = 0; 79 | 80 | 81 | 82 | QVector coeff = filt.low_pass(2, 83 | targetRate*lateDecimate, 84 | targetRate/2, 85 | (double)targetRate/(lateDecimate-1), 86 | firfilter::win_type::WIN_HAMMING, 87 | 0); 88 | firlen = coeff.length(); 89 | fir_decI = new FIR(firlen, 0); 90 | fir_decQ = new FIR(firlen, 0); 91 | 92 | for(int i=0;iFIRSetPoint(i,coeff[i]); 95 | fir_decQ->FIRSetPoint(i,coeff[i]); 96 | } 97 | 98 | 99 | 100 | 101 | } 102 | outputRate = targetRate; 103 | osc_bfo = new Oscillator(outputRate, offsetbw); 104 | 105 | 106 | if(filterbw >0) 107 | { 108 | 109 | 110 | QVector coeff = filt.low_pass(2, 111 | targetRate, 112 | filterbw, 113 | (double)filterbw/4, 114 | firfilter::win_type::WIN_HAMMING, 115 | 0); 116 | 117 | 118 | fir_usb=new FIR(coeff.length(), 0); 119 | for(int i=0;iFIRSetPoint(i,coeff[i]); 122 | 123 | } 124 | } 125 | 126 | 127 | for(int a = 0; a & samples) 236 | { 237 | for(long unsigned int i=0;i_vector*samples.at(i); 242 | osc_mix->tick(); 243 | 244 | decimate[0][i]=curr; 245 | } 246 | // decimate 247 | for(int i = 0; idecimate(decimate[i], decimate[i+1]); 251 | } 252 | 253 | if(mpVFOs != 0 && mpVFOs->length() > 0 ) 254 | { 255 | 256 | 257 | for(int a = 0; alength(); a++) 258 | { 259 | vfo * pvfo = mpVFOs->at(a); 260 | 261 | pvfo->process(decimate[decimateCount]); 262 | 263 | } 264 | 265 | 266 | } 267 | else 268 | { 269 | if(demodUSB) 270 | { 271 | 272 | if(!laststageDecimate) 273 | { 274 | usb_demod(); 275 | } 276 | else 277 | { 278 | usb_decimdemod(); 279 | } 280 | } 281 | else 282 | { 283 | compress(); 284 | } 285 | 286 | transmitData(); 287 | } 288 | 289 | 290 | if(emitFFT) 291 | { 292 | emit fftData( decimate[decimateCount]); 293 | } 294 | 295 | 296 | } 297 | 298 | 299 | 300 | void vfo::usb_demod() 301 | { 302 | 303 | for (long unsigned int i = 0; i < decimate[decimateCount].size(); i++) { 304 | 305 | cpx_typef curr = decimate[decimateCount][i]; 306 | 307 | if(offsetbw > 1){ 308 | 309 | curr = osc_bfo->_vector*curr; 310 | osc_bfo->tick(); 311 | 312 | } 313 | 314 | float usb = 0; 315 | 316 | if(filterbw > 0) 317 | { 318 | usb = fir_usb->FIRUpdateAndProcess(delayT.update_dont_touch(curr.real()) - philbert->FIRUpdateAndProcess(curr.imag())); 319 | 320 | } 321 | 322 | else 323 | { 324 | usb = delayT.update_dont_touch(curr.real()) - philbert->FIRUpdateAndProcess(curr.imag()); 325 | 326 | } 327 | 328 | transmit_usb[i] = usb * gain * 32768.0; 329 | 330 | } 331 | 332 | } 333 | 334 | void vfo::usb_decimdemod() 335 | { 336 | 337 | 338 | int mark = 0; 339 | int check = 0; 340 | for (long unsigned int i = 0; i < decimate[decimateCount].size(); i++) { 341 | 342 | cpx_typef curr = decimate[decimateCount][i]; 343 | 344 | // low pass 345 | 346 | if(offsetbw > 1){ 347 | curr = osc_bfo->_vector*curr; 348 | osc_bfo->tick(); 349 | } 350 | 351 | if(check== 0) 352 | { 353 | 354 | curr = cpx_typef(fir_decI->FIRUpdateAndProcess(curr.real()), fir_decQ->FIRUpdateAndProcess(curr.imag())); 355 | 356 | float usb = delayT.update_dont_touch(curr.real()) - philbert->FIRUpdateAndProcess(curr.imag()); 357 | 358 | if(filterbw > 0) 359 | { 360 | usb = fir_usb->FIRUpdateAndProcess(usb); 361 | 362 | } 363 | 364 | transmit_usb[mark] = usb * gain * 32768.0; 365 | mark++; 366 | check++; 367 | 368 | } 369 | 370 | else if( check == discard) 371 | { 372 | fir_decI->FIRUpdate(curr.real()); 373 | fir_decQ->FIRUpdate(curr.imag()); 374 | 375 | check = 0; 376 | } 377 | else 378 | { 379 | fir_decI->FIRUpdate(curr.real()); 380 | fir_decQ->FIRUpdate(curr.imag()); 381 | check++; 382 | } 383 | 384 | 385 | } 386 | 387 | } 388 | 389 | void vfo::compress() 390 | { 391 | 392 | 393 | if(cstyle==1) 394 | { 395 | 396 | // drop 4 LSB och each arm and combine into 1 byte 397 | for (long unsigned int i = 0; i < decimate[decimateCount].size(); i++) { 398 | 399 | cpx_typef curr = decimate[decimateCount][i]; 400 | 401 | signed char real = (curr.real()/scalecomp)*128; 402 | signed char imag = (curr.imag()/scalecomp)*128; 403 | 404 | transmit_iq[i] = ( (real & 0xF0) | (imag & 0xF0) >> 4 ); 405 | 406 | } 407 | 408 | } 409 | 410 | else 411 | { 412 | 413 | for (long unsigned int i = 0; i < decimate[decimateCount].size(); i++) { 414 | 415 | cpx_typef curr = decimate[decimateCount][i]; 416 | 417 | transmit_iq[2*i] = curr.real()*128; 418 | transmit_iq[2*i+1]= curr.imag()*128; 419 | 420 | } 421 | 422 | } 423 | 424 | } 425 | 426 | void vfo::transmitData(){ 427 | 428 | if(demodUSB) 429 | { 430 | if(zmqBind) 431 | { 432 | vfo::bind_publisher.publish((unsigned char*)transmit_usb.data(), transmit_usb.size()*sizeof(short), zmqTopic, outputRate); 433 | } 434 | else 435 | { 436 | connect_publisher.publish((unsigned char*)transmit_usb.data(), transmit_usb.size()*sizeof(short), zmqTopic, outputRate); 437 | } 438 | } 439 | else if(zmqTopic.length()>0) 440 | { 441 | 442 | if(zmqBind) 443 | { 444 | bind_publisher.publish((unsigned char*)transmit_iq.data(), transmit_iq.size()*sizeof(char), zmqTopic, outputRate); 445 | } 446 | else 447 | { 448 | connect_publisher.publish((unsigned char*)transmit_iq.data(), transmit_iq.size()*sizeof(char), zmqTopic,outputRate); 449 | 450 | } 451 | } 452 | 453 | } 454 | 455 | void vfo::setCompressonStyle(int st) 456 | { 457 | 458 | cstyle = st; 459 | 460 | } 461 | 462 | void vfo::setScaleComp(int scale) 463 | { 464 | 465 | scalecomp = scale; 466 | 467 | } 468 | void vfo::setDemodUSB(bool usb) 469 | { 470 | 471 | demodUSB = usb; 472 | } 473 | 474 | bool vfo::getDemodUSB() 475 | { 476 | return demodUSB; 477 | } 478 | void vfo::setFilter(bool filter, int bw ) 479 | { 480 | 481 | filterAudio = filter; 482 | filterbw = bw; 483 | } 484 | 485 | void vfo::setVFOs(QVector * vfos) 486 | { 487 | 488 | mpVFOs = vfos; 489 | 490 | } 491 | 492 | void vfo::fftVFOSlot(QString topic) 493 | { 494 | 495 | if(topic.compare(zmqTopic) ==0) 496 | { 497 | 498 | emitFFT = true; 499 | 500 | FFTcount = 0; 501 | } 502 | else 503 | { 504 | emitFFT = false; 505 | 506 | FFTcount = 0; 507 | } 508 | 509 | } 510 | -------------------------------------------------------------------------------- /vfo.h: -------------------------------------------------------------------------------- 1 | #ifndef VFO_H 2 | #define VFO_H 3 | 4 | #include "qstring.h" 5 | #include "zmqpublisher.h" 6 | #include "halfbanddecimator.h" 7 | #include "oscillator.h" 8 | 9 | 10 | 11 | class vfo : public QObject 12 | { 13 | 14 | Q_OBJECT 15 | 16 | public: 17 | 18 | ~vfo(); 19 | vfo(QObject *parent = 0); 20 | 21 | void init(int samplesPerBuffer, bool bind, int lateDecimate = 0); 22 | void process(const std::vector & samples); 23 | void setZmqAddress(QString bind); 24 | void setZmqTopic(QString topic); 25 | void setScaleComp(int scale); 26 | void setFs(int samplerate); 27 | void setDecimationCount(int count); 28 | void setMixerFreq(double freq); 29 | double getMixerFreq(); 30 | int getOutRate(); 31 | void setOffsetBandwidth(double bw); 32 | void setFilterBandwidth(double bw); 33 | void setGain(float g); 34 | void setDemodUSB(bool usb); 35 | bool getDemodUSB(); 36 | void setCompressonStyle(int st); 37 | void setFilter(bool filter, int bw = 0); 38 | void setVFOs(QVector *pVFOs); 39 | std::vector decimate[9]; 40 | QVector * mpVFOs; 41 | 42 | 43 | 44 | signals: 45 | 46 | void fftData(const std::vector &data); 47 | 48 | public slots: 49 | void fftVFOSlot(QString topic); 50 | 51 | private: 52 | 53 | QString zmqAddress; 54 | QString zmqConnect; 55 | QString zmqTopic; 56 | int Fs; 57 | bool zmqBind; 58 | 59 | //static publisher when binding 60 | static ZmqPublisher bind_publisher; 61 | ZmqPublisher connect_publisher; 62 | 63 | HalfBandDecimator * hdecimator[8]; 64 | 65 | 66 | QVector out; 67 | 68 | std::vector transmit_usb; 69 | std::vector transmit_iq; 70 | 71 | 72 | FIR * fir_usb; 73 | FIRHilbert * philbert; 74 | DelayThing delayT; 75 | 76 | FIR * fir_decI; 77 | FIR * fir_decQ; 78 | 79 | int decimateCount; 80 | uint32_t outputRate; 81 | 82 | //WaveTable * mix_bfo; 83 | Oscillator * osc_bfo; 84 | Oscillator * osc_mix; 85 | 86 | float gain; 87 | 88 | double mixer_freq; 89 | double bandwidth; 90 | void usb_demod(); 91 | void usb_decimdemod(); 92 | void compress(); 93 | void transmitData(); 94 | 95 | bool demodUSB; 96 | bool filterAudio; 97 | 98 | int cstyle = 0; 99 | 100 | cpx_typef avecpt; 101 | float val; 102 | float one; 103 | 104 | int filterbw; 105 | int offsetbw; 106 | 107 | bool laststageDecimate; 108 | int discard; 109 | 110 | bool emitFFT; 111 | 112 | int FFTcount; 113 | 114 | int scalecomp; 115 | 116 | }; 117 | 118 | #endif // VFO_H 119 | -------------------------------------------------------------------------------- /zmqpublisher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "zmqpublisher.h" 3 | #include "qmessagebox.h" 4 | 5 | 6 | ZmqPublisher::ZmqPublisher() 7 | { 8 | 9 | bind = false; 10 | bindAddress = "tcp://*:6002"; 11 | connected = false; 12 | } 13 | 14 | 15 | void ZmqPublisher::connect() 16 | { 17 | 18 | if(!connected) 19 | { 20 | 21 | context = zmq_ctx_new(); 22 | publisher = zmq_socket(context, ZMQ_PUB); 23 | 24 | int keepalive = 1; 25 | int keepalivecnt = 10; 26 | int keepaliveidle = 1; 27 | int keepaliveintrv = 1; 28 | int reconnectInterval = 1000; 29 | int maxReconnectInterval = 0; 30 | 31 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE,(void*)&keepalive, sizeof(ZMQ_TCP_KEEPALIVE)); 32 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_CNT,(void*)&keepalivecnt,sizeof(ZMQ_TCP_KEEPALIVE_CNT)); 33 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_IDLE,(void*)&keepaliveidle,sizeof(ZMQ_TCP_KEEPALIVE_IDLE)); 34 | zmq_setsockopt(publisher, ZMQ_TCP_KEEPALIVE_INTVL,(void*)&keepaliveintrv,sizeof(ZMQ_TCP_KEEPALIVE_INTVL)); 35 | 36 | zmq_setsockopt(publisher, ZMQ_RECONNECT_IVL,(void*)&reconnectInterval,sizeof(ZMQ_RECONNECT_IVL)); 37 | zmq_setsockopt(publisher, ZMQ_RECONNECT_IVL_MAX,(void*)&maxReconnectInterval,sizeof(ZMQ_RECONNECT_IVL_MAX)); 38 | 39 | 40 | 41 | std::string connected_url = bindAddress.toUtf8().constData(); 42 | 43 | 44 | if(bind) 45 | { 46 | zmqStatus = zmq_bind(publisher, connected_url.c_str() ); 47 | 48 | if(zmqStatus <0) 49 | { 50 | 51 | int error = zmq_errno(); 52 | 53 | QMessageBox msgBox; 54 | msgBox.setText("ZeroMQ could not bind to socket on provided URL " + bindAddress + " error code: " + QString::number(error) + "\r\nCheck if the URL and check if another SDR is already running"); 55 | msgBox.exec(); 56 | } 57 | } 58 | else 59 | { 60 | zmqStatus = zmq_connect(publisher, connected_url.c_str() ); 61 | } 62 | 63 | // will set this to true regardless 64 | connected = true; 65 | 66 | } 67 | 68 | 69 | } 70 | void ZmqPublisher::setAddress(QString bind) 71 | { 72 | bindAddress = bind; 73 | 74 | } 75 | 76 | void ZmqPublisher::setBind(bool b) 77 | { 78 | 79 | bind = b; 80 | } 81 | 82 | void ZmqPublisher::publish(unsigned char *buf, uint32_t len, QString topic, uint32_t sampleRate){ 83 | 84 | std::string topic_text = topic.toUtf8().constData(); 85 | unsigned char rate[4]; 86 | memcpy(rate, &sampleRate, 4); 87 | 88 | if(len != 0) 89 | { 90 | 91 | zmq_send(publisher, topic_text.c_str(), 5, ZMQ_SNDMORE); 92 | zmq_send(publisher, rate, 4, ZMQ_SNDMORE ); 93 | zmq_send(publisher, buf, len, 0 ); 94 | } 95 | 96 | } 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /zmqpublisher.h: -------------------------------------------------------------------------------- 1 | #ifndef ZMQPUBLISHER_H 2 | #define ZMQPUBLISHER_H 3 | 4 | #include "QString" 5 | #include "zmq.h" 6 | 7 | class ZmqPublisher 8 | { 9 | public: 10 | ZmqPublisher(); 11 | 12 | void connect(); 13 | void setAddress(QString address); 14 | void setBind(bool b = false); 15 | void setTopic(QString topic); 16 | void publish(unsigned char *buf, uint32_t len, QString topic, uint32_t sampleRate); 17 | bool connected; 18 | 19 | 20 | private: 21 | 22 | void* context; 23 | void* publisher; 24 | QString bindAddress; 25 | int zmqStatus; 26 | bool bind; 27 | 28 | }; 29 | 30 | #endif // ZMQPUBLISHER_H 31 | --------------------------------------------------------------------------------