отображение данных в реальном времени на (qwt) осциллографе

Я пытаюсь создать программу, используя Qt (С++), которая может записывать звук с моего микрофона, используя QAudioinput и QIODevice. Теперь я хочу визуализировать свой сигнал

Любая помощь будет оценена по достоинству. Спасибо

[Edit1] — скопировано из вашего комментария (от Spektre)

  • У меня есть только один буфер для обоих каналов
  • Я использую Qt, значение канала чередуется в буфере
  • вот как я разделяю значения

    for ( int i = 0, j = 0; i < countSamples ; ++j) 
     {
     YVectorRight[j]=Samples[i++];
     YVectorLeft[j] =Samples[i++];
     }
    
  • после того, как я нарисую YvectorRight и YvectorLeft. Я не понимаю, как запустить только один канал


person The Man    schedule 09.02.2014    source источник
comment
+1 за необычный вопрос, связанный с HW. посмотри мой ответ. немного отредактируйте свой вопрос, добавьте то, что вы уже пробовали, и что вам нужно решить. любой флаг редактирования с видимым текстом (я делаю это [edit1], [edit2]), а также добавить комментарий, что вы что-то редактируете, чтобы любой в списке комментариев получил уведомление   -  person Spektre    schedule 09.02.2014
comment
Я не использую QT/QWT, но вы можете использовать функцию таймера или потока (таймер - это компонент, добавляющий его к заданному интервалу окна, и в нем событие ontimer выполняет рисование) для потока просто используйте CreateThread... (в Windows и в Linux есть я думаю так же)   -  person Spektre    schedule 13.02.2014


Ответы (1)


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

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

    • fsmpl is input signal sampling frequency [Hz]

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

  2. рисовать

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

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

    Это можно сделать, изменив начальный адрес или просто сместив кривую по оси X.

  3. Уровень

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

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

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

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

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

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

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

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

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

  7. Графический интерфейс

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

    • (semi)Analog values: Amplitude,TimeBase,Level,X-offset,Y-offset
    • дискретные значения: режим уровня (/,), источник уровня (A, B,-), каждый канал (прямое включение, заземление, выключение, емкость вкл.)

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

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

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

генератор

И, наконец, после добавления БПФ также анализатора спектра.

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

ПС.

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

Кстати. У меня есть эти три приложения в виде подключаемых классов подокна С++ (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
    
    • the view_samples is the viewed/processed size of data (for one or more screens) it should be few times less then the (countSamples>>1)
    • этот код может потерять один экран в пограничной области, чтобы избежать необходимости реализации циклических буферов (колец), но для начала даже это нормально
    • просто закодируйте все условия триггера с помощью оператора if или switch
person Spektre    schedule 09.02.2014
comment
вы можете опубликовать свой код в своем вопросе, чтобы другие также могли видеть и помогать (только не забудьте выбрать его и нажать кнопку формата кода, чтобы он отображался в этой серой области с подсветкой синтаксиса и форматированием строки кода), если вы добавьте код под маркер, добавьте n * 4 пробела в каждую строку, пока она не станет серой. Для дополнительных вопросов добавьте их также к своему вопросу (пронумеруйте их, например, Q1, Q2,...), и мы постараемся ответить на них (я уверен, что кто-то еще добавит к этому). Кстати, я кодирую в основном на bds2006 C++ win32, поэтому на вопросы, связанные с Qwt или другой платформой, все равно придется отвечать кому-то другому. - person Spektre; 09.02.2014
comment
PS. загрузите это: ulozto.sk/xFASrEPv/soundio-exe-rar пароль сгенерируйте его использует предпочтительный звуковой ввод и вывод из настроек звука Windows - person Spektre; 09.02.2014
comment
Привет, Спектре, как ты генерируешь треугольную и прямоугольную форму сигнала? - person The Man; 18.05.2014
comment
@user2932518 user2932518 легко с циклом for или предварительно вычисленной таблицей ... с треугольной формой цикла for (i=0;i‹N;i++) для первой половины out[i] = Amplitude*i/(N/2-1) и для второго out[i] = Amplitude*(Ni-1)/(N/2-1); прямоугольная волна также относительно проста... if (i›ratio) out[i] = 0 else out[i] = Amplitude; - person Spektre; 19.05.2014
comment
У меня есть только один буфер для обоих каналов, я использую Qt, значение канала чередуется в буфере. вот как я разделяю значение for ( int i = 0, j = 0; i ‹ countSamples ; ++j) { YVectorRight[j] =Samples[i++]; YVectorLeft[j] = Samples[i++]; } после того, как я построю YvectorRight и YvectorLeft. Я не понимаю, как запустить только один канал - person The Man; 19.08.2014
comment
@TheMan отредактировал ответ, ищите Edit1. Кстати, ваши комментарии перескакивают с вопроса на вопрос, если бы я не видел их обоих, я бы не знал, о чем вы говорите. Да, это больше подходит здесь, чем к вашему вопросу об анализаторе спектра, но исходный комментарий есть :) будьте осторожны с этим в будущем, потому что другие пользователи не будут знать, о чем вы пишете, и поэтому они не смогут помочь. Также попробуйте добавить больше информации в свои вопросы не только о том, что вы хотите, но и о том, что вы уже сделали + какой-нибудь пример кода, чтобы другие могли действительно помочь (именно поэтому ваш триггерный вопрос закрывается). - person Spektre; 20.08.2014