• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/workflows/H27-Dec-2021-6653

cmake/H27-Dec-2021-8672

demo/H03-May-2022-650284

doc/H03-May-2022-

misc/H03-May-2022-3,2792,299

octave/H03-May-2022-46,73740,919

raw/H03-May-2022-

script/H03-May-2022-692453

src/H03-May-2022-122,979105,991

stm32/H03-May-2022-28,80217,308

unittest/H03-May-2022-22,15420,009

wav/H03-May-2022-

.gitignoreH A D27-Dec-2021176 98

.travis.ymlH A D27-Dec-20213.4 KiB9180

COPYINGH A D27-Dec-202125.8 KiB503418

README.mdH A D27-Dec-20219.6 KiB289227

README_cohpsk.mdH A D27-Dec-2021955 4429

README_data.mdH A D27-Dec-202122 KiB353251

README_fdmdv.mdH A D27-Dec-20216.4 KiB12397

README_freedv.mdH A D27-Dec-202112.6 KiB218162

README_fsk.mdH A D27-Dec-20218.9 KiB180147

README_ofdm.mdH A D27-Dec-202110.4 KiB253197

codec2.pc.inH A D03-May-2022243 119

README.md

1# Codec 2 README
2
3Codec 2 is an open source (LGPL 2.1) low bit rate speech codec: http://rowetel.com/codec2.html
4
5Also included:
6
7  + The FreeDV API for digital voice over radio. FreeDV is an open source digital voice protocol that integrates modems, codecs, and FEC [README_freedv](README_freedv.md)
8  + APIs for raw and Ethernet packet data over radio [README_data](README_data.md)
9  + High performance coherent OFDM modem for HF channels [README_ofdm](README_ofdm.md)
10  + High performance non-coherent FSK modem [README_fsk](README_fsk.md)
11  + An STM32 embedded version of FreeDV 1600/700D/700E for the [SM1000](stm32/README.md)
12  + Coherent PSK modem [README_cohpsk](README_cohpsk.md) for HF channels
13  + FDMDV DPSK modem [README_fdmdv](README_fdmdv.md) for HF channels
14
15## Quickstart
16
171. Install packages (Debian/Ubuntu):
18   ```
19   sudo apt install git build-essential cmake
20   ```
21   Fedora/RH distros:
22   ```
23   sudo dnf groupinstall "Development Tools" "C Development Tools and Libraries"
24   sudo dnf install cmake
25   ```
26
271. Build Codec 2:
28   ```
29   git clone https://github.com/drowe67/codec2.git
30   cd codec2
31   mkdir build_linux
32   cd build_linux
33   cmake ..
34   make
35   ```
36
371. Listen to Codec 2:
38   ```
39   cd codec2/build_linux
40   ./demo/c2demo ../raw/hts1a.raw hts1a_c2.raw
41   aplay -f S16_LE ../raw/hts1a.raw
42   aplay -f S16_LE hts1a_c2.raw
43   ```
441. Compress, decompress and then play a file using Codec 2 at 2400 bit/s:
45   ```
46   ./src/c2enc 2400 ../raw/hts1a.raw hts1a_c2.bit
47   ./src/c2dec 2400 hts1a_c2.bit hts1a_c2_2400.raw
48   ```
49   which can be played with:
50   ```
51   aplay -f S16_LE hts1a_c2_2400.raw
52   ```
53   Or using Codec 2 using 700C (700 bits/s):
54   ```
55   ./src/c2enc 700C ../raw/hts1a.raw hts1a_c2.bit
56   ./src/c2dec 700C hts1a_c2.bit hts1a_c2_700.raw
57   aplay -f S16_LE hts1a_c2_700.raw
58   ```
591. If you prefer a one-liner without saving to files:
60   ```
61   ./src/c2enc 1300 ../raw/hts1a.raw - | ./src/c2dec 1300 - - | aplay -f S16_LE
62   ```
63
641. Or you can use your microphone and headphones to encode and listen to the result on the fly:
65   ```
66   br=1300; arecord -f S16_LE -c 1 -r 8000 | ./src/c2enc $br - - | ./src/c2dec $br - - | aplay -f S16_LE -
67   ```
68
69## FreeDV 2020 support (building with LPCNet)
70
711. Build codec2 initially without LPCNet
72   ```
73   cd ~
74   git clone https://github.com/drowe67/codec2.git
75   cd codec2 && mkdir build_linux && cd build_linux
76   cmake ../
77   make
78   ```
79
801. Build LPCNet:
81   ```
82   cd ~
83   git clone https://github.com/drowe67/LPCNet
84   cd LPCNet && mkdir build_linux && cd build_linux
85   cmake -DCODEC2_BUILD_DIR=~/codec2/build_linux ../
86   make
87   ```
88
891. (Re)build Codec 2 with LPCNet support:
90   ```
91   cd ~/codec2/build_linux && rm -Rf *
92   cmake -DLPCNET_BUILD_DIR=~/LPCNet/build_linux ..
93   make
94   ```
95
96## Programs
97
98+ See `demo` directory for simple examples of using Codec and the FreeDV API.
99
100+ `c2demo` encodes a file of speech samples, then decodes them and saves the result.
101
102+ `c2enc` encodes a file of speech samples to a compressed file of encoded bits.  `c2dec` decodes a compressed file of bits to a file of speech samples.
103
104+ `c2sim` is a simulation/development version of Codec 2.  It allows selective use of the various Codec 2 algorithms.  For example switching phase modelling or quantisation on and off.
105
106+ `freedv_tx` & `freedv_rx` are command line implementations of the FreeDV protocol, which combines Codec 2, modems, and Forward Error Correction (FEC).
107
108+ `cohpsk_*` are coherent PSK (COHPSK) HF modem command line programs.
109
110+ `fdmdv_*` are differential PSK HF modem command line programs (README_fdmdv).
111
112+ `fsk_*` are command line programs for a non-coherent FSK modem (README_fsk).
113
114+ `ldpc_*` are LDPC encoder/decoder command line programs, based on the CML library.
115
116+ `ofdm_*` are OFDM PSK HF modem command line programs (README_ofdm).
117
118## Building and Running Unit Tests
119
120CTest is used as a test framework, with support from [GNU Octave](https://www.gnu.org/software/octave/) scripts.
121
1221. Install GNU Octave and libraries on Ubuntu with:
123   ```
124   sudo apt install octave octave-common octave-signal liboctave-dev gnuplot python3-numpy sox valgrind
125   ```
1261. To build and run the tests:
127   ```
128   cd ~/codec2
129   rm -Rf build_linux && mkdir build_linux
130   cd build_linux
131   cmake -DUNITTEST=1 ..
132   make
133   ```
134
1351. To just run tests without rebuilding:
136   ```
137   ctest
138   ```
139
1401. To get a verbose run (e.g. for test debugging):
141   ```
142   ctest -V
143   ```
144
1451. To just run a single test:
146   ```
147   ctest -R test_OFDM_modem_octave_port
148   ```
149
1501. To list the available tests:
151   ```
152   ctest -N
153   ```
154
1551. Many Octave scripts rely on the CML LDPC library.  To run these from the Octave CLI, you need to set
156   the `CML_PATH` environment variable.  A convenient way to do this is using a `.octaverc` file
157   in your `codec/octave` directory.  For example on a Linux machine, create a `.octaverc` file:
158   ```
159   setenv("CML_PATH","../build_linux/cml")
160   ```
161
162## Directories
163```
164cmake       - cmake support files
165demo        - Simple Codec 2 and FreeDv API demo applications
166misc        - misc C programs that have been useful in development,
167              not reqd for Codec 2 release. Part of Debug build.
168octave      - Octave scripts used to support development
169script      - shell scripts for playing and converting raw files
170src         - C source code for Codec 2, FDMDV modem, COHPSK modem, FreeDV API
171raw         - speech files in raw format (16 bits signed linear 8 kHz)
172stm32       - STM32F4 microcontroller and SM1000 FreeDV Adaptor support
173unittest    - Code to perform and support testing. Part of Debug build.
174wav         - speech files in wave file format
175```
176## GDB and Dump Files
177
1781. To compile with debug symbols for using gdb:
179   ```
180   cd ~/codec2
181   rm -Rf build_linux && mkdir build_linux
182   cd build_linux
183   CFLAGS=-g cmake ..
184   make
185   ```
186
1871. For dump file support (dump data from c2sim for input to Octave development scripts):
188   ```
189   cd ~/codec2
190   rm -Rf build_linux && mkdir build_linux
191   cd build_linux
192   CFLAGS=-DDUMP cmake ..
193   make
194   ```
195
196## Building for Windows on a Linux machine
197
198On Ubuntu 17 and above:
199   ```
200   sudo apt-get install mingw-w64
201   mkdir build_windows && cd build_windows
202   cmake .. -DCMAKE_TOOLCHAIN_FILE=/home/david/freedv-dev/cmake/Toolchain-Ubuntu-mingw32.cmake -DUNITTEST=FALSE -DGENERATE_CODEBOOK=/home/david/codec2/build_linux/src/generate_codebook
203   make
204   ```
205
206## Building for Windows on a Windows machine
207
208 ```
209 mkdir build_windows (Or what ever you want to call your build dir)
210 cmake -G "MinGW Makefiles" -D CMAKE_MAKE_PROGRAM=mingw32-make.exe
211 Or if you use ninja for building cmake -G "Ninja" ..
212 mingw32-make or ninja  depends on what you used in the last command
213 wait for it to build.
214 ```
215
216
217## Including Codec 2 in an Android project
218
219In an Android Studio 'NDK' project (a project that uses 'native' code)
220Codec 2 can be added to the project in the following way.
221
2221. Add the Codec 2 source tree to your app (e.g. in app/src/main/codec2)
223   (e.g. as a git sub-module).
224
2251. Add Codec 2 to the CMakeList.txt (app/src/main/cpp/CMakeLists.txt):
226
227    ```
228    # Sets lib_src_DIR to the path of the target CMake project.
229    set( codec2_src_DIR ../codec2/ )
230    # Sets lib_build_DIR to the path of the desired output directory.
231    set( codec2_build_DIR ../codec2/ )
232    file(MAKE_DIRECTORY ${codec2_build_DIR})
233
234    add_subdirectory( ${codec2_src_DIR} ${codec2_build_DIR} )
235
236    include_directories(
237	    ${codec2_src_DIR}/src
238	    ${CMAKE_CURRENT_BINARY_DIR}/../codec2
239    )
240    ```
241
2421. Add Codec 2 to the target_link_libraries in the same file.
243
244## Building Codec 2 for Microcontrollers
245
246Codec 2 requires a hardware Floating Point Unit (FPU) to run in real time.
247
248Two build options have been added to support building on microcontrollers:
2491. Setting the `cmake` variable MICROCONTROLLER_BUILD disables position independent code (-fPIC is not used).  This was required for the IMRT1052 used in Teensy 4/4.1).
250
2511. On ARM machines, setting the C Flag \_\_EMBEDDED\_\_ and linking with the ARM CMSIS library will improve performance on ARM-based microcontrollers. \_\_REAL\_\_ and FDV\_ARM\_MATH are additional ARM-specific options that can be set to improve performance if required, especially with OFDM modes.
252
253A CMakeLists.txt example for a microcontroller is below:
254
255```
256set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
257set(MICROCONTROLLER_BUILD 1)
258
259set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlittle-endian -ffunction-sections -fdata-sections -g -O3")
260set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -ffunction-sections -fdata-sections")
261
262add_definitions(-DCORTEX_M7 -D__EMBEDDED__)
263add_definitions(-DFREEDV_MODE_EN_DEFAULT=0 -DFREEDV_MODE_1600_EN=1 -DFREEDV_MODE_700D_EN=1 -DFREEDV_MODE_700E_EN=1 -DCODEC2_MODE_EN_DEFAULT=0 -DCODEC2_MODE_1300_EN=1 -DCODEC2_MODE_700C_EN=1)
264
265FetchContent_Declare(codec2
266    GIT_REPOSITORY https://github.com/drowe67/codec2.git
267    GIT_TAG origin/master
268    GIT_SHALLOW ON
269    GIT_PROGRESS ON
270)
271FetchContent_GetProperties(codec2)
272if(NOT ${codec2_POPULATED})
273    FetchContent_Populate(codec2)
274endif()
275set(CMAKE_REQUIRED_FLAGS "")
276
277set(LPCNET OFF CACHE BOOL "")
278add_subdirectory(${codec2_SOURCE_DIR} ${codec2_BINARY_DIR} EXCLUDE_FROM_ALL)
279```
280
281## Building Debian packages
282
283To build Debian packages, simply run the "cpack" command after running "make". This will generate the following packages:
284
285+ codec2: Contains the .so and .a files for linking/executing applications dependent on Codec2.
286* codec2-dev: Contains the header files for development using Codec2.
287
288Once generated, they can be installed with "dpkg -i" (once LPCNet is installed). If LPCNet is not desired, CMakeLists.txt can be modified to remove that dependency.
289

