Waterfall, или водопад, — это спо­соб визу­али­зации сиг­налов, который мож­но встре­тить прак­тичес­ки во всех прог­раммах для работы с радио. Каж­дая линия показы­вает спектр сиг­нала, его час­тоты и ампли­туду. А если нем­ного покол­довать, мож­но рисовать на этом водопа­де кар­тинки. Этим мы сегод­ня и зай­мем­ся.
Пример водопада из программы Gqrx
При­мер водопа­да из прог­раммы Gqrx
 

Сигнал и его спектр

Спектр — это пред­став­ление сиг­нала в час­тотной области, которое показы­вает, какие имен­но час­тоты при­сутс­тву­ют в сиг­нале. Спектр быва­ет ампли­туд­ным и фазовым. Пер­вый показы­вает ампли­туды час­тот в сиг­нале, а вто­рой — фазы этих час­тот. В сов­ремен­ном мире, ког­да кто‑то пишет о спек­тре, обыч­но под­разуме­вает­ся имен­но ампли­туд­ный спектр.

Сам спектр быва­ет двух видов: неп­рерыв­ный и дис­крет­ный. Неп­рерыв­ный спектр — это ког­да сиг­нал содер­жит бес­конеч­ное чис­ло ком­понент, рас­пре­делен­ных в диапа­зоне час­тот. Дис­крет­ный — ког­да сиг­нал содер­жит толь­ко опре­делен­ные час­тотные ком­понен­ты. Такое харак­терно для сиг­налов, которые сос­тавле­ны из, нап­ример, сум­мы синусо­ид или косину­соид.

Те­перь нач­нем с самого прос­того — с синусо­идаль­ного сиг­нала.

info

Все свои экспе­римен­ты с матема­тикой я буду делать в Octave.

Соз­дадим синусо­иду с ампли­тудой 1 попугай и час­тотой 5 Гц.

% Амплитуда
A = 1;
% Частота в герцах
f = 5;
% Длительность нашего сигнала в секундах
T = 1;
% Частота дискретизации, или количество точек в секунду. Этот параметр влияет на точность вывода: чем больше точек, тем точнее сигнал
fs = 100;
% Временной ряд
t = 0:1/fs:T;
% Генерируем!
y = A * sin(2 * pi * f * t);
plot(t, y);
xlabel('Время (с)');
ylabel('Амплитуда');
title('Синусоида');
grid on;

Пос­ле запус­ка это­го кода в Octave ты получишь гра­фик синусо­иды.

Синусоида
Си­нусо­ида

На гра­фике пять положи­тель­ных полупе­риодов и пять отри­цатель­ных, потому что дли­тель­ность — 1 с, а час­тота — 5 Гц, вот и получа­ется, что пол­ных пери­одов имен­но пять. Это самый прос­той сиг­нал, который име­ет толь­ко одну час­тоту в спек­тре — это час­тота самой синусо­иды, то есть 5 Гц.

 

Преобразование Фурье

Определение

Пре­обра­зова­ние Фурье́ (сим­вол ℱ) — опе­рация, сопос­тавля­ющая одной фун­кции вещес­твен­ной перемен­ной дру­гую (вооб­ще говоря, ком­плексноз­начную) фун­кцию вещес­твен­ной перемен­ной. Эта новая фун­кция опи­сыва­ет коэф­фици­енты («ампли­туды») при раз­ложении исходной фун­кции на эле­мен­тарные сос­тавля­ющие — гар­моничес­кие колеба­ния с раз­ными час­тотами.

По сути, пре­обра­зова­ние Фурье — это опе­рация, которая поз­воля­ет раз­ложить сиг­нал на его прос­тые сос­тавля­ющие, то есть опре­делить, из сум­мы каких сиг­налов на каких час­тотах он сос­тоит.

Разложение сигнала на элементы с помощью преобразования Фурье
Раз­ложение сиг­нала на эле­мен­ты с помощью пре­обра­зова­ния Фурье

На кар­тинке выше наг­лядно показан про­цесс такого раз­ложения. И наобо­рот — сум­ма всех синих сиг­налов даст крас­ный, а их час­тоты показа­ны на спек­тре сиг­нала спра­ва.

