# AFF3CT: measuring channel codes by simulation, then reusing the decoders

> AFF3CT is a C++ forward error correction simulator and library that sweeps BER/FER curves for Turbo, Polar, LDPC, BCH and Reed Solomon codes. It fits link level research and prototyping, not live radio work, and the only documented install path is a recursive clone and CMake build.

**aff3ct/aff3ct** — Fast multi-thread FEC simulator & library of efficient digital communication algorithms for SDR.

- Repository: https://github.com/aff3ct/aff3ct
- Website: http://aff3ct.github.io
- Stars: 610 · Forks: 177
- Language: C++
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/aff3ct-aff3ct

## What AFF3CT actually measures

AFF3CT answers a narrow question with a lot of precision: given a channel code, a decoder and a noisy channel, what error rates do you get, and how fast can you get them. It is written in C++, targets forward error correction, and ships as two things inside one repository, a command line simulator and a reusable library. The simulator runs communication chains by Monte Carlo method. It pushes coded frames through a channel model, decodes them, and counts errors over the frames it has processed. The library half exists because parts of the simulator turned out to be useful on their own, for custom chains, hardware prototyping, and SDR pipelines.

The users this serves are people working at link level coding theory. People who need to know whether one decoder configuration beats another before committing to it, people who need a BER/FER curve rather than a theoretical bound, and people who want to prototype a fixed-point receiver before writing hardware. If your problem is application level delivery over a network, the scope will feel narrow and the C++ build will feel heavy.

## Building from source with CMake and a recursive clone

The installation path is the standard clone, configure and build sequence. Three things must already be on the machine: a C++11 compiler, CMake and Git. The clone uses the recursive flag, which matters because the repository ships a .gitmodules file, so submodules are part of the build rather than an optional extra.

```bash
git clone --recursive https://github.com/aff3ct/aff3ct.git
mkdir aff3ct/build
cd aff3ct/build
cmake .. -DCMAKE_BUILD_TYPE="Release"
make -j4
```

Release mode is the sensible choice here because speed is the point of the tool. The top level tree shows how the project is arranged: src/ and include/ hold the code, cmake/ and conf/ hold build and configuration files, scripts/ holds helper scripts, doc/ holds documentation sources, and lib/ and refs/ sit alongside them. CI definitions live in ci/ with a .gitlab-ci.yml file at the root, and since release v4.6.0, described as CI/CD moved to GitHub Actions, the .github/ directory is present in the tree. The practical reading is that a build is expected to be reproduced from a clean checkout. No binary package or installer is documented.

## Running one Polar code sweep and reading the counters

The quickest way to see the simulator work is the Polar code example that the project documents. It estimates the decoding performance of the (2048,1723) Polar code across a range of signal to noise ratios in a single invocation:

```bash
aff3ct -C "POLAR" -K 1723 -N 2048 -m 1.0 -M 4.0 -s 1.0
```

The flags read as follows. The -C switch selects the code family, POLAR. The -K value 1723 is the information block length and the -N value 2048 is the full code length. The -m and -M values are the lower and upper bounds of the sweep in dB, and -s 1.0 is the step, so the run walks from 1.0 to 4.0 dB.

The output is a table with a fixed banner:

```bash
# ----------------------------------------------------
# ---- A FAST FORWARD ERROR CORRECTION TOOLBOX >> ----
# ----------------------------------------------------
```

Below the banner each row carries counters that matter when you read a curve. FRA counts frames, BE counts bit errors, FE counts frame errors, and BER and FER are the ratios derived from them. SIM_THR reports simulation throughput in Mb/s, and ET/RT reports elapsed time. The example in the project documentation shows a frame error rate of 1.00e+00 at the two lowest points, falling to 1.98e-02 at the highest sweep point, with throughput in the tens of Mb/s. Note that the counters are cumulative in the sense the documentation presents them, so read them as totals per row, not per interval.

## Where the speed comes from: SIMD, threads and multi-node runs

The simulator's stated design target is high speed simulations, and the listed techniques behind it are SIMD, multi-threading and multi-node programming models. The repository topics list mpi and multi-threading, so a run can be spread across nodes rather than confined to a single machine.

This is not decoration. A BER/FER sweep is embarrassingly parallel at the frame level, since each Monte Carlo frame can be simulated and decoded independently. That is why the output reports throughput and elapsed time as first class columns: a curve that takes a night is a different engineering decision from one that takes a minute, and the ET/RT column lets you price a sweep before you commit to it.

The trade-off is that the simulator does not abstract away the code under test. Every code family and decoder pairing has its own parameter set, so the flag vocabulary changes with what you simulate, and the same simulation run in two different configurations is not guaranteed to produce comparable counters unless you keep the channel model and the stopping criterion fixed.

## The library half: custom chains, fixed-point receivers and SDR modules

The library exists for cases the simulator cannot express. The project lists three applications for it: build custom communication chains that are not possible with the simulator, facilitate hardware prototyping, and enable various modules to be used in SDR contexts. The documentation points users who want to use AFF3CT as a library to a dedicated examples page.

