Сегодняшняя моя статья — это мысли вслух от человека, который встал на путь программирования почти случайно (хотя и закономерно).


Да, я понимаю, что мой опыт — это только мой опыт, однако он, мне кажется, хорошо попадает в общую тенденцию. Более того, опыт, описанный ниже, больше относится к сфере научной деятельности, однако чем чёрт не шутит — может пригодится и вне.



Источник: https://xkcd.com/664/


В общем, всем настоящим студентам от бывшего студента посвящается!


Ожидания


Когда в 2014 году я заканчивал бакалавриат по специальности "Инфокоммуникационные технологии и системы связи" я почти ничего не знал о мире программирования. Да, у меня, как и у многих, был на первом курсе предмет "Информатика" — но, господи, это же было на первом курсе! Прошла целая вечность!


В общем и целом, ничего особенно отличного от бакалавриата я не ждал, и поступая на магистерскую программу "Communication and Signal Processing" Германо-Российского Института Новых Технологий.


А зря...


Мы были всего вторым набором, и ребята с первого ещё только собирали чемоданы в далёкую Германию (стажировка занимает полгода на втором курсе магистратуры). Иначе говоря, никто из ближайшего круга ещё не сталкивался всерьёз с методами европейского образования, и спрашивать о деталях было особо не у кого.


Были у нас на первом курсе, конечно, разного рода практики, на которых обычно нам демократично предлагался выбор между написанием скриптов (преимущественно на языке MATLAB) и использованием разных узкоспециализированных GUI (в том смысле, что без написания скриптов — сред имитационного моделирования).



Стоит ли говорить, что мы, будущие Masters of Science, по своей юношеской дурости, как огня, сторонились написания кода. Вот, он, допустим, Simulink от компании MathWorks: вот они блоки, вот они связи, вот они всякого рода настройки и переключатели.


Родной и понятный для человека, занимавшегося прежде схемотехникой и системотехникой, вид!

Так нам казалось...


Реальность


Одной из практических работ первого семестра была разработка приёмопередатчика OFDM сигнала в рамках предмета "Methods for Modeling and Optimization". Идея весьма удачная: технология и по сей день актуальная и довольно популярная в силу использования, например, в сетях Wi-Fi и LTE/LTE-A (в виде OFDMA). Самое то для магистров, чтобы потренировать навыки моделирования телеком систем.



И вот на руки нам выдают несколько вариантов ТЗ с заведомо непрактичными параметрами кадра (дабы не искать решение в Интернете), и мы накидываемся на уже упомянутый Simulink… И получаем чайником действительности по голове:


  • Каждый блок таит в себе уйму неизвестных параметров, менять которые с кондачка — страшновато.
  • Манипуляции с числами произвести нужно, вроде, простые, однако городить приходится всё равно дай боже.
  • Кафедральные машины заметно подтормаживают от лихорадочного использование GUI, даже на этапе серфинга по библиотекам доступных блоков.
  • Чтобы доделать что-то дома, нужно иметь такой же Simulink. И никаких, собственно, альтернатив.

Да, проект в итоге мы, конечно, доделали, но доделали с громким выдохом облегчения.