При пря­мом пре­обра­зова­нии Фурье мы получа­ем на выходе ком­плексное чис­ло, которое сос­тоит из реаль­ной и мни­мой час­ти.

Комплексные числа

Ком­плексное чис­ло — это рас­ширен­ное мно­жес­тво вещес­твен­ных чисел. Ком­плексные чис­ла выг­лядят сле­дующим обра­зом: a + bi, где a и b — вещес­твен­ные чис­ла, а i — мни­мая еди­ница. Мни­мая еди­ница — это корень из –1, то есть = –1.

В радио очень широко исполь­зуют­ся ком­плексные чис­ла, так как они поз­воля­ют хра­нить боль­ше информа­ции о сиг­нале. Нап­ример, сущес­тву­ют ампли­туд­ный и фазовый спек­тры, и пер­вый опре­деля­ется дей­стви­тель­ной частью, а вто­рой — мни­мой.

Сра­зу же хочет­ся упо­мянуть еще одно из свой­ств пре­обра­зова­ния Фурье: если сдви­гать сиг­нал во вре­мени, то ампли­туд­ный спектр сиг­нала менять­ся не будет. Изме­нять­ся будет толь­ко фазовый спектр, который опи­сыва­ется ком­плексной частью.

 

Обратное преобразование Фурье

Об­ратное пре­обра­зова­ние Фурье — это про­цеду­ра получе­ния сиг­нала из спек­тра. У сиг­нала может быть нес­коль­ко парамет­ров, такие как мак­сималь­ная ампли­туда, диапа­зон час­тот и его дли­тель­ность. Давай нач­нем с прос­того при­мера: сде­лаем сиг­нал из спек­тра, на котором будет толь­ко отметка в 5 Гц с ампли­тудой 1.

% Частота дискретизации в герцах
fs = 1000;
% Длительность сигнала в секундах
T = 1;
% Общее количество отсчетов
N = T * fs;
% Создание спектра
% Инициализация спектра нулями
spectrum = zeros(1, N);
% Частота для отметки в спектре
f_target = 5;
% Индекс для частоты 5 Гц
index = f_target + 1;
% Установка амплитуды
spectrum(index) = 1;

Пер­вым делом зада­ются парамет­ры: дли­тель­ность, час­тота дис­кре­тиза­ции и количес­тво отсче­тов на осно­ве дли­тель­нос­ти и дис­кре­тиза­ции. Далее соз­даем сам спектр — он будет, по сути, прос­то мас­сивом. Уста­нав­лива­ем в нем все зна­чения в ноль и толь­ко ампли­туду час­тоты 5 Гц ста­вим в еди­ницу. В этом при­мере мы уста­нав­лива­ем толь­ко вещес­твен­ную часть ком­плексно­го чис­ла. Ты можешь поп­робовать добавить мни­мую часть — для это­го вмес­то spectrum(index) = 1; напиши spectrum(index) = 1 + 4i; и пос­мотри, что будет. Фаза сиг­нала дол­жна изме­нить­ся.

% Обратное преобразование Фурье для получения сигнала
signal = real(ifft(spectrum));
t = 0:1/fs:T-1/fs;
% Визуализация сигнала
figure;
plot(t, real(signal));
title('Сигнал, полученный из спектра');
xlabel('Время (с)');
ylabel('Амплитуда');
% Визуализация спектра
f_axis = (0:N-1) * fs / N;
figure;
stem(f_axis(1:N/2), abs(spectrum(1:N/2)), 'filled');
title('Спектр с отметкой на 5 Гц');
xlabel('Частота (Гц)');
ylabel('Амплитуда');
xlim([0 10]);

Пре­обра­зуем наш спектр в сиг­нал с помощью коман­ды ifft, которая выпол­няет обратное пре­обра­зова­ние, и стро­им визу­али­зацию. В моем коде я беру сра­зу реаль­ную часть сиг­нала для отоб­ражения, но если поменять фун­кцию real на imag в стро­ке с ifft, то мож­но будет получить фазовый спектр, о котором я говорил в начале статьи.

 