README_cohpsk.md

1# README_cohpsk.md
2
3## Introduction
4
5## Quickstart
6
71. BER test in AWGN channel with just less that 2% average bit error rate:
8
9   ```
10    $ ./cohpsk_get_test_bits - 5600 | ./cohpsk_mod - - | ./cohpsk_ch - - -30 | ./cohpsk_demod - - | ./cohpsk_put_test_bits -
11    <snip>
12    SNR3k(dB):  3.41 C/No: 38.2 PAPR:  8.1
13    BER: 0.017 Nbits: 5264 Nerrors: 92
14
15  ```
16
172. Plot some of the demod internal states, used to chase down freq offset problemL
18
19   ```
20    $ cd build_linux/src
21    $ ./cohpsk_get_test_bits - 5600 | ./cohpsk_mod - -  | ./cohpsk_ch - - -40 -f -20 | ./cohpsk_demod -o cohpsk_demod.txt - - | ./cohpsk_put_test_bits -
22    $ cd ../../octave
23    $ octave --no-gui
24    $ cohpsk_demod_plot("../build_linux/src/cohpsk_demod.txt")
25   ```
26
273. Run Octave<-> tests
28
29   ```
30   $ cd ~/codec2/build_linux/unittest
31   $ ./tochpsk
32   $ cd ~/codec2/octave
33   $ octave --no-gui
34   octave> tcohpsk
35   ```
36
37## References
38
39## C Code
40
41## Octave Scripts
42
43
44

README_data.md