Hardware prototyping is the sharpest of those cases, and the README names the mechanism behind it, fixed-point receivers and hardware in the loop tools, as one of the features that motivated the simulator. Modelling a fixed-point receiver lets you predict what a real word-length implementation will do, including the error floors that appear when quantisation enters the decoder, rather than what an idealised floating point decoder would do. That is a genuinely different question from asking for a BER curve.

For SDR work, the payoff is that the same decoding modules that the simulator drives can be dropped into a signal processing pipeline, so a decoder tested under simulation conditions is the decoder that runs on received samples. The README does not, however, document a specific sample rate conversion, file format, or hardware device integration, so the boundary between library and SDR framework is set by your own code.

## Where AFF3CT is the wrong tool

Several cases disqualify the project quickly. If you need to demodulate a recording or watch a live radio, this is a simulation framework and the README does not document a live capture path. If you want to compare the latency of a decoder on real hardware, the reported throughput and elapsed time describe the simulation, not the per frame latency of your receiver. If your team has no C++ toolchain, the build asks for a C++11 compiler, CMake and Git, and the checkout is recursive, which is a real setup cost next to a Python notebook.

The documentation is also quiet on several operational points. It does not document rollback of a release. It does not list supported operating systems. It does not describe a binary distribution, which leaves the recursive clone and CMake build as the only documented installation route. It does not set out what happens to a long sweep when the machine is interrupted, so an overnight run that dies at the last step has no documented recovery path.

None of that makes the project unusable. It does mean an adopter has to supply the operational answers themselves rather than reading them off the documentation.

## How the simulator differs from a MATLAB style script

The project names its own comparison point. Among the reasons that motivated the simulator, reducing simulation time compared with MATLAB appears explicitly, and the resulting tool ships as a command line program rather than a script library.

The difference in approach is composition. AFF3CT treats a code family, a decoder, a channel model and a counter set as selectable objects driven by flags, so a sweep is a parameter range, and the same configuration is reusable across runs and across code families without being rewritten. A MATLAB script written for one code tends to hard code its parameters and its decoder, so moving to a different code family means rewriting the script rather than changing one argument. The other alternative is writing your own C++ or Python simulation, which gives you exactly what you need and nothing else, and the cost is that the channel models, the statistical counters, and the decoder implementations all become yours to write and to validate. AFF3CT pays off when several codes and several channel models have to be compared repeatedly. For a single measurement it is heavy.

## Licence, release cadence and what to pin

AFF3CT is distributed under the MIT licence. That is the permissive option if you intend to embed the library inside receiver software you ship, and the MIT terms require the copyright notice and the licence text to travel with copies and substantial portions of the code. That is a licensing observation about the terms themselves, and your own review is what decides how it applies in your organisation.

The release history shows numbered versions with dated tags: v4.6.0 on 2026-07-16, v4.7.0 on 2026-08-19, titled Polar Codes Improvements, and v4.7.1 on 2026-09-09. The repository is not archived, and the last push was on 2026-10-20, so work on the tree is current.

One detail deserves attention. The default branch is develop rather than a release branch, so a fresh clone of the default branch gives you development state and not the tagged v4.7.1 tree. For a study whose results you intend to publish or reproduce, build from a tag and record it. Since v4.7.0 is titled Polar Codes Improvements, Polar results produced before that tag and after it should not be compared without a note, and the same caution applies to any change that lands on develop after your last build.

## Conclusion

AFF3CT earns a place in a link level research or prototyping workflow: it turns BER and FER estimation into a repeatable command and hands you reusable decoding modules under a permissive licence. It does not serve live radio capture, per frame latency measurement on real hardware, or teams that would rather not build a C++ project. Before adopting it, confirm that the channel models match your link, that the decoder configuration matches the one you intend to ship, and that the parameters you sweep are the ones that decide the outcome, then pin a release tag because the default branch is develop.

## FAQ

### How do I install AFF3CT and build it from source?

The project asks for a C++11 compiler, CMake and Git, then a recursive clone followed by a Release CMake configure and a make in the build directory. The clone must be recursive because the repository carries submodules, and no binary installer is documented.

### What is the difference between the AFF3CT simulator and the AFF3CT library?

The simulator is a command line program that runs Monte Carlo communication chains and prints BER and FER counters. The library exposes the same building blocks for building custom chains the simulator cannot express, for hardware prototyping, and for reuse in SDR pipelines.

### Which channel codes can AFF3CT simulate?

The README names Turbo codes, Polar codes and LDPC codes as the range of codes supported, and the repository topics also list BCH and Reed Solomon. Codes are selected per run with the -C switch, for example -C "POLAR".

### Should I build the default branch or a release tag?

The default branch is develop, so it carries development state rather than a released build. Recent tags include v4.6.0, v4.7.0 and v4.7.1, and the last push was on 2026-10-20, so pinning a tag gives you a tree you can name in a results table.

## Sources

- [aff3ct/aff3ct on GitHub](https://github.com/aff3ct/aff3ct)
- [License: MIT](https://github.com/aff3ct/aff3ct/blob/develop/LICENSE)
- [Project website](http://aff3ct.github.io)
- [README](https://github.com/aff3ct/aff3ct/blob/develop/README.md)
- [Releases](https://github.com/aff3ct/aff3ct/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/aff3ct-aff3ct