Смешиваем сигналы

Для при­мера давай сде­лаем сиг­нал из сме­си трех синусо­ид на час­тотах 5, 10 и 15 Гц. Для это­го дос­таточ­но все эти три синусо­иды прос­то сло­жить.

% Частота дискретизации в герцах
fs = 1000;
% Продолжительность сигнала в секундах
T = 1;
% Вектор времени
t = 0:1/fs:T-1/fs;
% Частоты
f1 = 5;
f2 = 10;
f3 = 15;
% Синусоиды
signal1 = sin(2 * pi * f1 * t);
signal2 = sin(2 * pi * f2 * t);
signal3 = sin(2 * pi * f3 * t);
% Складываем синусоиды (шок)
signal = signal1 + signal2 + signal3;
plot(t, signal);
xlabel('Время (с)');
ylabel('Амплитуда');
title('Синусоида');
grid on;

Все перемен­ные мож­но по отдель­нос­ти изу­чить в окне Workspace. Нетяже­ло заметить, что t — это мас­сив из 1000 эле­мен­тов, в котором хра­нят­ся вре­мена отсче­тов.

0 0.0010 0.0020 0.0030 0.0040 0.0050 0.0060 ...

Сам же сиг­нал (signal1) — это тоже мас­сив. Для каж­дого вре­мени Octave авто­мати­чес­ки пос­читал синус и соз­дал новый мас­сив. Каж­дому i-му эле­мен­ту мас­сива с сиг­налом соот­ветс­тву­ет i-й эле­мент мас­сива t, опре­деля­ющий вре­мя, в которое сиг­нал будет иметь такую ампли­туду.

0 0.031411 0.062791 0.094108 0.12533 0.15643 0.18738 ...

Ес­ли же закон­чить выпол­нение скрип­та и пос­мотреть резуль­таты сло­жения в перемен­ной signal, то уви­дим ожи­даемую сум­му трех синусо­идаль­ных сиг­налов.

0 0.18831 0.37551 0.56048 0.74215 0.91944 1.0913 ...

Те­перь мож­но запус­тить оставшу­юся часть кода и уви­деть отри­сован­ную фор­му сиг­нала.

Сигнал из трех синусоид (5, 10, 15 Гц)
Сиг­нал из трех синусо­ид (5, 10, 15 Гц)

Выг­лядит инте­рес­но. А теперь пос­мотрим на ампли­туд­ный спектр это­го сиг­нала. Что­бы это сде­лать, исполь­зуем сле­дующий код.

% Частота дискретизации в герцах
fs = 1000;
% Продолжительность в секундах
T = 1;
t = 0:1/fs:T-1/fs;
f1 = 5;
f2 = 10;
f3 = 15;
% Синусоиды
signal1 = sin(2 * pi * f1 * t);
signal2 = sin(2 * pi * f2 * t);
signal3 = sin(2 * pi * f3 * t);
% Сложение синусоид
signal = signal1 + signal2 + signal3;
% Выполнение преобразования Фурье
signal_fft = fft(signal);
P2 = abs(signal_fft / length(signal));
P1 = P2(1:length(signal)/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f_axis = fs*(0:(length(signal)/2))/length(signal);
% Визуализация спектра
bar(f_axis, P1, 'hist');
title('Амплитудный спектр сигнала');
xlabel('Частота (Гц)');
ylabel('|P1(f)|');
xlim([0, max(f_axis)]);

За­пус­каем и получа­ем три кра­сивых стол­бика как раз на час­тотах 5, 10 и 15 Гц. Прек­расно.

Спектр нашего сложного сигнала
Спектр нашего слож­ного сиг­нала
 

Картинка

Те­перь, ког­да мы зна­ем, как соз­давать свои слож­ные сиг­налы и как они рас­кла­дыва­ются обратно на сос­тавля­ющие их час­тоты, мож­но прис­тупать к кон­тро­лю над ми­ром тем, что выводит­ся на водопа­де. Задачу возь­мем нес­ложную — вывес­ти на водопад кар­тинку.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    1 Комментарий
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии