Отображение данных в реальном времени на осциллографе (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 ответ

Он сделал это несколько лет назад для студентов во время урока. Я надеюсь, что вы знаете, как работают осциллографы, поэтому вот только основы:

  1. временная база

    • fsmpl частота дискретизации входного сигнала [Гц]

    Попробуйте использовать как можно больше (44100,48000, ???) поэтому максимальная обнаруженная частота fsmpl/2 это дает вам вершину оси времени. Нижний предел определяется длиной буфера

  2. рисовать

    Создайте функцию, которая будет визуализировать ваш буфер выборки с указанного начального адреса (внутри буфера) с помощью:

    • Y-шкала... настройка амплитуды
    • Смещение по оси Y... Вертикальное положение луча
    • Смещение по оси X... Сдвиг по времени или горизонтальное положение

    Это может быть сделано путем изменения начального адреса или просто смещением кривой по оси X

  3. уровень

    Создать функцию, которая будет эмулировать функциональность уровня. Так что поиск буфера от начального адреса и остановки, если амплитуда пересекает уровень У вас может быть больше режимов, но вы должны реализовать следующие основы:

    • амплитуда: ( < lvl ) -> ( > lvl )
    • амплитуда: ( > lvl ) -> ( < lvl )

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

  4. предварительный просмотр

    Вы можете собрать все это, например, так: у вас есть start address переменная, поэтому выборка данных в некоторый буфер непрерывно и при вызове таймера level с start address (и обновить его). Тогда назовите ничью с новым start address и добавить timebase period в start address (конечно с точки зрения ваших образцов)

  5. многоканальный

    Я использую Line IN, поэтому у меня есть стереовход (A,B = слева, справа), поэтому я могу добавить некоторые другие вещи, такие как:

    • Уровень источника (A,B,никто)
    • режим рендеринга (время, Чебышев (кривая Лиссажу, если он замкнут))
    • Чебышев = x ось A, y ось B это создает знаменитые чебышевские изображения, которые хороши для зависимых синусоидальных сигналов. Обычно образуют круги, эллипсы, искаженные петли...
  6. разное

    Вы можете добавить фильтры для каналов, эмулирующих емкость или заземление входа и многое другое

  7. графический интерфейс пользователя

    Вам нужно много настроек, я предпочитаю аналоговые ручки вместо кнопок / полос прокрутки / ползунков, как на реальном осциллографе

    • (полу) аналоговые значения: амплитуда, временная база, уровень, смещение по оси X, смещение по оси Y
    • дискретные значения: режим уровня (/,), источник уровня (A,B,-), каждый канал (прямое включение, заземление, выключение, пропускная способность включена)

Вот несколько скриншотов моего осциллографа:

осциллографосциллограф

Вот скриншот моего генератора:

генератор

И, наконец, после добавления некоторых БПФ также Spectrum Analyzer

Анализатор спектра

PS.

  • Я начал с DirectSound, но он много отстой из-за глючных / нефункциональных обратных вызовов буфера
  • Теперь я использую WinAPI WaveIn/Out для всех звуков в моих приложениях. После нескольких изысков это лучше всего подходит для моих нужд и имеет лучшую задержку (Directsound слишком медленный более 10 раз), но для осциллографа это не имеет смысла (мне нужна низкая задержка, в основном для эмуляторов)

Btw. У меня есть эти три приложения как связываемые классы подокна C++ (Borland)

  • и последний раз использовался с моим эмулятором ATMega168 для отладки моего драйвера BLDC без датчиков
  • здесь вы можете попробовать мой осциллограф, генератор и анализатор спектра. Если вас не устраивает загрузка, прочтите комментарии ниже к этому сообщению. Кстати, пароль: "oscill"

Надеюсь, это поможет, если вам нужна помощь, просто прокомментируйте меня

Триггер [Edit1]

Вы запускаете все каналы одновременно, но условие триггера проверяется обычно только с одного. Теперь реализация проста, например, пусть условием триггера будет A(левый) канал, поднимающийся над уровнем, так:

  1. Сначала сделайте непрерывное воспроизведение без написанного триггера, вот так:

    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
    
  2. Добавить триггер

    Чтобы добавить условие триггера, просто найдите образец, который соответствует ему, и начните рисовать из него, чтобы изменить его на что-то вроде этого.

    // 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
Другие вопросы по тегам