Привет, Хабр!  Сегодня хочу поделиться своим небольшим домашним проектом: ModulationPy (GitHub) На данный момент доступны два класса схем модуляции: M-PSK: Phase Shift Keying (фазовая цифровая модуляция) M-QAM: Quadratured Amplitude Modulation (квадратурная амплитудная модуляция) где M - это порядок модуляции. Интересен модуль может быть, скорее всего, в разрезе образовательных целей в сфере беспроводной связи (подбор модуляций исходил именно из нее), однако, вдруг кому-то пригодится и для научных изысканий. Не MatLab'ом насущным едины! Итак, для начала скачиваем библиотеку с PyPI: Либо устанавливаем из исходников, но на PyPI на момент написания статьи все-таки актуальная версия.  Зависимости две:  numpy>=1.7.1 matplotlib>=2.2.2 (для построения сигнальных созвездий) Продемонстрируем на деле. Итак, например, мы хотим использовать QPSK с поворотом фазы pi/4, двоичным входом и наложением по Грею (Gray mapping). Импортируем и инициализируем: Проверяем то ли мы инициализировали, нарисовав сигнальное созвездие методом plot_const(): То же самое сделаем для 16-QAM (но для десятичных чисел на входе; указывать фазовый сдвиг не нужно - подразумевается наиболее распространенная прямоугольная QAM): На данный момент модуляция QAM реализована по примеру функции qammod в Octave [4]. И, да, реализованы только «четные» (в том смысле, что результат log2(M) - четное число) схемы модуляции (4-QAM, 16-QAM, 64-QAM). Пусть и не совсем полный набор, но как бы то ни было, в популярных стандартах беспроводной связи все равно нет "нечетных" схем модуляции (насколько я знаю). Далее предлагаю перейти, собственно, к главному в модемах: к модуляции и демодуляции. Для этого нам понадобятся два метода:modulate() и demodulate() , доступные в обоих классах. Метод modulate() принимает на вход всего один аргумент:  вектор входных значений (1-D ndarray of ints) - либо единиц и нулей, если выбрана опция bin_input=True , либо целых десятичных чисел от 0 до M-1, если bin_input=False ; Методdemodulate() ожидает максимум два аргумента:  вектор, который должен быть демодулирован (1-D ndarray of complex symbols)  ; значение дисперсии аддитивного шума (float, по умолчанию 1.0). Например, вот как это будет выглядеть для QPSK (двоичный вход/выход): Или тоже QPSK, но уже с недвоичным входом / выходом: Пример для 16-QAM (десятичный вход / выход): В общем и целом, я думаю, понятно. Доступные опции старался делать по примеру доступных в рамках матлабовского Communication Toolbox. Подробное описание приведено в README.md проекта.  Продемонстрируем адекватно ли модемы работают в случае присутствия шума (возьмем классический АБГШ, он же AWGN), используя простейшую модель приема-передачи: Сверяться будем с теоретическими кривыми [5] (если кому интересно, все формулы описаны тоже в README.md).  Исходные коды для моделирования представлены по ссылкам: M-PSK, M-QAM. Результаты: Да, с огрехами на малых значениях битовых ошибок (из-за относительно небольшого количества усреднений, я полагаю), однако.... it works!  А теперь я хотел бы вернуться к вопросу "соревнования" с упомянутой выше CommPy.  Что нас отличает: организация кода, стилистические различия (побочное, но не пренебрежимое);  я использовал более быстрый алгоритм демодуляции [6] (подробно описан в матлабовской документации , ну, и я добавил все в тот же README.md). И вот, что получилось "забенчмаркать": Скрипт: CommPy_vs_ModulationPy.ipynb Платформа: https://jupyter.org/try (Classic Notebook) Длина фрейма: 10 000 (элементов) Результаты: Метод (библиотека) Среднее время исполнения (мс) modulation (ModulationPy):  QPSK 10.3 modulation (CommPy):  QPSK 15.7 demodulation (ModulationPy):  QPSK 0.4 demodulation (CommPy):  QPSK 319 modulation (ModulationPy):  256-QAM 8.9 modulation (CommPy):  256-QAM 11.3 demodulation (ModulationPy):  256-QAM 42.6 demodulation (CommPy):  256-QAM 22 000 Разработчикам CommPy результаты, вроде, понравились (см. данный issue) - поэтому возможно в обозримом будущем что-то из моего ModulationPy будет перекочевывать в CommPy (я не против, главное, чтобы пользу приносило). Но это, как говорится, поживем - увидим. И, да, пусть результаты производительности и не дотянули до MatLab (по крайней мере исходя из данного примера: см. вкладку "Examples"), я все равно считаю достигнутое неплохим стартом! Наверное, проекту не хватает еще некоторых видов модуляции (тех же 32-QAM и 128-QAM или же используемой в DVB-S2/S2X APSK), однако, честно скажу, что не могу обещать их скорого добавления.  Проект всегда был для меня в большей мере площадкой для изучения языка Python и библиотеки  NumPy на практике (и сопутствующих инструментов: юнит-тесты (не успел правда в данном случае перейти на pytest - каюсь), CI (использую Travis), подготовка модуля для PyPi и т.д.), однако, теперь, слава богу, всему этому есть приложение и в рамках рабочих задач! Однако, все же буду рад вашим issue и pull request'ам! И если возьметесь интегрировать наработки в CommPy, тоже будет очень круто!  В общем, не серчайте, если вдруг не отвечу достаточно быстро, и да пребудет с вами сила науки!  Haykin S. Communication systems. – John Wiley & Sons, 2008. — p. 93  Goldsmith A. Wireless communications. – Cambridge university press, 2005. – p. 88-92 MathWorks: comm.PSKModulator (https://www.mathworks.com/help/comm/ref/comm.pskmodulator-system-object.html?s_tid=doc_ta) Octave: qammod (https://octave.sourceforge.io/communications/function/qammod.html) Link Budget Analysis: Digital Modulation, Part 3 (www.AtlantaRF.com) Viterbi, A. J. (1998). An intuitive justification and a simplified implementation of the MAP decoder for convolutional codes. IEEE Journal on Selected Areas in Communications, 16(2), 260-264. MathWorks: Approximate LLR Algorithm (https://www.mathworks.com/help/comm/ug/digital-modulation.html#brc6ymu) Инженер