Отображение данных в реальном времени на осциллографе (qwt)
Я пытаюсь создать программу, используя Qt (C++), которая может записывать звук с моего микрофона, используя QAudioinput и QIODevice. Теперь я хочу визуализировать мой сигнал
Любая помощь будет оценена. Спасибо
[Edit1] - скопировано из вашего комментария (Spektre)
- У меня есть только один буфер для обоих каналов
- Я использую Qt, значение канала чередуется в буфере
это как я разделяю ценности
for ( int i = 0, j = 0; i < countSamples ; ++j) { YVectorRight[j]=Samples[i++]; YVectorLeft[j] =Samples[i++]; }
после того, как я построю YvectorRight и YvectorLeft. Я не вижу, как запустить только один канал
1 ответ
Он сделал это несколько лет назад для студентов во время урока. Я надеюсь, что вы знаете, как работают осциллографы, поэтому вот только основы:
временная база
fsmpl
частота дискретизации входного сигнала [Гц]
Попробуйте использовать как можно больше
(44100,48000, ???)
поэтому максимальная обнаруженная частотаfsmpl/2
это дает вам вершину оси времени. Нижний предел определяется длиной буферарисовать
Создайте функцию, которая будет визуализировать ваш буфер выборки с указанного начального адреса (внутри буфера) с помощью:
- Y-шкала... настройка амплитуды
- Смещение по оси Y... Вертикальное положение луча
- Смещение по оси X... Сдвиг по времени или горизонтальное положение
Это может быть сделано путем изменения начального адреса или просто смещением кривой по оси X
уровень
Создать функцию, которая будет эмулировать функциональность уровня. Так что поиск буфера от начального адреса и остановки, если амплитуда пересекает уровень У вас может быть больше режимов, но вы должны реализовать следующие основы:
- амплитуда:
( < lvl ) -> ( > lvl )
- амплитуда:
( > lvl ) -> ( < lvl )
Есть много других возможностей для уровня, таких как глюк, относительный край,...
- амплитуда:
предварительный просмотр
Вы можете собрать все это, например, так: у вас есть
start address
переменная, поэтому выборка данных в некоторый буфер непрерывно и при вызове таймераlevel
сstart address
(и обновить его). Тогда назовите ничью с новымstart address
и добавитьtimebase period
вstart address
(конечно с точки зрения ваших образцов)многоканальный
Я использую Line IN, поэтому у меня есть стереовход (A,B = слева, справа), поэтому я могу добавить некоторые другие вещи, такие как:
- Уровень источника (
A,B
,никто) - режим рендеринга (время, Чебышев (кривая Лиссажу, если он замкнут))
- Чебышев =
x
осьA
,y
осьB
это создает знаменитые чебышевские изображения, которые хороши для зависимых синусоидальных сигналов. Обычно образуют круги, эллипсы, искаженные петли...
- Уровень источника (
разное
Вы можете добавить фильтры для каналов, эмулирующих емкость или заземление входа и многое другое
графический интерфейс пользователя
Вам нужно много настроек, я предпочитаю аналоговые ручки вместо кнопок / полос прокрутки / ползунков, как на реальном осциллографе
- (полу) аналоговые значения: амплитуда, временная база, уровень, смещение по оси X, смещение по оси Y
- дискретные значения: режим уровня (/,), источник уровня (A,B,-), каждый канал (прямое включение, заземление, выключение, пропускная способность включена)
Вот несколько скриншотов моего осциллографа:
Вот скриншот моего генератора:
И, наконец, после добавления некоторых БПФ также Spectrum Analyzer
PS.
- Я начал с DirectSound, но он много отстой из-за глючных / нефункциональных обратных вызовов буфера
- Теперь я использую WinAPI WaveIn/Out для всех звуков в моих приложениях. После нескольких изысков это лучше всего подходит для моих нужд и имеет лучшую задержку (Directsound слишком медленный более 10 раз), но для осциллографа это не имеет смысла (мне нужна низкая задержка, в основном для эмуляторов)
Btw. У меня есть эти три приложения как связываемые классы подокна C++ (Borland)
- и последний раз использовался с моим эмулятором ATMega168 для отладки моего драйвера BLDC без датчиков
- здесь вы можете попробовать мой осциллограф, генератор и анализатор спектра. Если вас не устраивает загрузка, прочтите комментарии ниже к этому сообщению. Кстати, пароль: "oscill"
Надеюсь, это поможет, если вам нужна помощь, просто прокомментируйте меня
Триггер [Edit1]
Вы запускаете все каналы одновременно, но условие триггера проверяется обычно только с одного. Теперь реализация проста, например, пусть условием триггера будет A(левый) канал, поднимающийся над уровнем, так:
Сначала сделайте непрерывное воспроизведение без написанного триггера, вот так:
for ( int i = 0, j = 0; i < countSamples ; ++j) { YVectorRight[j]=Samples[i++]; YVectorLeft[j] =Samples[i++]; } // here draw or FFT,draw buffers YVectorRight,YVectorLeft
Добавить триггер
Чтобы добавить условие триггера, просто найдите образец, который соответствует ему, и начните рисовать из него, чтобы изменить его на что-то вроде этого.
// static or global variables static int i0=0; // actual start for drawing static bool _copy_data=true; // flag that new samples need to be copied static int level=35; // trigger level value datatype should be the same as your samples... int i,j; for (;;) { // copy new samples to buffer if needed if (_copy_data) for (_copy_data=false,i=0,j=0;i<countSamples;++j) { YVectorRight[j]=Samples[i++]; YVectorLeft[j] =Samples[i++]; } // now search for new start for (i=i0+1;i<countSamples>>1;i++) if (YVectorLeft[i-1]<level) // lower then level before i if (YVectorLeft[i]>=level) // higher then level after i { i0=i; break; } if (i0>=(countSamples>>1)-view_samples) { i0=0; _copy_data=true; continue; } break; } // here draw or FFT,draw buffers YVectorRight,YVectorLeft from i0 position
-
view_samples
размер просматриваемых / обрабатываемых данных (для одного или нескольких экранов) должен быть в несколько раз меньше(countSamples>>1)
- этот код может потерять один экран в пограничной области, чтобы избежать необходимости использовать циклические буферы.
- просто закодируйте все условия триггера с помощью оператора if или switch
-