“相关专业新手程序员宣言”或者我是如何走到这一步的

我今天的文章是一个几乎偶然(尽管很自然)走上编程道路的人大声说出的想法。

是的,我明白我的经历只是我的经历,但在我看来,它很符合大势。 此外,下面描述的经验更多地与科学活动领域相关,但这不是开玩笑——它在外面也可能有用。

“相关专业新手程序员宣言”或者我是如何走到这一步的
来源: https://xkcd.com/664/

总的来说,献给所有现在的学生和以前的学生!

预期

2014 年,当我完成信息通信技术和通信系统学士学位时,我对编程世界几乎一无所知。 是的,像许多其他人一样,我在第一年就选修了“计算机科学”科目 - 但是,主啊,那是在我的第一年! 已经是永恒了!

总的来说,我并没有期望与学士学位有什么特别不同,当我进入硕士课程时 《通信与信号处理》 德俄新技术研究所。

但徒劳无功...

我们只是第二批招收的学生,第一批的同学们还在收拾行李前往遥远的德国(硕士学位第二年的实习时间为六个月)。 也就是说,身边的人还没有认真接触过欧洲的教育方法,也没有人去询问细节。

当然,在我们的第一年,我们有各种各样的实践,其中我们通常会民主地在编写脚本(主要是 MATLAB 语言)和使用各种高度专业化的 GUI(在不编写脚本的情况下进行模拟的意义上)之间进行选择。建模环境)。

“相关专业新手程序员宣言”或者我是如何走到这一步的

不用说,我们,未来的科学硕士,出于我们年轻时的愚蠢,避免像火一样编写代码。 例如,这里是 MathWorks 的 Simulink:这里是块,这里是连接,这里是各种设置和开关。

对于以前从事过电路设计和系统工程工作的人来说,这是一种原生且易于理解的观点!

“相关专业新手程序员宣言”或者我是如何走到这一步的
来源: https://ch.mathworks.com/help/comm/examples/parallel-concatenated-convolutional-coding-turbo-codes.html

所以在我们看来...

现实

第一个学期的实践工作之一是 OFDM 信号收发器的开发,作为“建模和优化方法”主题的一部分。 这个想法非常成功:由于其在 Wi-Fi 和 LTE/LTE-A 网络(以 OFDMA 的形式)等领域的使用,该技术仍然具有相关性并且相当受欢迎。 这是大师们练习电信系统建模技能的最好的事情。

“相关专业新手程序员宣言”或者我是如何走到这一步的

现在我们得到了几个技术规范的选项,这些选项显然不切实际的框架参数(以免在互联网上寻找解决方案),我们扑向已经提到的Simulink......我们被茶壶击中头部现实的:

  • 每个块都充满了许多未知参数,这些参数很容易突然改变。
  • 对数字的操作看起来很简单,但你仍然需要大惊小怪,上帝保佑。
  • 大教堂机器由于 GUI 的疯狂使用而明显减慢速度,即使是在浏览可用块库的阶段也是如此。
  • 要在家完成某件事,您需要拥有相同的 Simulink。 事实上,没有其他选择。

是的,最终我们当然完成了这个项目,但我们是长长地松了一口气。

一段时间过去了,我们已经到了硕士第一年的结束。 随着德国科目比例的增加,使用 GUI 的作业量开始成比例下降,尽管尚未达到范式转变的程度。 我们中的许多人,包括我在内,克服了相当大的开发难度,越来越多地在我们的科学项目中使用 Matlab(尽管以工具箱的形式),而不是看似熟悉的 Simulink。

我们疑惑的地方是一位二年级学生的一句话(当时他们刚回到俄罗斯):

  • 至少在实习期间,忘记 Similink、MathCad 和其他 LabView——一切都是用 MATLAB 编写的,使用 MatLab 本身或其免费“版本”Octave。

事实证明,这种说法部分属实:在伊尔梅瑙,关于工具选择的争议也没有完全解决。 确实,选择主要是在 MATLAB、Python 和 C 之间。

同一天,我自然而然地兴奋起来:难道我不应该将我的 OFDM 发射机模型部分转换为脚本形式吗? 只是为了好玩。

我开始工作了。

一步一个脚印

我将简单地给出一个链接,而不是理论计算 优秀的文章 2011年起 g 以及幻灯片上 LTE物理层 教授 米歇尔-蒂拉 (伊尔梅瑙工业大学)。 我想这就足够了。

“那么,”我想,“让我们再说一遍,我们要建模什么?”
我们将建模 正交频分复用帧生成器 (OFDM 帧生成器)。

它将包括什么:

  • 信息符号
  • 导频信号
  • 零点(直流)

(为了简单起见)我们从以下内容中抽象出来:

  • 来自建模循环前缀(如果您了解基础知识,添加它并不困难)

“相关专业新手程序员宣言”或者我是如何走到这一步的

所考虑模型的框图。 我们将停在逆 FFT (IFFT) 块。 完成这幅图,剩下的大家可以自己继续——我答应系里的老师给学生们留下一些东西。

让我们自己定义它们。 锻炼:

  • 固定数量的子载波;
  • 固定帧长度;
  • 我们必须在帧的中间添加一个零,并在帧的开头和结尾添加一对零(总共 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;

然后可以使用函数确定位置 林空间,将值减少到最接近的整数中的最小值:

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); 

现在让我们了解导频信号。

我们有一个模板(变量 飞行员),假设我们希望此模板中的导频按顺序插入到我们的帧中。 当然,这可以循环完成。 或者您可以使用矩阵来玩点小技巧 - 幸运的是 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

“极乐!” ——我心满意足地想着,合上了笔记本电脑。 我花了几个小时才完成所有事情:包括编写代码、学习一些 Matlab 函数以及思考数学技巧。

我当时得出什么结论呢?

主观:

  • 写代码是令人愉快的,就像诗歌一样!
  • 脚本编写是通信和信号处理领域最方便的研究方法。

目的:

  • 没有必要用大炮射麻雀(当然,除非这样的教育目标是值得的):使用 Simulink,我们用复杂的工具解决了一个简单的问题。
  • GUI 很好,但了解“幕后”包含的内容会更好。

现在,我已经不再是一名学生了,我想对学生们说以下的话:

  • 去了!

尝试编写代码,即使一开始很糟糕。 对于编程,与任何其他活动一样,最困难的部分是开始。 最好尽早开始:如果您是一名科学家,甚至只是一名技术人员,迟早您会需要这项技能。

  • 要求!

要求教师和主管采用先进的方法和工具。 如果这可能的话,当然……

  • 要有创意!

如果不在教育计划的框架内,还有什么地方可以更好地克服初学者的所有痛苦呢? 创造并磨练你的技能——同样,越早开始越好。

各国有抱负的程序员,联合起来!

PS

为了记录我与学生的直接关系,我附上一张 2017 年与两位校长的难忘照片:Peter Scharff(右)和 Albert Kharisovich Gilmutdinov(左)。

“相关专业新手程序员宣言”或者我是如何走到这一步的

至少为了这些服装完成这个节目是值得的! (开玩笑)

来源: habr.com

添加评论