在(qwt)示波器上绘制实时数据

时间:2014-02-09 07:11:12

标签: c++ plot qwt real-time-data

我正在尝试使用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 个答案:

答案 0 :(得分:1)

几年前,嘿嘿为学生们在课堂上做了这件事。我希望你知道示波器是如何工作的,所以这里只是基础知识:

  1. <强>时基

    • fsmpl是输入信号采样频率[Hz]

    尝试使用尽可能大的(44100,48000, ???),以便检测到的最大频率为fsmpl/2,这会为您提供时基轴的顶部。下限由缓冲区长度

  2. 给出
  3. <强>绘制

    使用以下命令创建将从指定的起始地址(内部缓冲区)渲染采样缓冲区的函数:

    • Y-scale ...幅度设定
    • Y偏移...垂直光束位置
    • X偏移...时移或水平位置

    这可以通过修改起始地址或仅通过X偏移曲线

  4. 来完成
  5. <强>等级

    创建将模拟级别功能的功能。因此从起始地址搜索缓冲区,如果幅度跨越等级则停止。您可以拥有更多模式,但这些是您应该实现的基础:

    • 幅度:( < lvl ) -> ( > lvl )
    • 幅度:( > lvl ) -> ( < lvl )

    还有许多其他可能性,如毛刺,相对边缘,......

  6. 预览

    你可以将所有这些放在一起,例如:你有start address变量,所以连续地在一些缓冲区中和在level的定时器调用start address上采样数据(并更新它)。然后使用新的start address调用draw并将timebase period添加到start address(当然是根据您的样本)

  7. <强>多信道

    我使用 Line IN,所以我有立体声输入(A,B =左,右)因此我可以添加一些其他的东西,如:

    • 关卡来源(A,B,无)
    • 渲染模式(时基,切比雪夫(Lissajous曲线,如果关闭))
    • Chebyshev = x轴是Ay轴是B这创造了着名的Chebyshev图像,这些图像对于依赖的正弦信号是有益的。通常形成圆形,椭圆形,扭曲的循环......
  8. 错误投放

    您可以为模拟电容或输入接地的通道添加滤波器等等

  9. <强> GUI

    你需要很多设置我更喜欢模拟旋钮而不是按钮/滚动条/滑块,就像真正的示波器一样

    • (半)模拟值:幅度,时基,电平,X偏移,Y偏移
    • 离散值:电平模式(/,),电平源(A,B, - ),每个通道(直接接通,接地,断开,容量接通)
  10. 以下是我的示波器的一些截图:

    oscilloscope oscilloscope

    以下是我的生成器的屏幕截图:

    generator

    最后在添加一些FFT之后还有频谱分析仪

    Spectrum analyser

    <强> PS。

    • 我从 DirectSound 开始,但由于有缺陷/无功能的缓冲区回调,它很糟糕
    • 我现在使用 WinAPI WaveIn / Out 获取我的应用中的所有声音。经过几次诡计之后,对我的需求是最好的,并且具有最佳延迟(Directsound太慢超过10次)但是对于示波器它没有任何优点(我需要低延迟,主要是模拟器)

    顺便说一下。我将这三个应用程序作为可链接的C ++子窗口类(Borland)

    • 最后用于我的ATMega168仿真器,用于无传感器BLDC驱动程序调试
    • 在这里你可以尝试我的Oscilloscope,generator and Spectrum analyser如果你对下载感到困惑,请阅读下面的评论 btw密码是:“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语句编码所有触发条件