我今天的文章是一个几乎偶然(尽管很自然)走上编程道路的人大声说出的想法。
是的,我明白我的经历只是我的经历,但在我看来,它很符合大势。 此外,下面描述的经验更多地与科学活动领域相关,但这不是开玩笑——它在外面也可能有用。
总的来说,献给所有现在的学生和以前的学生!
预期
2014 年,当我完成信息通信技术和通信系统学士学位时,我对编程世界几乎一无所知。 是的,像许多其他人一样,我在第一年就选修了“计算机科学”科目 - 但是,主啊,那是在我的第一年! 已经是永恒了!
总的来说,我并没有期望与学士学位有什么特别不同,当我进入硕士课程时
但徒劳无功...
我们只是第二批招收的学生,第一批的同学们还在收拾行李前往遥远的德国(硕士学位第二年的实习时间为六个月)。 也就是说,身边的人还没有认真接触过欧洲的教育方法,也没有人去询问细节。
当然,在我们的第一年,我们有各种各样的实践,其中我们通常会民主地在编写脚本(主要是 MATLAB 语言)和使用各种高度专业化的 GUI(在不编写脚本的情况下进行模拟的意义上)之间进行选择。建模环境)。
不用说,我们,未来的科学硕士,出于我们年轻时的愚蠢,避免像火一样编写代码。 例如,这里是 MathWorks 的 Simulink:这里是块,这里是连接,这里是各种设置和开关。
对于以前从事过电路设计和系统工程工作的人来说,这是一种原生且易于理解的观点!
所以在我们看来...
现实
第一个学期的实践工作之一是 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