This repository contains Python simulation utilities and MATLAB research codes for Rydberg atomic receivers. The top-level workflow is split into three parts: A Flask-based web visualizer for asynchronous quantum-receiver simulation, a Python single-carrier simulator that can be reused programmatically, and paper-oriented MATLAB codes for reproduction of my paper on dynamic transfer functions of Rydberg atomic receivers.
Author: Jieao Zhu from Tsinghua University, using Copilot as my AI coding agent
The web visualizer (Fig.1) is a lightweight Flask application defined in app.py. It provides a browser-based front end for launching Rydberg atomic receiver simulations, monitoring background jobs, and visualizing the generated transmit and receive waveforms.
Fig.1 Website of Rydberg atomic receiver simulation
Fig.2 Waveform panels and console of the Rydberg atomic simulator
app.pyis the entry point of the web service.templates/index.htmlandstatic/js/app.jsimplement the browser UI.- The request flow is:
- Generate a random transmit IF waveform.
- Choose the simulation backend (
cpporcuda). - Launch the quantum receiver simulation in a background worker.
- Poll the job status and render the returned waveforms and constellation data.
- The asynchronous worker is implemented in
python/web_sc_worker.py, while the simulation logic lives inpython/web_single_carrier.py. - The reusable classes for waveform generation are implemented in
python/utils/sim_SingleCarrier.pyandpython/utils/sim_OFDM.py. - The reusable classes for
C++/CUDA-based quantum simulation are implemented inpython/utils/transient_quantum.py.
The web visualizer can use either the C++ RK4 backend or the CUDA backend. Build the optional kernels from the repository root:
make cpp
make cudaThe build scripts place the binaries under python/utils/bin/.
On Windows, the CUDA build may need a valid host compiler path via CUDAHOSTCXX. The CUDA shared library must export cudaThermalSim, which is already handled by python/utils/build_cu.sh.
Start the web service from the repository root with:
python app.pyThe service listens on 0.0.0.0:5000 by default, so it can be opened locally in a browser or accessed from another machine on the same network when the firewall allows it.
If the C++ or CUDA backend is unavailable, the web API will return an error until the corresponding binary has been built.
Fig.3 Speedup of CUDA-based simulator v.s. traditional C++-based simulator
When the Flask service is running on the simulation server, an external computer can call the API at http://<server-ip>:5000.
Recommended request sequence:
POST /api/generate_txto generate a transmit IF waveform and obtainseed.POST /api/start_simulationwith the same waveform parameters andseed.GET /api/simulation_status/<job_id>untilstatusbecomescompleted.
Required JSON parameters:
| API | Required parameters | Optional parameters | Notes |
|---|---|---|---|
/api/generate_tx |
zc_length, symbol_count |
seed |
If seed is omitted, the server generates one. |
/api/start_simulation |
zc_length, symbol_count, seed, engine |
gpu_index |
engine must be cpp or cuda; gpu_index is required when engine=cuda. |
/api/simulation_status/<job_id> |
job_id (path parameter) |
offset (query parameter) |
offset is used for incremental log pulling. |
Example client script from an external computer:
import requests
import time
BASE = "http://192.168.1.100:5000"
# 1) Generate TX waveform
tx_req = {
"zc_length": 139,
"symbol_count": 100,
}
tx_rsp = requests.post(f"{BASE}/api/generate_tx", json=tx_req, timeout=30)
tx_rsp.raise_for_status()
tx_payload = tx_rsp.json()
seed = tx_payload["seed"]
# 2) Start simulation
sim_req = {
"zc_length": 139,
"symbol_count": 100,
"seed": seed,
"engine": "cpp", # use "cuda" with an extra gpu_index field
}
start_rsp = requests.post(f"{BASE}/api/start_simulation", json=sim_req, timeout=30)
start_rsp.raise_for_status()
job_id = start_rsp.json()["job_id"]
# 3) Poll status
offset = 0
while True:
stat_rsp = requests.get(f"{BASE}/api/simulation_status/{job_id}", params={"offset": offset}, timeout=30)
stat_rsp.raise_for_status()
stat = stat_rsp.json()
offset = stat.get("next_offset", offset)
if stat["status"] == "completed":
result = stat["result"]
print("MSE(dB):", result["mse_db"])
break
if stat["status"] == "failed":
raise RuntimeError(stat.get("error", "Simulation failed"))
time.sleep(1.0)On the local machine, you can directly build the single-carrier link without HTTP by reusing the chain in python/study_sc.py.
The pipeline is:
- Generate symbols and IF waveform with
SingleCarrierinpython/utils/sim_SingleCarrier.py. - Up-convert to IF and map to incident E-field.
- Resample to RK grid (
dt=1e-9) and runTransientQuantumSimulator.run(...). - Convert probe response to real IF waveform.
- Down-convert and demodulate with
demodSingleCarrierWaveform(...). - Compute constellation MSE.
Minimal local example (aligned with study_sc.py):
import numpy as np
from scipy.signal import resample_poly, butter, lfilter
from utils.sim_SingleCarrier import SingleCarrier
from utils.transient_quantum import TransientQuantumSimulator, SimConfig, configure_raqr
Fs_sym = 100e3
Fs_IF = 2e6
IF_freq = 60e3
NinfoSyms = 100
np.random.seed(114514)
sc = SingleCarrier(Fs_sym, Fs_IF, rollOffFactor=0.2, paddingZeros=10)
tx_syms = np.array([sc.Symbols[i] for i in np.random.randint(0, len(sc.Symbols), size=NinfoSyms)])
tx_if = sc.modSingleCarrierWaveform(tx_syms)
tx_if *= np.exp(1j * 2.0 * np.pi * (IF_freq / Fs_IF) * np.arange(len(tx_if)))
raqr = configure_raqr("Transit")
Pt_dBm, distance_m, eta0 = 10.0, 120.0, 376.73
Eamp = np.sqrt((10 ** (Pt_dBm / 10.0) * 1e-3 * 10 ** (2.15 / 10.0) * 2.0 * eta0) / (4.0 * np.pi * distance_m ** 2))
dt = 1e-9
rk_fs = 1.0 / dt
rk_wave = resample_poly(tx_if, int(round(rk_fs / Fs_IF)), 1)
t_arr = np.arange(0.0, len(rk_wave) * dt, dt)
sim_cfg = SimConfig(Temperature=300.0, Nt=len(t_arr), dt=dt, T=len(t_arr) * dt, t_arr=t_arr)
sim = TransientQuantumSimulator(verbose=False)
resp = sim.run(raqr, sim_cfg, raqr.A_LO + Eamp * rk_wave, init_method="SteadyState", Nd=1501, n_jobs=-1, use_cpp_rk=True, device="cpu", prefer_threadpool=True, speed_grade=1)
rx_probe_linear = 10 ** (resp.probeResponse / 10.0)
rx_probe_linear = rx_probe_linear[500:-500]
rx_if_real = resample_poly(rx_probe_linear, 1, int(round(rk_fs / Fs_IF)))[50:-50]
rx_if_real -= np.mean(rx_if_real)
b, a = butter(8, 1.2 * Fs_sym / Fs_IF, btype="low")
rx_if_cplx = lfilter(b, a, rx_if_real * np.exp(-1j * 2 * np.pi * (IF_freq / Fs_IF) * np.arange(len(rx_if_real))))
rx_syms = sc.demodSingleCarrierWaveform(rx_if_cplx, NrxSymbols=NinfoSyms, verbose=0)
mse_db = 10.0 * np.log10(np.mean(np.abs(tx_syms - rx_syms) ** 2))
print("MSE(dB):", mse_db)You can also run the full reference script directly:
python -u ./python/study_sc.py # Run the speed benchmark of single-carrier simulators Apart from building a Rydberg simulation website, this code package is also meant for reproducing the results of the following paper [1]:
[1] J. Zhu and L. Dai, "General signal model and capacity limit for Rydberg quantum information system," IEEE Trans. Wireless Commun., vol. 25, no. 12, pp. 8292-8307, Dec. 2025.
If you use this simulation code package in any way, please cite the original paper [1] above.
The author in charge of this simulation code package is: Jieao Zhu (email: zja21@mails.tsinghua.edu.cn ; johnzja@qq.com).
Reference: We highly respect reproducible research, so we try to provide the simulation codes for our published papers. More information can be found at: http://oa.ee.tsinghua.edu.cn/dailinglong/publications/publications.html, or at the IEEE website:
https://ieeexplore.ieee.org/document/11278503.
Please note that the MATLAB R2025a is used for this simulation code package, and there may be some incompatibility problems among different MATLAB versions.
Copyright reserved by the Broadband Communications and Signal Processing Laboratory (led by Dr. Linglong Dai), Department of Electronic Engineering, Tsinghua University, Beijing 100084, China.
Abstract of the paper:
Abstract—Rydberg atomic receivers represent a transformative approach to achieving high-sensitivity, broadband, and miniaturized radio frequency (RF) reception. However, existing static signal models for Rydberg atomic receivers rely on the steady-state assumption of atomic quantum states, which cannot fully describe the signal reception process of dynamic signals. To fill in this gap, in this paper, we present a general model to compute the dynamic signal response of Rydberg atomic receivers in closed form. Specifically, by applying small-signal perturbation techniques to the quantum master equation, we derive closed-form Laplace domain transfer functions that characterize the receiver’s dynamic responses to time-varying signal fields. To gain more insights into the quantum-based RF-photocurrent conversion process, we further introduce the concept of quantum transconductance that describes the quantum system as an equivalent classical system. By applying quantum transconductance, we quantify the influence of in-band blackbody radiation (BBR) noise on the atomic receiver sensitivity. Extensive simulations for Rydberg atomic receivers validate the proposed signal model, and demonstrate the possibility of quantum receivers to outperform classical electronic receivers through the improvement of quantum transconductance.
| MATLAB script | Description | Paper figure |
|---|---|---|
./matlab/sim_ptResp_transit.m |
Draws the probe transmission (pt) as a function of |
|
./matlab/sim_gqFreqResp.m |
Draws the quantum transconductance |
Fig. 9 |
./matlab/study_DCtransfer.m |
Draws the probe response as a function of |
Fig. 2 |
./matlab/sim_noise.m |
Draws the quantum transconductance and output noise PSD as a function of |
Fig. 5 and Fig. 7 |
./matlab/wfsims/sim_singleCarrier.m |
Performs single-carrier transmission test for Rydberg atomic receivers. | Fig. 6 and Fig. 11 |
./matlab/sim_QuantumTransConductance.m |
Draws the zero-pole plot and frequency response of the quantum transconductance |
Fig. 10 |
./matlab/sim_RydbergMIMO.m |
Performs Rydberg-MIMO capacity simulation, compared with conventional RF receivers with antenna mutual coupling. | Fig. 12 |
Enjoy the reproducible research!



