A continuación se presentan los conceptos básicos necesarios para poder realizar control remoto de un instrumento y adquisición programada.
Un instrumento de medición permite convertir una magnitud física que se desea medir en otra magnitud que pueda ser registrada o percibida por nuestros sentidos. Los instrumentos fueron variando a lo largo de la historia en la medida que avanza la tecnología.
- Un ejemplo antiguo y analógico puede ser una balanza: transforma una fuerza (el peso) en un desplazamiento espacial que puede ser medido mediante una regla.
- Con el advenimiento de la electrónica, se pasó a un esquema en el que la mayoría de los
instrumentos transforman la magnitud medida a una señal eléctrica (una corriente o tensión), que luego es medida y registrada por otro instrumento (multímetro, osciloscopio, etc) y
presentada en un pantalla.
- magnitud a medir → señal de corriente / tensión → pantalla o registro en papel
- En la actualidad, con la tecnología digital, cada vez es más habitual que los instrumentos
entreguen directamente en forma digital (por un canal de comunicación de datos)
el resultado de una medición.
- magnitud a medir → señal de corriente / tensión → pantalla
- magnitud a medir → señal de corriente / tensión → canal digital de datos → computadora
- magnitud a medir → canal digital de datos → computadora
Por ello, hoy en día se necesita conocer cómo es el proceso de digitalización y el de transmisión de datos para poder realizar una adquisición por computadora. La incorporación de la computadora al laboratorio permite entonces automatizar (programación mediante) el registro de datos o la realización de (algunas partes de) un experimento.
Instrumentación
El primer paso es conocer los instrumentos que se van a utilizar. Imaginemos que contamos con un osciloscopio y un generador de funciones. Debemos ir a buscar la información relevante de estos equipos.
- Osciloscopio:
Tektronix TBS1052b-edu
- Página web del producto: https://www.tek.com/oscilloscope/tbs1052b-edu
- Página de documentos del producto
- Generador de funciones:
Tektronix AFG1022
- Página web del producto: https://www.tek.com/arbitrary-function-generator/afg1000-arbitrary-function-generator
- Documentos del producto:
En los manuales están los detalles técnicos de cada instrumento. Esto incluye detalles de la conversión Analógico/Digital de los equipos. Por ejemplo, en el manual del osciloscopio (pág 115):
Nos especifica:
- Datos de la digitalización
- Resolución “vertical” (de Voltaje):
8 bits
→ $2^8 = 256$ pasos de digitalización - Sample Rate:
1 GS/s
, 1 Giga Sample son 1000 millones de datos por segundo (maximo) - Record Length:
2500
puntos, 2500 datos de 8 bits pueden ser registrados en el tiempo.
- Resolución “vertical” (de Voltaje):
- Datos de electrónica relevantes:
- “Bandwidth” / Ancho de banda:
50 MHz
, frecuencia de corte a partir de la cual se pierden armónicos. Es una limitación eléctrica (la limitación de digitalización es el SampleRate/2 , mucho mayor al BandWidth que reportan acá). - Impedancia de entrada:
1 MΩ
- “Bandwidth” / Ancho de banda:
En el manual del generador de funciones (pag 11)
(pag 22)
Nos especifica:
- Datos de la conversión A/D
- “Waveform” / Forma de la Onda: hasta
8192
puntos (para definir la forma de onda) de14 bits
de resolución ($2^{14} = 16384$ pasos de digitalización) - Sample Rate:
125 MS/s
, Hasta 125 Mega Samples por segundo son 125 millones de puntos por segundo (máximo) - Amplitud: los
14 bits
se distribuyen en un rango desde2 mVpp
(mili Volts de pico a pico) hasta20 Vpp
para una carga “alta” (mucho mayor a50 Ω
).
- “Waveform” / Forma de la Onda: hasta
- Datos de electrónica relevantes:
- Impedancia de salida:
50 Ω
- Impedancia de salida:
Luego, debemos conocer cuales son los canales de comunicación con ese instrumental. Existe una API estándar en la industria llamada VISA (Virtual instrument software architecture), que permite unificar en una sola interfaz las diferentes tecnologías de comunicación.
Cada sistema operativo y software o lenguaje de programación tiene alguna
implementación propia de VISA (a veces debe ser instalada). En el caso de
python
hay que instalar pyvisa
.
La mayoría de los instrumentos soporta comandos por SCPI, que es una sintaxis estándar para escribir instrucciones para instrumentos. Las instrucciones consisten en palabras y valores escritos en texto plano, cada una asociada a los diferentes valores que puede medir un instrumento o parámetros de configuración necesarios para su operación.
Por ejemplo, para adquirir el vector de números que representan el voltaje medido por el canal 1 de un osciloscopio se usan estos dos comandos:
Seleccionar el canal 1:
'DATA:SOURCE CH1'
leer los datos
CURV?
Para establecer la frecuencia de la función de onda de un generador de funciones
en 50 Hz
usamos este comando:
FREQ 50
Así, en nuestro lenguaje de programación, deberemos crear textos con estas instrucciones y enviarlas a cada instrumento mediante la API de VISA.
Control remoto en Python
Hay varios ejemplos de adquisición remota y control ya armados. Algunos están en repositorios compartidos, como los del profesor Hernan Grecco en GitHub.
Veamos dos ejemplos…
Osciloscopio
Importaremos la librería visa
y usaremos el Resource Manager de la librería que nos permite
conectarnos al equipo informándole la dirección. Luego, los métodos query()
y write()
nos permitirán enviar las instrucciones al equipo y traer la respuesta (en el caso de query()
).
Vamos a usar las siguientes instrucciones extraídas del manual.
Lo que está entre corchetes []
o en minúscula es opcional ponerlo.
Referencia | Comando (ej) | Función |
---|---|---|
DATa:SOUrce <wfm> |
DATA:SOU CH1 |
Selecciona el canal del osciloscopio |
CURV? |
CURV? |
Pide los datos medidos del canal actual |
HORizontal:MAIn:SCAle <escala> |
HOR:MAIN:SCA 5E-3 |
Fija la escala temporal del osciloscopio (en segundos) |
WFMPRE:XZE?;XIN?;YZE?;YMU?;YOFF?; |
WFMPRE:XZE?;XIN?;YZE?;YMU?;YOFF?; |
Adquiere los datos de la escala de la pantalla del osciloscopio |
El último comando son en realidad varios anidados. Permiten obtener la información necesaria para transformar los
2500 números enteros de 8 bits que adquirimos con CURV?
en Volts con el espaciado en segundos que corresponda.
from matplotlib import pyplot as plt
from numpy import *
import numpy as np
import pyvisa as visa
print(__doc__)
# Cargamos el Resource Manager. El manejador de recursos VISA
rm = visa.ResourceManager()
# Informamos la dirección de acceso al osciloscopio (en este caso, por USB)
osci = rm.open_resource('USB0::0x0699::0x0363::C065089::INSTR')
# Con el método 'query()' podemos enviar instrucciones QUE TIENEN RESPUESTA
# Por ejemplo, la instrucción que nos informa el nombre del instrumento
# al que nos conectamos
respuesta = osci.query('*IDN?')
# La instruccion '*IDN?' nos permite conocer a que instrumento nos conectamos
print(respuesta)
# Le pido algunos parametros de la pantalla, para poder escalear adecuadamente
xze, xin, yze, ymu, yoff = osci.query_ascii_values('WFMPRE:XZE?;XIN?;YZE?;YMU?;YOFF?;', separator=';')
#############################################################################
# Nota: Si falla la línea anterior, corroborá que el canal del osciloscopio #
# esté encendido. A veces es necesario que ambos estén encendidos para que #
# funciones correctamente #
#############################################################################
# Con el método 'write' enviamos instrucciones QUE NO TIENEN RESPUESTA
# Modo de transmisión: Binario
osci.write('DAT:ENC RPB')
osci.write('DAT:WID 1')
# Adquiere los datos del canal 1 y los devuelve en un array de numpy
data = osci.query_binary_values('CURV?', datatype='B', container=np.array)
voltaje =(data-yoff)*ymu+yze;
tiempo = xze + np.arange(len(data)) * xin
plt.plot(tiempo, voltaje )
plt.xlabel('Tiempo [s]')
plt.ylabel('Voltaje [V]')
Generador de funciones
Vamos a usar las siguientes instrucciones extraídas del manual.
Lo que está entre corchetes []
o en minúscula es opcional ponerlo.
Referencia | Comando (ej) | Función |
---|---|---|
[SOURce[1|2]]:VOLTage <amplitude> |
VOLT 0.5 |
Cambiar la amplitud pico a pico (en Volts) |
[SOURce[1|2]]:FREQuency <frequency> |
FREQ 2000 |
Cambiar la frecuencia (en Hz) |
[SOURce[1|2]]:VOLTage[:LEVel][:IMMediate]:OFFSet <voltage> |
VOLT:OFFS 0.3 |
Cambiar la tensión del centro de la funcion de onda. |
Vamos a realizar distintos tipos de barridos sobre parámetros del generador de funciones. Cuando no especificamos
el canal, se asumo que es el SOURCE1
.
import time
from numpy import *
import numpy as np
import pyvisa as visa
# Cargamos el Resource Manager. El manejador de recursos VISA
rm = visa.ResourceManager()
# Informamos la dirección de acceso al osciloscopio (en este caso, por USB)
fungen = rm.open_resource('USB0::0x0699::0x0346::C033250::INSTR')
# Con el método 'query()' podemos enviar instrucciones QUE TIENEN RESPUESTA
# Por ejemplo, la instrucción que nos informa el nombre del instrumento
# al que nos conectamos
print(fungen.query('*IDN?'))
# Para enviar instrucciones que no entregan una respuesta se usa
# el método 'write()'
# Vamos a generar valores de frecuencias con una separación logarítmica
# vamos de 10^1 a 10^3 , con 20 pasos
for freq in logspace(1, 3, 20):
fungen.write('FREQ {:f}'.format(freq) )
print('Comando enviado: ' + 'FREQ {:f}'.format(freq) )
time.sleep(0.1) # tiempo de espera de 0.1 segundos
# Rampa lineal de amplitudes
# Vamos a tener 10 pasos que van de 0 V a 1 V
for amplitude in np.linspace(0, 1, 10):
fungen.write('VOLT {:f}'.format(amplitude) )
print('Comando enviado: ' + 'VOLT {:f}'.format(amplitude) )
time.sleep(0.1) # tiempo de espera de 0.1 segundos
# Rampa lineal de offset
# Vamos a tener 10 pasos que van de 0 V a 1 V
for offset in np.linspace(0, 1, 10):
fungen.write('VOLT:OFFS {:f}'.format(offset) )
print('Comando enviado: ' + 'VOLT:OFFS {:f}'.format(offset) )
time.sleep(0.1) # tiempo de espera de 0.1 segundos
# Cuando dejamos de usar el generador de funciones, lo cerramos
fungen.close()