Прошло некоторое время, и мы подошли к окончанию первого курса магистратуры. Количество домашних работ с использованием GUI стало пропорционально спадать с увеличением доли немецких предметов, хотя ещё и не достигало точки смены парадигмы. Многие из нас, включая меня, преодолевая свою немалую амплитуду на раскачку, всё больше и больше использовали в своих научных проектах именно Matlab (пусть и в виде Toolbox'ов), а не знакомый, казалось бы, Simulink.


Точкой в наших сомнениях стала фраза одного из студентов второго курса (они как раз к тому времени вернулись в Россию):


  • Забудьте, по крайне мере на время стажировки, про Similink, MathCad и прочий LabView — за бугром всё пишут на языке MATLAB, используя собственно сам MatLab или его бесплатную "версию" Octave.

Заявление оказалось верным отчасти: в Ильменау спор о выборе инструментария тоже не был решен до конца. Правда, выбор стоял по большей части между языками MATLAB, Python и C.


В тот же день меня взял закономерный азарт: а не перенести ли свою часть модели OFDM передатчика в скриптовую форму? Just for fun.


И я приступил к работе.


Step by step


Вместо теоретических выкладок я просто дам ссылку на эту прекрасную статью 2011 года от tgx и на слайды по физическому уровню LTE профессора Мишель-Тиля (ТУ Ильменау). Я думаю, этого будет достаточно.

"Итак, — подумал я, — повторим, что же мы будем моделировать?"
Моделировать будем генератор OFDM кадра (OFDM frame generator).


Что он будет включать:


  • информационные символы
  • пилотные сигналы
  • нули (DC)

От чего (простоты ради) мы абстрагируемся:


  • от моделирования циклического префикса (при знании основ, добавить оный уже не составит труда)


Блок-схема рассматриваемой модели. Остановимся мы до блока обратного БПФ (IFFT). Остальное для полноты картины каждый может продолжить сам — я обещал преподавателям с кафедры оставить что-то и для студентов.


Определим для себя тех. задание:


  • фиксированное количество поднесущих (sub-carriers);
  • фиксированная длина кадра;
  • мы должны добавить один ноль в середину и по паре нулей к началу и концу кадра (итого, 5 штук);
  • информационные символы модулируются с помощью M-PSK или M-QAM, где M — это порядок модуляции.

Приступаем к коду.


Скрипт целиком можно скачать по ссылке.

Определим входные параметры:


clear all; close all; clc

M = 4; % e.g. QPSK 
N_inf = 16; % number of subcarriers (information symbols, actually) in the frame
fr_len = 32; % the length of our OFDM frame
N_pil = fr_len - N_inf - 5; % number of pilots in the frame
pilots = [1; j; -1; -j]; % pilots (QPSK, in fact)

nulls_idx = [1, 2, fr_len/2, fr_len-1, fr_len]; % indexes of nulls

Теперь определим индексы информационных символов, приняв предпосылку, что пилотные сигналы должны обязательно идти до и/или после нулей:


idx_1_start = 4;
idx_1_end = fr_len/2 - 2;

idx_2_start = fr_len/2 + 2;
idx_2_end =  fr_len - 3;

Тогда позиции можно определить с помощью функции linspace, приведя значения к наименьшему из ближайших целых:


inf_idx_1 = (floor(linspace(idx_1_start, idx_1_end, N_inf/2))).'; 
inf_idx_2 = (floor(linspace(idx_2_start, idx_2_end, N_inf/2))).';

inf_ind = [inf_idx_1; inf_idx_2]; % simple concatenation

Добавим к этому индексы нулей и отсортируем:


%concatenation and ascending sorting
inf_and_nulls_idx = union(inf_ind, nulls_idx); 

Соответственно, индексы пилотных сигналов — это всё остальное:


%numbers in range from 1 to frame length 
% that don't overlape with inf_and_nulls_idx vector
pilot_idx = setdiff(1:fr_len, inf_and_nulls_idx); 

Теперь давайте разбираться с пилотными сигналами.


У нас есть шаблон (переменная pilots), и, допустим, мы хотим, чтобы в наш кадр пилоты вставлялись из этого шаблона последовательно. Сделать это, конечно, можно в цикле. А можно немного помудрить с матрицами — благо MATLAB позволяет делать это с достаточным комфортом.


Во-первых, определим, сколько таких шаблонов помещается в кадр полностью:


pilots_len_psudo = floor(N_pil/length(pilots));

Далее формируем вектор, который состоит из наших шаблонов:


% linear algebra tricks:
mat_1 = pilots*ones(1, pilots_len_psudo); % rank-one matrix
resh = reshape(mat_1, pilots_len_psudo*length(pilots),1); % vectorization

И определяем небольшой вектор, который содержит только кусок шаблона — "хвост", не поместившийся полностью в кадр:


tail_len = fr_len  - N_inf - length(nulls_idx) ...
                - length(pilots)*pilots_len_psudo; 
tail = pilots(1:tail_len); % "tail" of pilots vector

Получаем пилотные символы:


vec_pilots = [resh; tail]; % completed pilots vector that frame consists

Переходим к информационным символам, а именно сформируем сообщение и промодулируем его:


message = randi([0 M-1], N_inf, 1); % decimal information symbols

if M >= 16
    info_symbols = qammod(message, M, pi/4);
else
    info_symbols = pskmod(message, M, pi/4);
end 

Всё готово! Собираем кадр:


%% Frame construction
frame = zeros(fr_len,1);
frame(pilot_idx) = vec_pilots;
frame(inf_ind) = info_symbols

Получится должно что-то такое:


frame =

   0.00000 + 0.00000i
   0.00000 + 0.00000i
   1.00000 + 0.00000i
  -0.70711 - 0.70711i
  -0.70711 - 0.70711i
   0.70711 + 0.70711i
   0.00000 + 1.00000i
  -0.70711 + 0.70711i
  -0.70711 + 0.70711i
  -1.00000 + 0.00000i
  -0.70711 + 0.70711i
  -0.70711 - 0.70711i
   0.00000 - 1.00000i
   0.70711 + 0.70711i
   1.00000 + 0.00000i
   0.00000 + 0.00000i
   0.00000 + 1.00000i
   0.70711 - 0.70711i
  -0.70711 + 0.70711i
  -1.00000 + 0.00000i
  -0.70711 + 0.70711i
   0.70711 + 0.70711i
   0.00000 - 1.00000i
  -0.70711 - 0.70711i
   0.70711 + 0.70711i
   1.00000 + 0.00000i
   0.70711 - 0.70711i
   0.00000 + 1.00000i
   0.70711 - 0.70711i
  -1.00000 + 0.00000i
   0.00000 + 0.00000i
   0.00000 + 0.00000i

"Кайф!" — подумал я довольно и закрыл ноутбук. Ушло у меня на всё про всё пару часов: включая написание кода, изучение некоторых матлабовских функций и продумывание математических трюков.


Какие выводы я тогда сделал


Субъективные:


  • Писать код приятно и сродни поэзии!
  • Написание скриптов — наиболее удобный метод исследований для области Communication and Signal Processing.

Объективные:


  • Не надо палить из пушки по воробьям (если такая учебная цель, конечно, не стоит): использовав Simulink, мы взялись за решение простой задачи навороченным инструментом.
  • GUI — это хорошо, но понимать что содержится "под капотом" — лучше.

И теперь, будучи уже далеко не студентом, я хочу сказать студенческой братии следующее:


  • Дерзайте!

Пробуйте писать код, пусть даже поначалу он будет плохим. С программированием как и с любой другой деятельностью, лиха беда — начало. А начать лучше раньше: если вы ученый или даже просто технарь — рано или поздно этот навык вам понадобится.


  • Требуйте!

Требуйте от преподавателей и научных руководителей прогрессивных подходов и инструментов. Если это, конечно, сколько-то возможно…


  • Творите!

Где же ещё лучше всего переболеть всеми болячками новичка, как не в рамках образовательной программы? Творите и оттачивайте своё мастерство — опять же чем раньше начать, тем лучше.


Начинающие программисты всех стран, объединяйтесь!


P.S.


Дабы запротоколировать своё прямое отношение к студенчеству, прикладываю памятное фото 2017 года с двумя ректорами: Петером Шарффом (справа) и Альбертом Харисовичем Гильмутдиновым (слева).


image


Стоило закончить программу как минимум ради таких костюмов! (шучу)

Комментарии (5)


  1. JekaMas
    26.08.2019 20:45

    Отрадно вас читать! Особенно ваши выводы.


    1. ritchie_kyoto Автор
      27.08.2019 07:05

      Спасибо вам за отзыв!


  1. melodictsk
    27.08.2019 06:47

    Я учился на радиофизика лазерщика, но программировать приходилось все 6 лет обучения. Некоторые кафедры больше, некоторые меньше. Я был в той где меньше. Не было SQL и прочих прикладных тем. Но основам программирования учили всех на первых курсах, ассемблер давали усеченно всем, численным методам на дэлфи обучили всех. это был 2000-2006 годы.


    1. ritchie_kyoto Автор
      27.08.2019 06:59

      С моей точки зрения, вам повезло с подходами к образованию. Спасибо за отзыв!


  1. simonrus
    27.08.2019 14:23
    +1

    Крайне рекомендую dsplog.com. Это то, что надо давать студентам 3-4 курса параллельно с современной теорией связи