Мониторинг буферов в GNU Radio
У меня есть вопрос относительно буферизации между блоками в GNU Radio. Я знаю, что каждый блок в GNU (включая пользовательские блоки) имеет буферы для хранения элементов, которые будут отправлены или получены. В моем проекте есть определенная последовательность, которую я должен поддерживать для синхронизации событий между блоками. Я использую радио GNU на платформе Xilinx ZC706 FPGA с FMCOMMS5.
В радио-компаньоне GNU я создал специальный блок, который управляет выходным портом GPIO на плате. Кроме того, у меня есть независимый исходный блок, который подает информацию в блок FMCOMMS GNU. Последовательность, которую я пытаюсь сохранить, заключается в том, что в радио GNU я сначала отправляю данные в блок FMCOMMS, во-вторых, я хочу убедиться, что данные были получены блоком FMCOMMS (по сути, путем проверки буфера), затем, наконец, я хочу контролировать выход GPIO.
Судя по моим наблюдениям, буфер исходного блока, похоже, не отправляет элементы, пока не заполнится. Это вызовет серьезную проблему в моем проекте, поскольку это означает, что данные GPIO будут отправляться до или параллельно с отправкой элементов в другие блоки GNU. Это потому, что я устанавливаю значение GPIO через прямой доступ к его адресу в функции "работа" моего пользовательского блока.
Я пытался использовать pc_output_buffers_full() в функции "работа" моего пользовательского источника для мониторинга буфера, но я всегда получаю 0,00. Я не уверен, должен ли он использоваться в пользовательских блоках или "буфер" в этом случае отличается от того, где хранятся выходные элементы. Вот небольшой фрагмент кода, который показывает проблему:
char level_count = 0, level_val = 1;
vector<float> buff (1, 0.0000);
for(int i=0; i< noutput_items; i++)
{
if(level_count < 20 && i< noutput_items)
{
out[i] = gr_complex((float)level_val,0);
level_count++;
}
else if(i<noutput_items)
{
level_count = 0;
level_val ^=1;
out[i] = gr_complex((float)level_val,0);
}
buff = pc_output_buffers_full();
for (int n = 0; n < buff.size(); n++)
cout << fixed << setw(5) << setprecision(2) << setfill('0') << buff[n] << " ";
cout << "\n";
}
Есть ли способ контролировать буфер, чтобы я мог определить, когда была отправлена моя первая часть бит данных? Или есть способ убедиться, что каждый отдельный элемент вывода отправляется как непрерывный поток в следующий блок (ы)?
GNU Radio Companion версия: 3.7.8
ОС: образ Linaro 14.04, работающий на FPGA
1 ответ
Или есть способ убедиться, что каждый отдельный элемент вывода отправляется как непрерывный поток в следующий блок (ы)?
Нет, это не так, как работает GNU Radio (вообще!):
Некоторое время назад я написал статью, в которой объясняется, как GNU Radio работает с буферами, и что это на самом деле. Хотя архитектура буферов GNU Radio в памяти может представлять для вас меньший интерес, позвольте мне вкратце рассказать о ее динамике:
- Буферы, которые (
general_
)work
функции вызываются с поведением для всего, что практично, как линейно адресуемые кольцевые буферы. Вы получаете случайное количество образцов одновременно (ограниченное минимальными числами, кратными числами), и все, что вы не потребляете, будет передано вам в следующий разwork
называется. - Эти буферы, следовательно, отслеживают, сколько вы израсходовали, и, следовательно, сколько свободного места в буфере.
- Входной буфер, который видит блок, на самом деле является выходным буфером "восходящего" блока в потоковом графе.
- Вычисления GNU Radio контролируются противодавлением: любой блок
work
метод будет немедленно вызван в бесконечном цикле, если:- Там достаточно ввода для блока, чтобы сделать работу,
- Там достаточно места в буфере вывода для записи.
- Поэтому, как только один блок заканчивает свою
work
вызов, блок восходящего потока информируется, что есть новое свободное пространство вывода, таким образом, как правило, приводит к его запуску - Это приводит к высокой параллельности, так как даже смежные блоки могут работать одновременно без конфликта
- Эта архитектура поддерживает большие порции входных элементов, особенно для блоков, которые занимают относительно много времени на компьютере: пока блок все еще работает, его входной буфер уже заполняется порциями сэмплов; когда он закончится, скорее всего, он сразу же будет вызван снова со всем доступным входным буфером, уже заполненным новыми выборками.
- Эта архитектура является асинхронной: даже если два блока являются "параллельными" в вашем потоковом графе, нет определенного временного соотношения между количеством элементов, которые они производят.
Я даже не убежден, что переключение GPIO время от времени на основе вычисления скорости в этой полностью недетерминированной модели графика потоков данных является хорошей идеей для начала. Может быть, вы бы предпочли рассчитать "временные метки", при которых следует переключать GPIO, и посылать кортежи команд (timestamp, gpio state) некоторому объекту в вашей FPGA, который сохраняет абсолютное время? В масштабе распространения радиосигналов и высокоскоростной обработки сигналов синхронизация ЦП действительно неточная, и вы должны использовать тот факт, что у вас есть ПЛИС для фактической реализации детерминированной синхронизации, и использовать программное обеспечение, работающее на ЦП (например, GNU Radio), чтобы определить, когда это должно произойти.
Есть ли способ контролировать буфер, чтобы я мог определить, когда была отправлена моя первая часть бит данных?
Кроме этого, метод для асинхронного оповещения другого другого блока о том, что, да, вы обработали N выборок, будет либо иметь один блок, который просто наблюдает за выходами обоих блоков, которые вы хотите синхронизировать, и использует идентичное количество выборки из обоих входов, или реализовать что-то с помощью передачи сообщений. Опять же, я подозреваю, что это не решение вашей реальной проблемы.