1# README_data.md
2
3# Introduction
4
5FreeDV can be used to send data over radio channels.  Two APis are supported:
6+ VHF packet data channel which uses Ethernet style framing.
7+ Raw frames of modem data over VHF and HF channels.
8
9## Credits
10
11The VHF data channel was developed by Jeroen Vreeken.
12
13## Quickstart
14
15VHF packet data API:
16
171. Simple test using mode 2400A and VHF packet data
18
19   ```sh
20   $ cd ~/codec2/build_linux
21   $ ./src/freedv_data_tx 2400A - --frames 15 | ./src/freedv_data_rx 2400A -
22
23   ```
24   You can listen to the modem signal using:
25   ```sh
26   $ ./src/freedv_data_tx 2400A - --frames 15 | aplay -f S16_LE -r 48000
27
28   ```
29
302. Same for 2400B and 800XA
31
32   ```sh
33   $ ./src/freedv_data_tx 2400B - --frames 15 | ./src/freedv_data_rx 2400B -
34   $ ./src/freedv_data_tx 800XA - --frames 15 | ./src/freedv_data_rx 800XA -
35
36   ```
37
383. Using a different callsign and secondary station id
39
40   ```sh
41   $ ./src/freedv_data_tx 2400A - --callsign T3ST --ssid 15 --frames 15 | src/freedv_data_rx 2400A -
42   ```
43
44Raw modem frame API:
45
461. Let's send a 128 byte frame containing some text over the modem:
47   ```sh
48   padding=$(head -c 115 < /dev/zero | tr '\0' '-'); echo "Hello World" $padding > in.txt
49   ./src/freedv_data_raw_tx --bursts 1 datac3 in.txt - | ./src/freedv_data_raw_rx --framesperburst 1 datac3 - -
50   Hello World --------
51   ```
52   Note we've padded the input frame to 126 bytes, the DATAC3 framesize (less CRC).
53
54# VHF Packet Data Channel
55
56The FreeDV VHF data channel operates on a packet level. The FreeDV modems however typically operate on a fixed frame base. This means that data packets have to be sent in multiple frames.
57
58The packet format is modeled after Ethernet. As a result, any protocol that is compatible with Ethernet can potentially be used over a FreeDV data link. (There are of course practical limits. Browsing the world wide web with just a few hundred bits per second will not be a pleasant experience.)
59
60## Header optimization
61
62When there are no packets available for transmission a small 'filler' packet with just the sender's address will be sent.
63When there is a packet available not all of the header needs to be sent. The sender's address can often be left out if it was already sent in a previous frame. Likewise when the packet has no specific destination but is targeted at a multicast address, this can also be transmitted in a single bit as opposed to a 6 byte broadcast address.
64
65
66## Addressing
67
68Since the format is based on Ethernet, a 6 byte sender and destination address is used. It is possible to encode an ITU compatible callsign in these bytes. See http://dmlinking.net/eth_ar.html for more info. Or have a look at freedv_data_tx.c and freedv_data_rx.c for an actual implementation.
69
70## Packet types
71
72The 2 byte EtherType field is used to distinguish between various protocols.
73
74## Checks
75
76Not all channels are perfect, and especially since a packet is split up over multiple frames, bits might get lost. Each packet therefore has a CRC which is checked before it is accepted.  Note there is No FEC on 2400A/2400B/800XA.
77
78## Available modes
79
80The data channel is available for modes 2400A, 2400B and 800XA.
81
82## API
83
84The data channel is part of the regular FreeDV API.
85
86### Initialization
87
88After creating a new freedv instance with freedv_open(), a few more calls need to be done before the data channel is usable.
89
90  ```
91   void freedv_set_data_header             (struct freedv *freedv, unsigned char *header);
92  ```
93
94The address that will be used for 'filler' packets must be set. The freedv_set_data_header() function must be called with a 6 byte header.
95
96  ```
97   typedef void (*freedv_callback_datarx)(void *, unsigned char *packet, size_t size);
98   typedef void (*freedv_callback_datatx)(void *, unsigned char *packet, size_t *size);
99   void freedv_set_callback_data           (struct freedv *freedv, freedv_callback_datarx datarx, freedv_callback_datatx datatx, void *callback_state);
100  ```
101
102Using freedv_set_callback_data() two callback functions can be provided. The datarx callback will be used whenever a new data packet has been successfully received. The datatx callback will be used when a new data packet is required for transmission.
103
104### Operation
105
106  ```
107   void freedv_datatx  (struct freedv *f, short mod_out[]);
108  ```
109
110During normal operation the freedv_datatx() function can be used whenever a data frame has to be sent. If no data is available it will request new data using the datatx callback. The callback function is allowed to set 'size' to zero if no data is available or if it wishes to send an address frame.
111
112For reception the regular freedv_rx() functions can be used as received data will automatically be reported using the datarx callback. Be aware that these functions return the actual number of received speech samples. When a data frame is received the return value will be zero. This may lead to 'gaps' in the audio stream which will have to be filled with silence.
113
114### Examples
115
116The freedv_data_tx and freedv_data_rx test programs implement the minimum needed to send and receive data packets.
117
118## Mixing voice and data
119
120Encoding only voice data is easy with the FreeDV API. Simply use the freedv_tx() function and provide it with speech samples.
121Likewise encoding only data is also easy. Make sure to provide a source of data frames using the freedv_set_callback_data() function, and use the freedv_datatx() function to generate frames.
122
123However there are many use cases where one would like to transmit a mix of voice and data. For example one might want to transmit their callsign in a machine readable format, or a short position report. There are a few ways to do this:
124
125### Data bursts at start and/or end of transmission
126
127This method simply transmits voice frames during the transmission, except for a few moments. For example when the user keys the radio the software uses the freedv_datatx() function for a number of frames before switching to regular voice frames.
128Likewise when the user releases the key the software may hold it for a number of frames to transmit data before it releases the actual radio.
129
130Be careful though: depending on your setup (radio, PC, soundcard, etc) the generated frames and the keying of your radio might not be perfectly in sync and the first or last frames might be lost in the actual transmission. Make sure to take this into account when using this method.
131
132### Data and voice interleaved
133
134Another method is to generate a mixed stream of frames. Compared to a small burst at the beginning or end a lot more data can be sent. We only need a way to choose between voice or data such that the recovered speech at the other side is not impacted.
135
136#### Detect voice activity
137
138When it is possible to determine activity in the voice signal (and it almost always is) this presence can be used to insert a data frame by calling freedv_datatx() instead of freedv_tx()/freedv_codectx(). This method is used in the freedv_mixed_tx demo program. When the option --codectx is given the codec2 library is used to determine the activity.
139
140  ```
141   $ ./src/freedv_mixed_tx 2400A ../raw/hts1a.raw - --codectx | src/freedv_data_rx 2400A -
142   $ ./src/freedv_mixed_tx 2400A ../raw/hts1a.raw - | src/freedv_data_rx 2400A -
143  ```
144
145The advantage of this method is that the audio is not distorted, there was nothing (or near nothing) to distort. A drawback is that constant voice activity may mean there are insufficient frames for data.
146
147### Receiving mixed voice and data
148
149Receiving and decoding a mixed voice and data stream is (almost) as easy as receiving a regular voice-only transmission.
150One simply uses the regular API calls for reception of speech samples. In addition, the callback functions are used for data.
151There is one caveat though: when a data frame is received the API functions (like freedv_rx) will return zero as this is the amount of codec/voice data received.
152For proper playback silence (or comfort noise) should be inserted for the duration of a frame to restore the timing of the original source speech samples.
153An example of how this is done is provided in freedv_mixed_rx
154
155  ```
156   $ ./src/freedv_mixed_tx 2400A ../raw/hts1a.raw - | src/freedv_mixed_rx 2400A - ./hts1a_out.raw
157  ```
158
159### Insert a data frame periodically
160
161This is a very simple method, simply insert a data frame every n frames, (e.g. once every 10 seconds). Since single FreeDV frames are relatively short (tens of milliseconds) the effect on received audio will be minor. The advantage of this method is that one can create a guaranteed amount of data bandwidth. A drawback is some interruption in the audio that may be noticed.
162
163### Combination of the above.
164
165A combination of the two methods may also be used. Send data when no voice is active and insert a frame when this does not occur for a long time.
166
167# Raw Data using the FreeDV API
168
169The raw data API can be used to send frames of bytes over radio channels.   The frames are protected with FEC and have a 16-bit checksum to verify correct transmission.  However the raw data API may lose frames due to channel impairments, loss of sync, or acquisition delays.  The caller must handle these situations.  The caller is also responsible for segmentation/re-assembly of the modem frames into larger blocks of data.
170
171Several modes are available which support FSK and OFDM modulation. FSK is aimed at VHF And UHF applications, and the OFDM modes have been optimised for multipath HF radio channels.
172
173For simple examples of how use the FreeDV API with raw data frames, see the demo programs [freedv_data1_tx.c](demo/freedv_data1_tx.c) and [freedv_data1_rx.c](src/freedv_data1_rx.c) The full featured sample programs [freedv_data_raw_tx.c](src/freedv_data_raw_tx.c) and [freedv_data_raw_rx.c](src/freedv_data_raw_rx.c) can be used to experiment with the raw data API.
174
175## FSK LDPC Raw Data Mode
176
177The FSK_LDPC mode uses 2 or 4 FSK in combination with powerful LDPC codes, and was designed for VHF or UHF AWGN channels. Parameters such as the number of FSK tones, sample rate, symbol rate, and LDPC code can be selected at initialisation time.  The frame format is:
178```
179| Preamble | UW | payload data | CRC | parity | UW | payload data | CRC | parity | ........... |
180           | frame 1 -------------------------| frame 2 -------------------------| ... frame n |
181```
182Only one preamble is transmitted for each data burst, which can contain as many frames as you like.  Each frame starts with a 32 bit Unique Word (UW), then the FEC codeword consisting of the data and parity bits.  At the end of the data bits, we reserve 16 bits for a CRC.
183
184Here is an example of sending some text:
185```
186$ cd codec2/build_linux/src
187$ echo 'Hello World                    ' |
188  ./freedv_data_raw_tx FSK_LDPC - - 2>/dev/null |
189  ./freedv_data_raw_rx FSK_LDPC - - 2>/dev/null |
190  hexdump -C
19100000000  48 65 6c 6c 6f 20 57 6f  72 6c 64 20 20 20 20 20  |Hello World     |
19200000010  20 20 20 20 20 20 20 20  20 20 20 20 20 20        |              ..|
19300000020
194```
195Notes:
1961. The input data is padded to 30 bytes.  The (512,256) code sends 256 data bits every frame, we reserve 16 for a CRC, so there are 240 bits, or 30 bytes of payload data required for one frame.
1971. The '2>/dev/null' command redirects stderr to nowhere, removing some of the debug information the test programs usually display to make this example easier to read.
198
199When testing, it's convenient to use an internal source of test data. Here is an example where we send a single burst of 10 test frames:
200```
201$ cd codec2/build_linux/src
202$ ./freedv_data_raw_tx --testframes 10 FSK_LDPC /dev/zero - | ./freedv_data_raw_rx --testframes FSK_LDPC - /dev/null
203Nbits: 50 N: 4000 Ndft: 1024
204bits_per_modem_frame: 256 bytes_per_modem_frame: 32
205bytes_per_modem_frame: 32
206Frequency: Fs:  8.0 kHz Rs:  0.1 kHz Tone1:  1.0 kHz Shift:  0.2 kHz M: 2
207
208frames processed: 131  output bytes: 320 output_packets: 10
209BER......: 0.0000 Tbits:  5440 Terrs:     0
210Coded BER: 0.0000 Tbits:  2560 Terrs:     0
211```
212The default is 100 bits/s 2FSK. The (512,256) code sends 256 data bits (32 bytes) with every codeword, the remaining 256 bits reserved for parity.  The `--testframes` mode reports `320 output bytes` (10 frames where sent), and `Tbits: 2560`, so all of our data made it through.
213
214In real world operation, 16 of the data bits are reserved for a CRC, leaving 240 payload data bits per frame. Taking into account the overhead of the UW, CRC, and parity bits, we send 240 payload data bits for every out of 544, so the payload data rate in this example is (240/512)*(100 bits/s) = 44.1 bits/s.
215
216We can add some channel noise using the `cohpsk_ch` tool and see how it performs:
217```
218$ ./freedv_data_raw_tx --testframes 1 --bursts 10 FSK_LDPC /dev/zero - |
219  ./cohpsk_ch - - -5 --Fs 8000 --ssbfilt 0 |
220  ./freedv_data_raw_rx --testframes -v FSK_LDPC - /dev/null
221<snip>
222frames processed: 336  output bytes: 320 output_packets: 10
223BER......: 0.0778 Tbits:  5440 Terrs:   423
224SNR3k(dB): -13.00 C/No: 21.8 PAPR:  7.5
225Coded BER: 0.0000 Tbits:  2560 Terrs:     0
226```
227The `cohpsk_ch` stderr reporting is mixed up with the testframes results but we can see that over a channel with a -13dB SNR, we obtained a raw bit error rate of 0.0778 (nearly 8%).  However the LDPC code cleaned that up nicely and still received all 10 packets with no errors.
228
229Here is an example running 4FSK at 20000 bits/s (10000 symbols/s), at a sample rate of 200 kHz:
230```
231$./freedv_data_raw_tx -m 4 --Fs 200000 --Rs 10000 --tone1 10000 --shift 10000 --testframes 100 --bursts 10 FSK_LDPC /dev/zero - |
232 ./cohpsk_ch - - -12 --Fs 8000 --ssbfilt 0 |
233 ./freedv_data_raw_rx -m 4 --testframes -v --Fs 200000 --Rs 10000 FSK_LDPC --mask 10000 - /dev/null
234 <snip>
235 frames processed: 5568  output bytes: 30144 output_packets: 942
236BER......: 0.0691 Tbits: 528224 Terrs: 36505
237Coded BER: 0.0022 Tbits: 248576 Terrs:   535
238```
239Some notes on this example:
2401. We transmit 10 bursts, each of 100 frames in length, 1000 packets total.  There are a couple of frames silence between each burst.  This gives the acquisition algorithms a good work out.
2411. Only 942 packets make it though this rather noisy channel, a 6% Packet Error Rate (PER).  In a real world application, a higher protocol layer would need to detect this, and arrange for re-transmission of missing packets.  If the SNR was a few dB better, all 1000 packets would likely make it through.  If it was 1dB worse, nothing would get through; LDPC codes have a very sharp "knee" in the PER versus SNR curve.
2421. Our first tone `--tone` is at 10kHz, and each tone is spaced `--shift` by 10kHz, so we have FSK tones at 10,20,30, and 40 kHz.  For good performance, FSK tones must be spaced by at least the symbol rate Rs.
2431. Although the `cohpsk_ch` utility is designed for 8kHz sample rate operation, it just operates on sampled signals, so it's OK to use at higher sample rates.  It does have some internal filtering so best to keep your signal well away from 0 and (sample rate)/2.  The SNR measurement is calibrated to a 3000 Hz noise bandwidth, so won't make much sense at other sample rates.  The third argument `-12` sets the noise level of the channel.
2441. The `--mask` frequency offset algorithm is used, which gives better results on noisy channels, especially for 4FSK.
245
246### Reading Further
247
2481. Examples in the [ctests](CMakeLists.txt).
2491. [FSK_LDPC blog post](http://www.rowetel.com/?p=7467)
250
251## OFDM Raw Data modes for HF Radio
252
253These modes use an OFDM modem with powerful LDPC codes and are designed for sending data over HF radio channels with multipath fading.  At the time of writing (April 2021) they are a work in progress, but usable as is.  The current modes supported are:
254
255| FreeDV Mode | RF bandwidth (Hz) | Payload data rate bits/s | Payload bytes/frame | FEC | Duration (sec) | MPP test | Use case |
256| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
257| DATAC0 | 500 | 291 | 14 | (256,128) | 0.44 | 70/100 at 0dB | Reverse link ACK packets (all SNRs) |
258| DATAC1 | 1700 | 980 | 510 | (8192,4096) | 4.18 | 92/100 at 5dB | Forward link data (medium SNR) |
259| DATAC3 | 500 | 321 | 126 | (2048,1024) | 3.19 | 74/100 at 0dB | Forward link data (low SNR) |
260
261Notes:
2621. 16 bits (2 bytes) per frame are reserved for a 16 bit CRC, e.g. for `datac3` we have 128 byte frames, and 128-2=126 bytes/frame of payload data.
2631. SNR is the target operating point SNR for each mode.
2641. "MPP test" is the number of packets received/transmitted on a simulated MultiPath Poor channel (1Hz Doppler spread, 2ms delay) at the operating point SNR.
265
266From the callers point of view, the frame format of each burst is:
267```
268| Preamble | payload data | CRC | payload data | CRC | ........... | Postamble |
269           | frame 1 -----------| frame 2 -----------| ... frame N |
270```
271In the next layer down, each frame is comprised of several OFDM "modem frames", that contain pilot, unique word, and FEC symbols to handle syncronisation and error correction over the challenging HF channel.  The preamble and postamble are used to locate the burst and estimate it's frequency offset.  Having both a pre and postamble increases the probability of successful detection of the burst in a fading channel. Here are some single frame bursts a MPP channel at 5dB SNR:
272
273![](doc/pre_post_amble_mpp.png)
274
275You can see what a mess the MPP channel makes.  Sometimes we find the pre-amble, other times the post-amble.  Using both increases the probability of detecting the burst, it's a form of time diversity.  If the probability of missing the pre-amble is P(fail)=0.1, then the probability of missing the pre and post-amble is P(fail)*P(fail)=0.01. If we find either we can work out where the burst starts and start demodulating.
276
277Here is an example of sending 3 bursts of 2 frames/burst, a total of 6 frames:
278```
279./src/freedv_data_raw_tx --framesperburst 2 --bursts 3 --testframes 6 DATAC0 /dev/zero - |
280./src/freedv_data_raw_rx --framesperburst 2 --testframes DATAC0 - /dev/null --vv
281<snip>
282BER......: 0.0000 Tbits:  1536 Terrs:     0
283Coded BER: 0.0000 Tbits:   768 Terrs:     0
284Coded PER: 0.0000 Tpkts:     6 Tpers:     0
285```
286
287Lets add some noise and a 20 Hz frequency offset:
288```
289./src/freedv_data_raw_tx --framesperburst 2 --bursts 3 --testframes 6 DATAC0 /dev/zero - |
290./src/cohpsk_ch - - -20 --Fs 8000 -f 20 |
291./src/freedv_data_raw_rx --framesperburst 2 --testframes DATAC0 - /dev/null --vv
292<snip>
293marks:space: 0.83 SNR offset: -0.79
294cohpsk_ch: SNR3k(dB):    -0.36  C/No....:    34.42
295<snip>
296BER......: 0.0195 Tbits:  1536 Terrs:    30
297Coded BER: 0.0000 Tbits:   768 Terrs:     0
298Coded PER: 0.0000 Tpkts:     6 Tpers:     0
299```
300We still received 6 frames OK (Tpkts field), but in this case there was a raw BER of about 2% which the FEC cleaned up nicely (Coded BER 0.0).  Just above that we can see the "SNR offset" and "cohpsk_ch: SNR3k" fields.  In the silence between bursts the modem signal has zero power, which biases the SNR measured by the `conhpsk_ch` channels simulation tool.  This bias is the "SNR offset".  So the true SNR for this test is actually:
301```
302SNR = -0.36 - (-0.79) = 0.43 dB
303```
304
305In the `raw` directory is a real world off-air sample of a signal sent between Adelaide and Melbourne (800km) using about 20W on 40m.  This can be decoded with:
306```
307./src/freedv_data_raw_rx datac1 --framesperburst 1 --testframes ../raw/test_datac1_006.raw /dev/null --vv
308<snip>
309BER......: 0.0134 Tbits: 73728 Terrs:   986
310Coded BER: 0.0000 Tbits: 36864 Terrs:     0
311Coded PER: 0.0000 Tpkts:     9 Tpers:     0
312```
313
314It's also useful to listen to the file, you can hear co-channel SSB, the bursts starting and stopping, and some fading:
315```
316aplay -f S16_LE ../raw/test_datac1_006.raw
317```
318
319Here is a spectrogram (waterfall on it's side - time flows from left to right, frequency on the Y axis):
320
321![](doc/test_datac1_006_spectrogram.png)
322
323The multipath channel carves notches out of the signal, and the level rises and falls.  The 27 carriers of the `datac1` channel can also be observed.  The SSB is the fuzz along the top. The SNR varied between 8 and 16dB. The fading is even more obvious on the scatter diagram:
324
325![](doc/test_datac1_006_scatter.png)
326
327The X shape is due to the level of each carrier changing with the fading.  In some cases a carrier is faded down to zero.  The FEC helps clean up any errors due to faded carriers.
328
329## SNR estimation and clipping
330
331The modem estimates the SNR of every received packet, which can be useful for selecting the best mode to maximise bit rate while  minimising the packet error rate.
332
333Clipping (compression) is enabled by default on each modem waveform to maximise the Peak to Average Power Ratio (PAPR).  Power amplifiers are usually rated in terms of peak power (PEP). For a given peak power, clipping increases SNR over the channel by 3-4dB.
334
335Clipping works by introducing controlled distortion, which affects the SNR estimator in the modem.  When clipping is enabled, the SNR reported by the datac0 and datac3 modes will start to roll off and reach a plateau at about 8dB with no channel noise.  For the same channel SNR, datac1 will return a higher (and more accurate) SNR estimate.  If clipping is disabled, the datac0 and datac3 modes will report a more accurate SNR.
336
337This command line demonstrates the effect:
338```
339./src/freedv_data_raw_tx datac3 /dev/zero - --testframes 10 --bursts 10 --clip 1 | ./src/cohpsk_ch - - -100 --fading_dir unittest  --Fs 8000 | ./src/freedv_data_raw_rx datac3 - /dev/null --testframes --framesperburst 1 -v
340```
341Try adjusting `--clip` and third argument of `cohpsk_ch` (noise level) for different modes.  Note the SNR estimates returned from `freedv_data_raw_rx` compared to the SNR from the channel simulator `cohpsh_ch`. You will notice clipping also increases the RMS power and reduces the PER for a given noise level.
342
343## Reading Further
344
345Resources:
3461. See the raw data example in Quickstart section above.
3471. For simple examples of how use the FreeDV API, see the demo programs [freedv_datac1_tx.c](demo/freedv_datac1_tx.c) and [freedv_datac1_rx.c](demo/freedv_datac1_rx.c)
3481. [freedv_data_raw_tx.c](src/freedv_data_raw_tx.c) and [freedv_data_raw_rx.c](src/freedv_data_raw_rx.c) are more full deatured example programs.
3491. The modem waveforms designs are described in this [spreadsheet](doc/modem_codec_frame_design.ods).
3501. Examples in the [ctests](CMakeLists.txt) (look for "FreeDV API raw data")
3511. [Codec 2 HF Data Modes Part 1 blog post](http://www.rowetel.com/?p=7167)
3521. [HF Data Acquisition](https://github.com/drowe67/codec2/pull/171) GitHub Pull Request
353

README_fdmdv.md

1# README_fdmdv
2
3## Introduction
4
5A 1400 bit/s (nominal) Frequency Division Multiplexed Digital Voice (FDMDV) modem based on [FreeDV 1600 Specification](https://freedv.org/freedv-specification).  Used for FreeDV 1600.
6
7The FDMDV modem was first implemented in GNU Octave, then ported to C. Algorithm development is generally easier in Octave, but for real-time work we need the C version.  Automated units tests ensure the operation of the Octave and C versions are identical.
8
9## Quickstart
10
11Built as part of codec2, see [README](README.md) for build instructions.
12
131. Generate some test bits and modulate them:
14    ```
15    $ ./fdmdv_get_test_bits test.c2 1400
16    $ ./fdmdv_mod test.c2 test.raw
17    $ play -r 8000 -s -2 test.raw
18    ```
19
201. Two seconds of test frame data modulated and sent out of sound device:
21    ```
22    $ ./fdmdv_get_test_bits - 2800 | ./fdmdv_mod - - | play -t raw -r 8000 -s -2 -
23    ```
24
251. Send 14000 modulated bits (10 seconds) to the demod and count errors:
26    ```
27    $  ./fdmdv_get_test_bits - 14000 | ./fdmdv_mod - - | ./fdmdv_demod - - 14 demod_dump.txt | ./fdmdv_put_test_bits -
28    ```
29    Use Octave to look at plots of 1 second (1400 bits) of modem operation:
30    ```
31    $ cd ../octave
32    $ octave --no-gui
33    octave:1> fdmdv_demod_c("../src/demod_dump.txt",14000)
34    ```
35
361. Run Octave simulation of entire modem and AWGN channel:
37    ```
38    $ cd ../octave
39    $ octave
40    octave:1> fdmdv_ut
41    ```
42
431. NOTE: If you would like to play modem samples over the air please convert the 8 kHz samples to 48 kHz.  Many PC sound cards have wildly inaccurate sample clock rates when set to 8 kHz, but seem to perform OK when set for 48 kHz.  If playing and recording files you can use the sox utility:
44    ```
45    $ sox -r 8000 -s -2 modem_sample_8kHz.raw -r 48000 modem_sample_48kHz.wav
46    ```
47    For real-time applications, the fdmdv.[ch] library includes functions to convert between 48 and 8 kHz sample rates.
48
491. Send 20 seconds at 2000 bit/s (20 carriers) to demod and count errors:
50    ```
51    $ ./fdmdv_get_test_bits - 20000 20 | ./fdmdv_mod - - 20 | ./fdmdv_demod - - 20 | ./fdmdv_put_test_bits - 20
52    ```
53
541. Test with timing slips due to sample clock offset of 1000ppm:
55    ```
56    $ ./fdmdv_get_test_bits - 30000 | ./fdmdv_mod - - | sox -t raw -r 8000 -s -2 - -t raw -r 7990 - | ./fdmdv_demod - - 14 demod_dump.txt | ./fdmdv_put_test_bits -
57    octave:98> fdmdv_demod_c("../build_linux/src/demod_dump.txt",28000)
58    27552 bits  0 errors  BER: 0.0000
59    ```
60
61## References
62
631. [FreeDV 1600 Specification](https://freedv.org/freedv-specification)
643. [Testing a FDMDV Modem](http://www.rowetel.com/blog/?p=2433)
654. [FDMDV Modem Page](http://www.rowetel.com/blog/?p=2458)
66
67## C Code
68
69| File | Description |
70| --- | --- |
71| src/fdmdv_mod.c | C version of modulator that takes a file of bits and converts it to a raw file of modulated samples |
72| src/fdmdv_demod.c | C version of demodulator that takes a raw file of modulated samples and outputs a file of bits. Optionally dumps demod states to a text file which can be plotted using the Octave script fdmdv_demod_c.m |
73| src/codec2_fdmdv.h | Header file that exposes FDMDV C API functions.  Include this file in your application program |
74| src/fdmdv.c | C functions that implement the FDMDV modem |
75| src/fdmdv-internal.h | internal states and constants for FDMDV modem, shouldn't be exposed to application program |
76| unittest/tfdmdv.c | Used to conjunction with unittest/tfdmdv.m to automatically test C FDMDV functions against Octave versions |
77
78## Octave Scripts
79
80Note these require some Octave packages to be installed, see [README](README.md)
81
82| File | Description |
83| --- | --- |
84| fdmdv.m | Functions and variables that implement the Octave version of the FDMDV modem |
85| fdmdv_ut.m | Unit test for fdmdv Octave code, useful while developing algorithm.  Includes tx/rx plus basic channel simulation |
86| fdmdv_mod.m | Octave version of modulator that outputs a raw file. The modulator is driven by a test frame of bits.  This can then be played over a real channel or through a channel simulator like PathSim.  The sample rate can be changed using "sox" to simulate differences in tx/rx sample clocks |
87| fdmdv_demod.m | Demodulator program that takes a raw file as input, and works out the bit error rate using the known test frame.  Can be used to test the demod performs with off-air signals, or signals that have been passed through a channel simulator |
88| fdmdv_demod_c.m | Takes an output text file from the C demod fdmdv_demod.c and produces plots and measures BER. Useful for evaluating fdmdv_demod.c performance. The plots produced are identical to the Octave version fdmdv_demod.m, allowing direct comparison of the C and Octave versions |
89| tfdmdv.m | Automatic tests that compare the Octave and C versions of the FDMDV modem functions.  First run unittest/tfdmdv, this will generate a text file with test vectors from the C version.  Then run the Octave script tfdmdv and it will generate Octave versions of the test vectors and compare each vector with the C equivalent.  It plots the vectors and errors (green).  It also produces an automatic checklist based on test results.  If the Octave or C modem code is changed, this script should be used to ensure the C and Octave versions remain identical |
90
911. Typical fdmdv_ut run:
92    ```
93    octave:6> fdmdv_ut
94    Eb/No (meas): 7.30 (8.29) dB
95    bits........: 2464
96    errors......: 20
97    BER.........: 0.0081
98    PAPR........: 13.54 dB
99    SNR.........: 4.0 dB
100    ```
101    It also outputs lots of nice plots that show the operation of the modem.
102
103    For a 1400 bit/s DQPSK modem we expect about 1% BER for Eb/No = 7.3dB, which corresponds to SNR = 4dB (3kHz noise BW). The extra dB of measured power is due to the DBPSK pilot. Currently the noise generation code doesn't take the pilot power into account, so in this example the real SNR is actually 5dB.
104
1051. To generate 10 seconds of modulated signal:
106    ```
107    octave:8> fdmdv_mod("test.raw",1400*10);
108    ```
109    To demodulate 2 seconds of the test.raw file generated above:
110    ```
111    octave:9> fdmdv_demod("test.raw",1400*2);
112    2464 bits  0 errors  BER: 0.0000
113    ```
114    It also produces several plots showing the internal states of the demod.  Useful for debugging and observing what happens with various channels.
115
116## Modelling sample clock errors using sox
117
118
119This introduces a simulated 1000ppm error:
120    ```
121    sox -r 8000 -s -2 mod_dqpsk.raw -s -2 mod_dqpsk_8008hz.raw rate -h 8008
122    ```
123

README_freedv.md

1# FreeDV Technology
2
3FreeDV is an open source digital voice protocol that integrates modems, speech codecs, and FEC.
4
5On transmit, FreeDV converts speech to a modem signal you can send over a radio channel.  On receive, FreeDV takes off air modem signals and converts them to speech samples.
6
7FreeDV is available as a GUI application, an open source library (FreeDV API), and in hardware (the SM1000 FreeDV adaptor).  FreeDV is part of the Codec 2 project.
8
9This document gives an overview of the technology inside FreeDV, and some additional notes on building/using the FreeDV 2020 and 2400A/2400B modes.
10
11![FreeDV mode knob](http://www.rowetel.com/images/codec2/mode_dv.jpg)
12
13## FreeDV API
14
15The general programming model is:
16  ```
17  speech samples -> FreeDV encode -> modulated samples (send over radio) -> FreeDV decode -> speech samples
18  ```
19
20The `codec2/demo` directory provides simple FreeDV API demo programs written in C and Python to help you get started, for example:
21
22```
23cd codec2/build_linux
24cat ../raw/ve9qrp_10s.raw | ./demo/freedv_700d_tx | ./demo/freedv_700d_rx | aplay -f S16_LE
25```
26
27The current demo programs are as follows:
28
29| Program | Description |
30| --- | --- |
31| [c2demo.c](demo/c2demo.c) | Encode and decode speech with Codec 2 |
32| [freedv_700d_tx.c](demo/freedv_700d_tx.c) | Transmit a voice signal using the FreeDV API |
33| [freedv_700d_rx.c](demo/freedv_700d_rx.c) | Receive a voice signal using the FreeDV API |
34| [freedv_700d_rx.py](demo/freedv_700d_rx.py) | Receive a voice signal using the FreeDV API in Python |
35| [freedv_datac1_tx.c](demo/freedv_datac1_tx.c) | Transmit raw data frames using the FreeDV API |
36| [freedv_datac1_rx.c](demo/freedv_datac1_rx.c) | Receive raw data frames using the FreeDV API |
37| [freedv_datac0c1_tx.c](demo/freedv_datac0c1_tx.c) | Transmit two types of raw data frames using the FreeDV API |
38| [freedv_datac0c1_rx.c](demo/freedv_datac0c1_rx.c) | Receive two types of raw data frames using the FreeDV API |
39
40So also [freedv_api.h](src/freedv_api.h) and [freedv_api.c](src/freedv_api.c) for the full list of API functions.  Only a small set of these functions are needed for basic FreeDV use, please see the demo programs for minimal examples.
41
42The full featured command line demo programs [freedv_tx.c](src/freedv_tx.c) & [freedv_rx.c](src/freedv_rx.c) demonstrate many features of the API:
43
44```
45$ ./freedv_tx 1600 ../../raw/hts1.raw - | ./freedv_rx 1600 - - | aplay -f S16_LE
46$ cat freedv_rx_log.txt
47```
48
49Speech samples are input to the API as 16 bit signed integers.  Modulated samples can be in real 16 bit signed integer or complex float. The expected sample rates can be found with `freedv_get_speech_sample_rate()` and `freedv_get_modem_sample_rate()`. These are typically 8000 Hz but can vary depending on the current FreeDV mode.
50
51## FreeDV HF Modes
52
53These are designed for use with a HF SSB radio.
54
55| Mode | Date | Codec | Modem | RF BW | Raw bits/s | FEC | Text bits/s | SNR min | Multipath |
56| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
57| 1600 | 2012 | Codec2 1300 | 14 DQPSK + 1 DBPSK pilot carrier | 1125 | 1600 | Golay (23,12) | 25 | 4 | poor |
58| 700C | 2017 | Codec2 700C | 14 carrier coherent QPSK + diversity | 1500 | 1400 | - | - | 2 | good |
59| 700D | 2018 | Codec2 700C | 17 carrier coherent OFDM/QPSK | 1000 | 1900 | LDPC (224,112)  | 25 | -2 | fair |
60| 700E | 2020 | Codec2 700C | 21 carrier coherent OFDM/QPSK | 1500 | 3000 | LDPC (112,56)  | 25 | 1 | good |
61| 2020 | 2019 | LPCNet 1733 | 31 carrier coherent OFDM/QPSK | 1600 | 3000 | LDPC (504,396)  | 22.2 | 2 | poor |
62
63Notes:
64
651. *Raw bits/s* is the number of payload bits/s carried over the channel by the modem.  This consists of codec frames, FEC parity bits, unprotected text, and synchronisation information such as pilot and unique word bits.  The estimates are open to interpretation for the OFDM waveforms due to pilot symbol and cyclic prefix considerations (see spreadsheet).
66
671. *RF BW* is the bandwidth of the RF signal over the air.  FreeDV is more bandwidth efficient than SSB.
68
691. *Multipath* is the relative resilience of the mode to multipath fading, the biggest problem digital voice faces on HF radio channels.  Analog SSB would be rated as "good".
70
711. *Text* is a side channel for low bit rate text such as your location and call sign.  It is generally unprotected by FEC, and encoded with varicode. The exception is if reliable_text support is turned on (see reliable_text.c/h); this results in text protected by LDPC(112,56) FEC with interleaving.
72
731. *SNR Min* is for an AWGN channel (no multipath/fading).
74
751. All of the modems use multiple parallel carriers running at a low symbol rate of around 50 Hz.  This helps combat the effects of multipath channels.
76
771. Some of the Codec 2 modes (2400/1300/700C etc) happen to match the name of a FreeDV mode.  For example FreeDV 700C uses Codec 2 700C for voice compression. However FreeDV 700D *also* uses Codec 2 700C for voice compression, but has a very different modem waveform to FreeDV 700C.  Sorry for the confusing nomenclature.
78
791. Coherent demodulation gives much better performance than differential, at the cost of some additional complexity.  Pilot symbols are transmitted regularly to allow the demod to estimate the reference phase of each carrier.
80
811. The 1600 and 700C waveforms use parallel tone modems, later modes use OFDM.  OFDM gives tighter carrier packing which allows higher bit rates, but tends to suffer more from frequency offsets and delay spread.
82
831. At medium to high SNRs, FreeDV 700C performs well (better than 700D) on fast fading multipath channels with large delay spread due its parallel tone design and high pilot symbol rate.  It employs transmit diversity which delivers BER performance similar to modes using FEC.  FreeDV 700C also has a short frame (40ms), so syncs fast with low latency.  Fast sync is useful on marginal channels that move between unusable and barely usable.
84
851. FreeDV 700D uses an OFDM modem and was optimised for low SNR channels, with strong FEC but a low pilot symbol rate and modest (2ms) cyclic prefix which means its performance degrades on multipath channels with fast (> 1Hz) fading.  The use of strong FEC makes this mode quite robust to other channel impairments, such as static crashes, urban HF noise, and in-band interference.
86
871. FEC was added fairly recently to FreeDV modes.  The voice codecs we use work OK at bit error rates of a few %, and packet error rates of 10%. Raw bit error rates on multipath channels often exceed 10%.  For reasonable latency (say 40ms) we need small codewords. Thus to be useful we require a FEC code that works at over 10% raw BER, has 1% output (coded) bit error rate, and a codeword of around 100 bits.  Digital voice has unusual requirements, most FEC codes are designed for data which is intolerant of any bit errors, and few operate over 10% raw BER.  Powerful FEC codes have long block lengths (1000's of bits) which leads to long latency.  However LDPC codes come close, and can also "clean up" other channel errors caused by static and interference.  The use of OFDM means we now have "room" for the extra bits required for FEC, so there is little cost in adding it, apart from latency.
88
89## FreeDV VHF Modes
90
91These modes use constant amplitude modulation like FSK or FM, and are designed for VHF and above.  However 800XA can be run over HF or VHF on a SSB radio.
92
93| Mode | Date | Codec2 | Modem | RF BW | Raw bits/s | FEC | Text bits/s |
94| --- | --- | --- | --- | --- | --- | --- | --- |
95| 2400A | 2016 | 1300 | 4FSK | 5kHz | 2400 | Golay (23,12) | 50 |
96| 2400B | 2016 | 1300 | baseband/analog FM | analog FM | 2400 | Golay (23,12) | 50 |
97| 800XA | 2017 | 700C |  4FSK | 2000 | 800 | - | N |
98| FSK_LDPC | 2020 | - | 2 or 4 FSK |  user defined | user defined | LDPC | - | - |
99
100The FSK_LDPC mode is used for data, and has user defined bit rate and a variety of LDPC codes available.  It is discussed in [README_data](README_data.md)
101
102## FreeDV 2400A and 2400B modes
103
104FreeDV 2400A and FreeDV 2400B are modes designed for VHF radio. FreeDV 2400A is designed for SDR radios (it has a 5 kHz RF bandwidth), however FreeDV 2400B is designed to pass through commodity FM radios.
105
106Demos of FreeDV 2400A and 2400B:
107```
108$ ./freedv_tx 2400A ../../raw/ve9qrp_10s.raw - | ./freedv_rx 2400A - - | play -t .s16 -r 8000 -
109$ ./freedv_tx 2400B ../../raw/ve9qrp_10s.raw - | ./freedv_rx 2400B - - | play -t .s16 -r 8000 -
110```
111Note for FreeDV 2400A/2400B the modem signal sample rate is 48kHz.  To
112listen to the modem tones from FreeDV 2400B, or play them into a FM HT
113mic input:
114```
115$ ./freedv_tx 2400B ../../raw/ve9qrp_10s.raw - | play -t .s16 -r 48000 -
116```
117Simulate FreeDV 2400B passing through a 300 to 3000 Hz audio path using sox to filter:
118```
119$  ./freedv_tx 2400B ../../raw/ve9qrp_10s.raw - | sox -t .s16 -r 48000 - -t .s16 - sinc 300-3000 | ./freedv_rx 2400B - - | play -t .s16 -r 8000 -
120```
121
122## FreeDV 2020 support (building with LPCNet)
123
1241. Build codec2 initially without LPCNet
125   ```
126   $ cd ~
127   $ git clone https://github.com/drowe67/codec2.git
128   $ cd codec2 && mkdir build_linux && cd build_linux
129   $ cmake ../
130   $ make
131   ```
132
1331. Build LPCNet:
134   ```
135   $ cd ~
136   $ git clone https://github.com/drowe67/LPCNet
137   $ cd LPCNet && mkdir build_linux && cd build_linux
138   $ cmake -DCODEC2_BUILD_DIR=~/codec2/build_linux ../
139   $ make
140   ```
141
1421. (Re)build Codec 2 with LPCNet support:
143   ```
144   $ cd ~/codec2/build_linux && rm -Rf *
145   $ cmake -DLPCNET_BUILD_DIR=~/LPCNet/build_linux ..
146   $ make
147   ```
148
149## FreeDV 2020 tests with FreeDV API
150
151```
152$ cat ~/LPCNet/wav/wia.wav | ~/LPCNet/build_linux/src/lpcnet_enc -s | ./ofdm_mod --mode 2020 --ldpc --verbose 1 -p 312 | ./ofdm_demod --mode 2020 --verbose 1 --ldpc -p 312 | ~/LPCNet/build_linux/src/lpcnet_dec -s | aplay -f S16_LE -r 16000
153```
154Listen the reference tx:
155```
156$ cat ~/LPCNet/wav/wia.wav | ~/LPCNet/build_linux/src/lpcnet_enc -s | ./ofdm_mod --mode 2020 --ldpc --verbose 1 -p 312 | aplay -f S16_LE
157```
158
159Listen the freedv_tx:
160```
161$ ./freedv_tx 2020 ~/LPCNet/wav/wia.wav - | aplay -f S16_LE
162```
163
164FreeDV API tx, with reference rx from above:
165```
166$ ./freedv_tx 2020 ~/LPCNet/wav/wia.wav - | ./ofdm_demod --mode 2020 --verbose 1 --ldpc -p 312 | ~/LPCNet/build_linux/src/lpcnet_dec -s | aplay -f S16_LE -r 16000
167```
168
169FreeDV API tx and rx:
170```
171$ ./freedv_tx 2020 ~/LPCNet/wav/all.wav - | ./freedv_rx 2020 - - | aplay -f S16_LE -r 16000
172$ ./freedv_tx 2020 ~/LPCNet/wav/all.wav - --testframes | ./freedv_rx 2020 - /dev/null --testframes -vv
173```
174
175Simulated HF slow fading channel, 10.8dB SNR:
176```
177$ ./freedv_tx 2020 ~/LPCNet/wav/all.wav - | ./cohpsk_ch - - -30 --Fs 8000 --slow | ./freedv_rx 2020 - - | aplay -f S16_LE -r 16000
178```
179It falls down quite a bit with fast fading (--fast):
180
181AWGN (noise but no fading) channel, 2.8dB SNR:
182```
183$ ./freedv_tx 2020 ~/LPCNet/wav/all.wav - | ./cohpsk_ch - - -22 --Fs 8000 | ./freedv_rx 2020 - - | aplay -f S16_LE -r 16000
184```
185
186## Command lines for PER testing 700D/700E PER with clipper
187
188AWGN:
189```
190$ ./src/freedv_tx 700D ../raw/ve9qrp.raw - --clip 0 --testframes | ./src/cohpsk_ch - - -16 --Fs 8000 | ./src/freedv_rx 700D - /dev/null --testframes
191```
192MultiPath Poor (MPP):
193```
194$ ./src/freedv_tx 700D ../raw/ve9qrp.raw - --clip 0 --testframes | ./src/cohpsk_ch - - -24 --mpp --fading_dir unittest --Fs 8000 | ./src/freedv_rx 700D - /dev/null --testframes
195```
196
197Adjust `--clip [0|1]` and 3rd argument of `cohpsk_ch` to obtain a PER of just less than 0.1, and note the SNR and PAPR reported by `cohpsk_ch`.  The use of the `ve9qrp` samples makes the test run for a few minutes, in order to get reasonable multipath channel results.
198
199## Reading Further
200
2011. [FreeDV web site](http://freedv.org)
2021. [FreeDV GUI User Manual](https://github.com/drowe67/freedv-gui/blob/master/USER_MANUAL.md)
2031. [Codec 2](http://rowetel.com/codec2.html)
2041. FreeDV can also be used for data [README_data](https://github.com/drowe67/codec2/blob/master/README_data.md)
2051. [FreeDV 1600 specification](https://freedv.org/freedv-specification)
2061. [FreeDV 700C blog post](http://www.rowetel.com/wordpress/?p=5456)
2071. [FreeDV 700D Released blog post](http://www.rowetel.com/wordpress/?p=6103)
2081. [FreeDV 2020 blog post](http://www.rowetel.com/wordpress/?p=6747)
2091. [FreeDV 2400A blog post](http://www.rowetel.com/?p=5119)
2101. [FreeDV 2400A & 2400B](http://www.rowetel.com/?p=5219)
2111. Technical information on various modem waveforms in the [modem codec frame design spreadsheet](https://github.com/drowe67/codec2/blob/master/doc/modem_codec_frame_design.ods)
2121. [Modems for HF Digital Voice Part 1](http://www.rowetel.com/wordpress/?p=5420)
2131. [Modems for HF Digital Voice Part 2](http://www.rowetel.com/wordpress/?p=5448)
2141. [FDMDV modem README](README_fdmdv.md)
2151. [OFDM modem README](README_ofdm.md)
2161. Many blog posts in the [rowetel.com blog archives](http://www.rowetel.com/?page_id=6172)
217
218

README_fsk.md

1# README_fsk
2
3A FSK modem with a non-coherent demodulator.  Performance is within a fraction of a dB of ideal.  The demodulator automagically estimates the tone frequencies and tracks frequency drift.
4
5Here is a typical Bit Error Rate (BER) versus Eb/No curve:
6
7![BER versus Eb/No curve](doc/fsk_modem_ber_8000_100.png)
8
9Note how close the theory line is to measured performance.
10
11This modem can demodulate FSK signals that sound like [this sample](doc/lockdown_3s.wav); and is used to receive images from the [edge of space](https://github.com/projecthorus/wenet):
12
13![HAB image from edge of space](doc/wenet_image.jpg)
14
15## Credits
16
17The Octave version of the modem was developed by David Rowe.  Brady O'Brien ported the modem to C, and wrote the C/Octave tests.  The modem is being maintained by David Rowe.  Mark Jessop has helped improve the modem operation by testing against various balloon telemtry waveforms.  Bill Cowley has developed the Log Likelihood Ratio (LLR) algorithms for 4FSK.
18
19## Quickstart
20
211. Build codec2:
22   ```
23   $ cd codec2 && mkdir build_linux && cmake .. && make
24   ```
25
261. Generate 1000 test bits, modulate them using 2FSK using a 8000 Hz sample rate, 100 bits/s, play on your sound card:
27   ```
28   $ cd ~/codec2/build_linux/src
29   $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1200 1200 - - | aplay -f S16_LE
30   ```
31    The low tone frequency is 1200Hz, and the upper tone 1200 + 1200 = 2400Hz.
32
331. Add the demodulator and measure the bit error rate over 10,000 bits of 100 bit/s 2FSK:
34   ```
35   $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits -
36   <snip>
37   [0099] BER 0.000, bits tested   9900, bit errors    0
38   PASS
39   ```
40   We get a Bit Error Rate (BER) of 0, as there is no channel noise to induce bit errors.
41
421. Same thing but this time with 4FSK, and less verbose output:
43   ```
44   $ ./fsk_get_test_bits - 10000 | ./fsk_mod 4 8000 100 1200 100 - - | ./fsk_demod 4 8000 100 - - | ./fsk_put_test_bits -q -
45   <snip>
46   [0099] BER 0.000, bits tested   9900, bit errors    0
47   PASS
48   ```
49
501. Lets add some channel noise:
51   ```
52   $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./cohpsk_ch - - -26 --Fs 8000 | ./fsk_demod 2 8000 100 - - | ./fsk_put_test_bits -b 0.015 -
53   <snip>
54   SNR3k(dB): -5.76 C/No: 29.0 PAPR:  3.0
55   [0099] BER 0.010, bits tested   9900, bit errors  103
56   PASS
57   ```
58   The cohpsk_ch utility takes the FSK modulator signal, and adds calibrated noise to it (the -26 value specifies the noise).  Try changing the noise level, and note how the Bit Error Rate (BER) changes.  The BER is 0.01, which is right on theory for this sort of FSK demodulator at this SNR (2FSK non-coherent demodulator Eb/No=9dB).
59
60   The SNR is calculated using the signal power divided by the noise power in 3000 Hz.  The C/No value is the same thing, but uses a noise bandwidth of 1 Hz.  There is less noise power when you look at just 1Hz, so C/No is higher. Peak to Average Power ratio (PAPR) is 3dB as a FSK signal is just a single sine wave, and a sine wave peak is 3dB higher than it's average.
61
621. You can visualise the C modem operation with a companion python script, for example:
63   ```
64   $ ./fsk_get_test_bits - 10000 | ./fsk_mod -p 10 4 8000 400 400 400 - - | ./fsk_demod -p 10 -t1 4 8000 400 - /dev/null 2>stats.txt
65   $ python ../../octave/plot_fsk_demod_stats.py stats.txt
66   ```
67
681. Send some digital voice using FSK at 800 bits/s, and try the two 2400 bits/s FSK modes:
69   ```
70   $ ./freedv_tx 800XA ../../raw/ve9qrp.raw - | ./freedv_rx 800XA - - -vv | aplay -f S16_LE
71   $ ./freedv_tx 2400A ../../raw/ve9qrp.raw - | ./freedv_rx 2400A - - -vv | aplay -f S16_LE
72   $ ./freedv_tx 2400B ../../raw/ve9qrp.raw - | ./freedv_rx 2400B - - -vv | aplay -f S16_LE
73   ```
74
751. LDPC encoded 4FSK, with framing:
76   ```
77   $ cd ~/codec2/build_linux/src
78   $ ./ldpc_enc /dev/zero - --code H_256_512_4 --testframes 200 |
79     ./framer - - 512 5186 | ./fsk_mod 4 8000 100 1000 100 - - |
80     ./cohpsk_ch - - -24 --Fs 8000  |
81     ./fsk_demod -s 4 8000 100 - - |
82     ./deframer - - 512 5186  |
83     ./ldpc_dec - /dev/null --code H_256_512_4 --testframes
84   <snip>
85   SNR3k(dB): -7.74 C/No: 27.0 PAPR:  3.0
86   Raw   Tbits: 100352 Terr:   6701 BER: 0.067
87   Coded Tbits:  50176 Terr:    139 BER: 0.003
88         Tpkts:    196 Tper:      4 PER: 0.020
89   ```
90   In this example the unique word is the 16 bit sequence `5186`.  See also several ctests using these application. Other codes are also available:
91   ```
92   $ ./ldpc_enc --listcodes
93
94   H2064_516_sparse     rate 0.80 (2580,2064)
95   HRA_112_112          rate 0.50 (224,112)
96   HRAb_396_504         rate 0.79 (504,396)
97   H_256_768            rate 0.33 (768,256)
98   H_256_512_4          rate 0.50 (512,256)
99   HRAa_1536_512        rate 0.75 (2048,1536)
100   H_128_256_5          rate 0.50 (256,128)
101   ```
102   If you change the code you also need to change the `frameSizeBits` argument in `framer/deframer` (`512` in the example above).
103
1041. The FSK/LDPC/framer steps above have been combined in a FreeDV API mode.  See "FSK LDPC Raw Data Mode" in [README_data.md](README_data.md).
105
1061. FSK modem C files in ```codec2/src```:
107
108   | File | Description |
109   | ---  | --- |
110   | fsk.c/fsk.h | core FSK modem library |
111   | fsk_mod.c | command line modulator |
112   | fsk_demod.c | command line demodulator |
113   | fsk_get_test_bits.c | source of test bits |
114   | fsk_put_test_bits.c | test bit sync, counts bit errors and packet errors |
115   | fsk_mod_ext_vco.c | modulator that uses an external FSK oscillator |
116   | framer.c | adds a unique word to a frame of bits to implement frame sync for LDPC codewords |
117   | deframer.c | locates and strips a unique word to implement frame sync for LDPC codewords |
118   | tollr.c | converts bits to LLRs for testing LDPC framing |
119
1201. GNU Octave files in ```codec2/octave```:
121
122   | File | Description |
123   | ---  | --- |
124   | fsk_lib.m | Core FSK modem library |
125   | fsk_lib_demo.m | A demonstration of fsk_lib, runs a single point BER test |
126   | fsk_demod_file.m | Demodulates FSK signals from a file, useful for debugging FSK waveforms |
127   | fsk_lock_down.m | simulations to support the "lock down" low SNR waveform |
128   | tfsk.m | automated test that compares the C and Octave versions of the modem |
129   | fsk_cml.m | Symbol rate experiments with FSK modem LLR estimation and LDPC |
130   | fsk_cml_sam.m | Sample rate experiments with FSK modem LLR estimation and LDPC |
131   | fsk_llr_plot.m | Plots curves from fsk_cml.m & fsk_cml_sam.m |
132   | fsk_lib_ldpc_demo.m | CML library LLR routines and LDPC codes with fsk_lib.m |
133
134   You can run many of them from the Octave command line:
135   ```
136   $ octave --no-gui
137   octave:1> fsk_lib_demo
138   ```
139
1401. A suite of automated ctests that exercise the C and Octave code:
141   ```
142   $ cd ~/codec2/build_linux
143   $ ctest -R test_fsk
144   1/9 Test #39: test_fsk_lib ......................   Passed    3.37 sec
145   3/9 Test #41: test_fsk_modem_octave_port ........   Passed    4.17 sec
146   4/9 Test #42: test_fsk_modem_mod_demod ..........   Passed    0.06 sec
147   5/9 Test #43: test_fsk_2fsk_ber .................   Passed    0.24 sec
148   6/9 Test #44: test_fsk_4fsk_ber .................   Passed    0.12 sec
149   7/9 Test #45: test_fsk_4fsk_ber_negative_freq ...   Passed    0.07 sec
150   8/9 Test #46: test_fsk_4fsk_lockdown ............   Passed    2.84 sec
151   9/9 Test #47: test_fsk_vhf_framer ...............   Passed    0.06 sec
152   ```
153   These are written in ```codec2/CmakeLists.txt```, inspect them to find out how we test the modem.
154
1551. ```fsk_demod_file.m``` is useful for peering inside the modem, for example when debugging.
156   ```
157   $ cd ~/codec2/build_linux/src
158   $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1000 1000 - ../../octave/fsk.s16
159   $ octave --no-gui
160   octave:1> fsk_demod_file("fsk.s16",format="s16",8000,100,2)
161   ```
162
163## Further Reading
164
165   Here are some links to projects and blog posts that use this modem:
166
167   1. [Horus Binary](https://github.com/projecthorus/horusbinary) High Altitude Balloon (HAB) telemetry protocol, 3 second updates, works at 7dB lower SNR that RTTY.
168   1. [Testing HAB Telemetry, Horus binary waveform](http://www.rowetel.com/?p=5906)
169   1. A really useful reference on a variety of modulation techniques from [Atlanta DSP](http://www.atlantarf.com/FSK_Modulation.php).  I keep this handy when experimenting with modems.
170   1. The [RTTY modem project](http://www.rowetel.com/?p=4629) that kicked off the FSK modem work.
171   1. [Wenet](https://github.com/projecthorus/wenet) - high speed SSTV images from balloons at the edge of space
172   1. [Wenet High speed SSTV images](http://www.rowetel.com/?p=5344)
173   1. [FreeDV 2400A and 2400B](http://www.rowetel.com/?p=5219), digital speech for VHF/UHF radios.
174   1. [HF FSK with Rpitx](http://www.rowetel.com/?p=6317), a zero hardware FSK transmitter using a Pi
175   1. [Eb/No and SNR worked Example](http://www.rowetel.com/wordpress/?p=4621)
176   1. [FSK LLR LDPC Code Experiments](https://github.com/drowe67/codec2/pull/129)
177   1. [FreeDV API FSK LDPC Raw Data Mode](README_data.md)
178
179
180

README_ofdm.md

1# README_ofdm
2
3An Orthogonal Frequency Division Multiplexed (OFDM) modem designed for digital voice over HF SSB.  Typical configuration for FreeDV 700D is 700 bit/s voice, a rate 0.5 LDPC code, and 1400 bit/s raw data rate over the channel.
4
5The OFDM modem was first implemented in GNU Octave, then ported to C. Algorithm development is generally easier in Octave, but for real time work we need the C version.  Automated units tests ensure the operation of the Octave and C versions are identical.
6
7## Credits
8
9Steve, David, Don, Richard
10
11## References
12
131. Spreadsheet describing the [waveform design](doc/modem_codec_frame_design.ods)  The OFDM tab descrives the baseline 700D OFDM waveform.
14
151. This modem can be used for sending [raw data frames](README_data.md) over HF channels.
16
171. [Towards FreeDV 700D](https://www.rowetel.com/?p=5573)
18
191. [FreeDV 700D - First Over The Air Tests](https://www.rowetel.com/?p=5630)
20
211. [Steve Ports an OFDM modem from Octave to C](https://www.rowetel.com/?p=5824)
22
231. [Modems for HF Digital Voice Part 1](http://www.rowetel.com/wordpress/?p=5420)
24
251. [Modems for HF Digital Voice Part 2](http://www.rowetel.com/wordpress/?p=5448)
26
27# Examples
28
29Built as part of codec2-dev, see [README](README.md) for build instructions.
30
311. Generate 10 seconds of test frame bits, modulate, and play audio
32   out of sound device (SoX v14.4.2):
33   ```
34   $  build_linux/src$ ./ofdm_mod --in /dev/zero --testframes 10 | play --type s16 --rate 8000 --channels 2 -
35   ```
36
371. Generate 10 seconds of uncoded test frame bits, modulate, demodulate, count errors:
38   ```
39   $  build_linux/src$ ./ofdm_mod --in /dev/zero --testframes 10 | ./ofdm_demod --out /dev/null --testframes --verbose 1 --log demod_dump.txt
40   ```
41   Use Octave to look at plots of C modem operation:
42   ```
43     $ cd ../../octave
44     $ octave --no-gui
45     octave:1> ofdm_demod_c("../build_linux/src/demod_dump.txt")
46   ```
47
481. Run Octave versions of mod and demod (called tx and rx to avoid namespace clashes in Octave):
49   ```
50   $ cd ~/octave
51   $ octave --no-gui
52   octave:1> ofdm_tx("ofdm_test.raw","700D",10)
53   octave:1> ofdm_rx("ofdm_test.raw")
54   ```
55   The Octave modulator ofdm_tx can simulate channel impairments, for
56   example AWGN noise at 4dB SNR:
57   ```
58     octave:1> ofdm_tx("ofdm_test.raw", "700D", 10, 4)
59   ```
60   The Octave versions use the same test frames as C so can interoperate.
61   ```
62     build_linux/src$ ./ofdm_demod --in ../../octave/ofdm_test.raw --out /dev/null --testframes --verbose 1
63   ```
64
651. Run mod/demod with LDPC FEC; 60 seconds, 3dB SNR:
66   ```
67     octave:6> ofdm_ldpc_tx('ofdm_test.raw',"700D",60,3)
68     octave:7> ofdm_ldpc_rx('ofdm_test.raw',"700D")
69   ```
70   C demodulator/LDPC decoder:
71   ```
72   build_linux/src$ ./ofdm_demod --in ../../octave/ofdm_test.raw --out /dev/null --verbose 1 --testframes --ldpc
73   ```
74
751. Pass Codec 2 700C compressed speech through OFDM modem:
76   ```
77   build_linux/src$ ./c2enc 700C ../../raw/ve9qrp_10s.raw - --bitperchar | ./ofdm_mod --ldpc | ./ofdm_demod --ldpc | ./c2dec 700C - - --bitperchar | play --type s16 --rate 8000 --channels 1 -
78   ```
79
801. Listen to signal through simulated fading channel in C:
81   ```
82   build_linux/src$ ./c2enc 700C ../../raw/ve9qrp_10s.raw - --bitperchar | ./ofdm_mod --ldpc | ./cohpsk_ch - - -20 --Fs 8000 --slow -f -5 | aplay -f S16
83   ```
84
851. Run test frames through simulated channel in C:
86   ```
87   build_linux/src$ ./ofdm_mod --in /dev/zero --ldpc --testframes 20 | ./cohpsk_ch - - -24 --Fs 8000 -f -10 --fast | ./ofdm_demod --out /dev/null --testframes --verbose 1 --ldpc
88   ```
89
901. Run codec voice through simulated fast fading channel, just where it starts to fall over:
91   ```
92   build_linux/src$ ./c2enc 700C ../../raw/ve9qrp.raw - --bitperchar | ./ofdm_mod --ldpc | ./cohpsk_ch - - -24 --Fs 8000 -f -10 --fast | ./ofdm_demod --ldpc --verbose 1 | ./c2dec 700C - - --bitperchar | aplay -f S16
93   ```
94
951. FreeDV 1600 on the same channel conditions, roughly same quality at 8dB higher SNR:
96   ```
97   build_linux/src$ ./freedv_tx 1600 ../../raw/ve9qrp_10s.raw - | ./cohpsk_ch - - -30 --Fs 8000 -f -10 --fast | ./freedv_rx 1600 - - | aplay -f S16
98   ```
99
1001. Using FreeDV API test programs:
101   ```
102   build_linux/src$ ./freedv_tx 700D ../../raw/hts1a.raw - --testframes | ./freedv_rx 700D - /dev/null --testframes
103   build_linux/src$ ./freedv_tx 700D ../../raw/hts1a.raw - | ./freedv_rx 700D - - | aplay -f S16
104   build_linux/src$ ./freedv_tx 700D ../../raw/ve9qrp.raw - | ./cohpsk_ch - - -26 --Fs 8000 -f -10 --fast | ./freedv_rx 700D - - | aplay -f S16
105   ```
106
107## FreeDV 2020 extensions
108
1091.  20.5ms symbol period, 31 carrier waveform, (504,396) code, but only 312 data bits used, so we don't send unused data bits.  This means we need less carriers (so more power per carrier), and code rate is increased slightly:
110    ```
111    build_linux/src$ ./ofdm_mod --in /dev/zero --testframes 300 --mode 2020 --ldpc 1 --verbose 1 -p 312 | ./cohpsk_ch - - -22 --Fs 8000 -f 10 --ssbfilt 1 | ./ofdm_demod --out /dev/null --testframes --mode 2020 --verbose 1 --ldpc -p 312
112
113    SNR3k(dB):  2.21 C/No: 37.0 PAPR:  9.6
114    BER......: 0.0505 Tbits: 874020 Terrs: 44148
115    Coded BER: 0.0096 Tbits: 649272 Terrs:  6230
116    ```
117
118## Acquisition tests
119
1201. Acquisition (getting sync) can be problematic in fading channels. Some special tests have been developed, that measure acquisition time on off air 700D samples at different time offsets:
121   ```
122   octave:61> ofdm_ldpc_rx("../wav/vk2tpm_004.wav", "700D", "", 5, 4)
123   build_linux/src$ ./ofdm_demod --in ../../wav/vk2tpm_004.wav --out /dev/null --verbose 2 --ldpc --start_secs 5 --len_secs 4
124   ```
125
1261. Different time offsets effectively tests the ability to sync on fading channel in different states.  Stats for a series of these tests can be obtained with:
127   ```
128   octave:61> ofdm_time_sync("../wav/vk2tpm_004.wav", 30)
129   <snip>
130   pass: 30 fails: 0 mean: 1.35 var 0.51
131   ```
132
133## Octave Acceptance Tests
134
135Here are some useful tests for the Octave, uncoded modem.
136
137The rate 1/2 LDPC code can correct up to about 10% raw BER, so a good test is to run the modem at Eb/No operating points that produce just less that BER=0.1. The BER2 measure truncates the effect of any start up transients, e.g. as the frequency offset is tracked out.
138
1391. HF Multipath:
140   ```
141   octave:580> ofdm_tx("ofdm_test.raw","700D",60,2,'mpm',20)
142   octave:581> ofdm_rx("ofdm_test.raw")
143   BER2.: 0.0803 Tbits: 84728 Terrs:  6803
144   ```
145
1461. AWGN:
147   ```
148   octave:582> ofdm_tx("ofdm_test.raw","700D",60,-2,'awgn')
149   octave:583> ofdm_rx("ofdm_test.raw")
150   BER2.: 0.0885 Tbits: 84252 Terrs:  7459
151   ```
152
153## C Acceptance Tests
154
155Here are some useful tests for the LDPC coded C version of the modem, useful to verify any changes.
156
1571. AWGN channel, -2dB:
158   ```
159   ./ofdm_mod --in /dev/zero --ldpc --testframes 60 --txbpf | ./cohpsk_ch - - -20 --Fs 8000 -f -10 | ./ofdm_demod --out /dev/null --testframes --verbose 1 --ldpc
160
161   SNR3k(dB): -1.85 C/No: 32.9 PAPR:  9.8
162   BER......: 0.0815 Tbits: 98532 Terrs:  8031
163   Coded BER: 0.0034 Tbits: 46368 Terrs:   157
164   ```
165
1661. Fading HF channel:
167   ```
168   ./ofdm_mod --in /dev/zero --ldpc --testframes 60 --txbpf | ./cohpsk_ch - - -24 --Fs 8000 -f -10 --fast | ./ofdm_demod --out /dev/null --testframes --verbose 1 --ldpc
169
170   SNR3k(dB):  2.15 C/No: 36.9 PAPR:  9.8
171   BER......: 0.1015 Tbits: 88774 Terrs:  9012
172   Coded BER: 0.0445 Tbits: 41776 Terrs:  1860
173   ```
174
175   Note: 10% Raw BER operating point on both channels, as per design.
176
177# Data Modes
178
179The OFDM modem can also support datac1/datac2/datac3 modes for packet data.  The OFDM modem was originally designed for very short (28 bit) voice codec packets.  For data, packets of hundreds to thousands of bits a desirable so we can use long, powerful FEC codewords, and reduce overhead.  The datac1/datac2/datac3 QPSK modes are currently under development.
180
181Here is an example of running the datac3 mode in a low SNR AWGN channel:
182
183```
184./src/ofdm_mod --mode datac3 --ldpc --in  /dev/zero --testframes 60 --verbose 1 | ./src/cohpsk_ch - - -20 --Fs 8000 | ./src/ofdm_demod --mode datac3 --ldpc --out /dev/null --testframes -v 1
185<snip>
186SNR3k(dB): -3.54 C/No: 31.2 PAPR: 10.4
187BER......: 0.1082 Tbits: 36096 Terrs:  3905 Tpackets:    47
188Coded BER: 0.0000 Tbits: 12032 Terrs:     0
189```
190Note despite the raw BER of 10%, 47/50 packets are received error free.
191
192# C Code
193
194| File | Description |
195| :-- | :-- |
196| ofdm.c | OFDM library |
197| codec2_ofdm.h | API header file for OFDM library |
198| ofdm_get_test_bits | Generate OFDM test frames |
199| ofdm_mod | OFDM modulator command line program |
200| ofdm_demod | OFDM demodulator command line program, supports uncoded (raw) and LDPC coded test frames, LDPC decoding of codec data, and can output LLRs to external LDPC decoder |
201| ofdm_put_test_bits | Measure BER in OFDM test frames |
202| unittest/tofdm | Run C port of modem to compare with octave version (see octave/tofdm) |
203| cohpsk_ch | From COHPSK modem development, useful C channel simulator |
204
205# Octave Scripts
206
207| File | Description |
208| :-- | :-- |
209| ofdm_lib | OFDM library |
210| ofdm_dev | Used for modem development, run various simulations |
211| ofdm_tx | Modulate test frames to a file of sample, cam add channel impairments |
212| ofdm_rx | Demod from a sample file and count errors |
213| tofdm | Compares Octave and C ports of modem |
214| ofdm_ldpc_tx | OFDM modulator with LDPC FEC |
215| ofdm_ldpc_rx | OFDM demodulator with LDPC FEC |
216
217## Specifications
218
219Nominal FreeDV 700D configuration:
220
221| Parameter | Value |
222| :-- | :-- |
223| Modem | OFDM, pilot assisted coherent QPSK |
224| Payload bits/s | 700 |
225| Text bits/s | 25 (note 4) |
226| Unique Word | 10 bits |
227| Carriers | 17 |
228| RF bandwidth | 944 Hz |
229| Symbol period | 18ms
230| Cyclic Prefix | 2ms (note 1)
231| Pilot rate | 1 in every 8 symbols |
232| Frame Period | 160ms |
233| FEC | rate 1/2 (224,112) LDPC |
234| Operating point | |
235|   AWGN | Eb/No -0.5dB SNR(3000Hz): -2.5dB (note 2) |
236|   HF Multipath | Eb/No  4.0dB SNR(3000Hz):  2.0dB (note 3) |
237|   Freq offset | +/- 60  Hz   (sync range) |
238| Freq drift | +/- 0.2 Hz/s (for 0.5 dB loss) |
239| Sample clock error | 1000 ppm |
240
241Notes:
242
2431. Modem can cope with up to 2ms of multipath
2441.
245   ```
246   Ideal SNR(3000) = Eb/No + 10*log10(Rb/B)
247                     = -1 + 10*log10(1400/3000)
248                     = -4.3 dB
249   ```
250   So we have about 1.8dB overhead for synchronisation, implementation loss,  and the text channel.
2511. "CCIR Poor" HF Multipath channel used for testing is two path, 1Hz Doppler, 1ms delay.
2521. The text channel is an auxillary channel, unprotected by FEC, that typically carries callsign/location information for Ham stations.
253