c++ plot qwt real-time-data

c++ - trazando datos en tiempo real en(qwt) Oscillocope



matplotlib c++ (1)

Hehe hizo esto hace unos años para los estudiantes durante la clase. Espero que sepas cómo funcionan los osciloscopios, así que estos son solo los conceptos básicos:

  1. base de tiempo

    • fsmpl es la frecuencia de muestreo de la señal de entrada [Hz]

    Trate de usar lo más grande posible (44100,48000, ???) por lo que la frecuencia máxima detectada es entonces fsmpl/2 esto le da la parte superior de su eje de base de tiempo. El límite bajo viene dado por la longitud de tu buffer

  2. dibujar

    Crea una función que renderizará tu buffer de muestreo desde la dirección de inicio especificada (dentro del buffer) con:

    • Escala Y ... ajuste de amplitud
    • Desplazamiento en Y ... Posición del haz vertical
    • X-offset ... Time shift o posición horizontal

    Esto se puede hacer modificando la dirección de inicio o simplemente compensando X la curva

  3. Nivel

    Crear una función que emulará la funcionalidad de nivel . Así que busque el búfer desde la dirección de inicio y deténgalo si la amplitud cruza el nivel. Puede tener más modos, pero estos son conceptos básicos que debe implementar:

    • amplitud: ( < lvl ) -> ( > lvl )
    • amplitud: ( > lvl ) -> ( < lvl )

    Hay muchas otras posibilidades para nivel como error, borde relativo, ...

  4. Avance

    Puede poner todo esto junto, por ejemplo, así: tiene una variable de start address para que muestre los datos en un búfer de forma continua y en el level llamada del temporizador con la start address (y actualícelo). Luego llame al sorteo con una nueva start address y agregue el timebase period para start address (por supuesto en términos de sus muestras)

  5. multicanal

    Uso Line IN así que tengo entrada estéreo (A, B = izquierda, derecha) por lo tanto, puedo agregar algunas otras cosas como:

    • Fuente de nivel ( A,B , ninguno)
    • modo de renderizado (base de tiempo, Chebyshev (curva de Lissajous si está cerrado))
    • Chebyshev = x axis es A , y eje es B crea imágenes famosas de Chebyshev que son buenas para señales sinusoidales dependientes. Normalmente forma círculos, elipses, bucles distorsionados ...
  6. miscel cosas

    Puede agregar filtros para canales que emulan capacitancia o toma de tierra de entrada y mucho más

  7. GUI

    Necesitas muchas configuraciones. Prefiero perillas analógicas en lugar de botones / barras de desplazamiento / deslizadores como en un osciloscopio real.

    • (semi) Valores analógicos: Amplitud, TimeBase, Nivel, X-offset, Y-offset
    • valores discretos: modo de nivel (/,), fuente de nivel (A, B, -), cada canal (directo, tierra, apagado, capacidad activada)

Aquí hay algunas capturas de pantalla de mi osciloscopio:

Aquí está la captura de pantalla de mi generador:

Y finalmente después de agregar algo de FFT también Spectrum Analyzer

PD.

  • Empecé con DirectSound, pero es una mierda porque tiene devoluciones de llamada de buffer defectuosas / no funcionales
  • Uso WinAPI WaveIn / Out para todo el sonido en mis aplicaciones ahora. Después de algunos caprichos, es lo mejor para mis necesidades y tiene la mejor latencia (Directsound es demasiado lento más de 10 veces) pero para osciloscopio no tiene mérito (necesito baja latencia sobre todo para emuladores)

Por cierto. Tengo estas tres aplicaciones como clases de subventana de C ++ vinculables (Borland)

  • y utilizado por última vez con mi emulador ATMega168 para mi depuración del controlador BLDC sin sensores
  • aquí puedes probar mi Osciloscopio, generador y analizador de espectro. Si te confunden con la descarga, lee los comentarios a continuación. Esta contraseña de btw es: "oscill"

Espero que te sirva de ayuda si necesitas ayuda con algo solo coméntame

[Editar1] desencadenar

Dispare todos los canales a la vez, pero la condición del activador se comprueba generalmente desde uno. Ahora la implementación es simple, por ejemplo, permita que la condición de activación sea ​​el canal A (izquierda) que se eleva por encima del nivel, de modo que:

  1. Primero haz una reproducción continua sin ningún gatillo que hayas escrito, es así:

    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. Añadir disparador

    Para agregar la condición de activación, solo encuentra la muestra que se encuentra con ella y comienza a dibujar a partir de la misma para que la cambie a algo como esto

    // 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

    • el view_samples es el tamaño de datos visto / procesado (para una o más pantallas) debe ser pocas veces menor que el (countSamples>>1)
    • este código puede perder una pantalla en el área del borde para evitar que necesite implementar buffers cíclicos bot para principiantes, incluso esto está bien
    • solo codifica todas las condiciones de activación a través de alguna instrucción if o switch

Estoy tratando de crear un programa, usando Qt (c ++), que puede grabar audio desde mi micrófono usando QAudioinput y QIODevice. Ahora, quiero visualizar mi señal

Cualquier ayuda sería apreciada. Gracias

[Editar1] - copiado de tu comentario (por Spektre)

  • Tengo solo un Buffer para ambos canales
  • Uso Qt, el valor del canal está entrelazado en el búfer
  • así es como yo separé los valores

    for ( int i = 0, j = 0; i < countSamples ; ++j) { YVectorRight[j]=Samples[i++]; YVectorLeft[j] =Samples[i++]; }

  • después de trazar YvectorRight y YvectorLeft. No veo cómo activar solo un canal