TXLevel and RXLevel: MMDVM modulation level

Category: CalibrationDifficulty: ★★★~9 min

A hotspot works perfectly until the first careful look at the log — and there it is: BER of 3%, 5%, sometimes more. The radio hears the hotspot with raspy artifacts, or the other way around: the hotspot fails to decode the radio. The frequency is dialed in, the Color Code is correct, yet there are plenty of errors. In most cases the culprit is incorrectly set TXLevel and RXLevel parameters in the MMDVM.ini file. Let's go over what they are, how they work, and how to set them correctly.

What TXLevel and RXLevel are

The [Modem] section of the MMDVM.ini configuration file (or the equivalent Pi-Star/WPSD settings) holds two key parameters:

[Modem]
TXLevel=50
RXLevel=50

TXLevel is the software scaling of the signal level that MMDVMHost feeds to the hotspot board's DAC. The higher the value, the larger the signal amplitude at the board's transmitter input, and therefore the greater the deviation (FM swing) on the air.

RXLevel is the software scaling of the signal coming from the output of the board's receiver discriminator into the microcontroller's ADC. It adjusts the receive-path sensitivity on the software side.

Both parameters take integer values. The actual working range depends on the board's firmware: for most MMDVM_HS boards (ZUMspot, MMDVM_HS_Hat, Nano_hotSPOT) the meaningful range is from 0 to 100 (the units are close to a percentage of the maximum), but higher values are also allowed in the configuration file. The default value is 50 for both parameters.

Global and per-mode levels MMDVM.ini also has per-mode parameters: DMRTXLevel, DStarTXLevel, YSFTXLevel, and so on. They override the global TXLevel for a specific mode. If you only use DMR, the global parameter is enough. A commented-out DMRTXLevel means that TXLevel will be used.

Why the levels matter: deviation and 4FSK

DMR uses 4FSK modulation (four-level frequency-shift keying with a filter). Each symbol is transmitted at one of four deviation levels: ±1.944 kHz and ±0.648 kHz relative to the carrier. If the deviation does not match the standard, the receiver at the other end (another hotspot, a repeater, a radio) starts making errors when decoding the symbols — BER goes up.

The DMR standard prescribes a full deviation of ±2.75 kHz for the maximum symbol. That is exactly what the hotspot's TXLevel must be brought to. Too little TXLevel means under-deviation, and radios decode the hotspot poorly. Too much means over-deviation, where adjacent symbols "bleed" into each other and BER rises as well.

The same goes for reception: if RXLevel is too low, the signal from the radio doesn't reach the ADC thresholds and the decoder makes errors. Too high, and the ADC is overloaded and clips the signal.

TXLevel is not power The parameter does not control the hotspot's RF transmitter power. Power is determined by the hardware (the CC1101, ADF7021, etc. chip, paired with a PA stage or not). TXLevel affects only the shape and amplitude of the modulating signal at the transmitter input — that is, the deviation.

Signs of incorrect levels

Setting TXLevel via MMDVMCal

MMDVMCal is a console calibration utility bundled with Pi-Star and WPSD. In the RadioStar image you can access it via the panel (the calibration section) or over SSH. The procedure for DMR deviation:

  1. Stop MMDVMHost:
    sudo systemctl stop mmdvmhost
  2. Launch MMDVMCal, specifying the board port:
    sudo MMDVMCal /dev/ttyAMA0
    (the port may be /dev/ttyUSB0 — it depends on the board).
  3. In the MMDVMCal interface press D to enter DMR Deviation mode, then T to start a continuous TX test transmission.
  4. Receive the signal on an SDR receiver (RTL-SDR + SDR#/GQRX) or a spectrum analyzer. The 4FSK spectrum will be visible on screen — four "humps" in two bands.
  5. Use the + / - keys to change TXLevel in MMDVMCal, achieving the correct spacing between the 4FSK lines (±1.944 kHz and ±0.648 kHz — for a total deviation of ±2.75 kHz).
  6. Lock in the value you found and write it into MMDVM.ini:
    [Modem]
    TXLevel=62
    (an example — the real value depends on the specific board).
  7. Start MMDVMHost again:
    sudo systemctl start mmdvmhost
A method without an analyzer If you don't have an SDR receiver, transmit voice from a radio or key up the PTT without speaking and watch the BER in the log. Lower or raise TXLevel in steps of 5, restarting MMDVMHost after each change. The minimum stable BER at a fixed distance is your goal (<1%, ideally <0.5%).

Setting RXLevel

RXLevel is set on reception: the hotspot should reliably decode the radio's signal with a BER below 1%. The procedure:

  1. Place the radio near the hotspot at a fixed distance (for example, 1–2 meters).
  2. Transmit a test signal from the radio (PTT + speech, or a continuous tone via MMDVMCal — R mode).
  3. Watch the BER in real time:
    tail -f /var/log/pi-star/MMDVM-*.log | grep BER
  4. Change RXLevel in MMDVM.ini in steps of 5, restarting MMDVMHost each time. The goal is the minimum BER at that distance.
  5. Once you've found the optimum, move the radio out to its working distance and confirm the BER stayed acceptable.

On some boards the hardware RX potentiometer is already set correctly at the factory, and a software RXLevel=50 works well. But if the potentiometer is inaccessible or unlabeled, the software parameter becomes the only tool.

RXOffset + RXLevel together Set the frequency offset (RXOffset/TXOffset) first — it determines whether the signal lands inside the decoder's passband. Only after the frequency is accurate should you adjust RXLevel. Do it the other way around and the level optimum will be false and will drift once you correct the frequency.

Levels, BER, and DMRhub network data

In voice mode a small BER (1–3%) is perceived as mild artifacts — in practice a conversation is still possible. But DMRhub does not work with voice alone: hotspot registration, transmitting identifiers, private calls, contact-list synchronization — all of this is data. To transmit data, DMR uses the same physical symbols but requires a much lower BER: an error in a single byte of a header packet can break the entire transaction.

Correctly set TXLevel and RXLevel, paired with an accurate frequency (the offset in RXOffset/TXOffset), deliver a stable BER below 0.5% and reliable operation of the hotspot with the network server. In the RadioStar image the level parameters are available in the web panel without editing the configuration file by hand.

Typical values and reference points

There is no universal "correct" number — every board has its own DAC/ADC and signal path. Even so:

Important Do not copy TXLevel/RXLevel values from someone else's configs without checking the BER on your own board. Even identical board models can vary by component tolerances. Someone else's value is only a starting reference, not a final setting.

A steady level means a reliable link to the network

Once TXLevel and RXLevel are calibrated, the hotspot will register with DMRhub reliably, and data transmission (private calls, the app) will go through without errors. In the RadioStar image the level parameters are edited right from the panel — no SSH and no manual config editing.

Sources

  1. VK4PK — MMDVMCal DVM Calibration: the TX-deviation and RX-level procedure — lyonscomputer.com.au
  2. N4IRS MMDVM-Install Wiki — MMDVM Calibration: MMDVMCal steps, the Bessel null point — github.com/N4IRS/MMDVM-Install
  3. N4IRS MMDVM.ini reference — default TXLevel/RXLevel/DMRTXLevel parameters — github.com/N4IRS/MMDVM-Install
  4. juribeparada MMDVM_HS README — calibration for HS boards (ADF7021) — github.com/juribeparada/MMDVM_HS