Ustatnia modyfikacja 28 grudnia 2025 przez Olek
Korzystając z multimetru stacjonarnego RIGOL DM3068, mogę przeprowadzać wyjątkowo precyzyjne pomiary temperatury, osiągając dokładność rzędu mikro stopni. Osobiście zastosowałem platynowe PT100, choć wiem, że multimetr umożliwia pomiar za pomocą wielu innych typów czujników rezystancyjnych. Czteroprzewodowe podłączenie pozwala mi na skuteczną kompensację rezystancji przewodów pomiarowych.
O ile pomiar i bieżąca prezentacja temperatury są możliwe bezpośrednio z multimetru, wiem, że automatyczna rejestracja danych wymaga jego integracji z systemami zewnętrznymi. Dlatego w tym celu wykorzystałem komputer z dedykowanym oprogramowaniem, co uważam za najefektywniejsze rozwiązanie.
Do stworzenia oprogramowania wybrałem język Python, który uznaję za optymalny, wydajny i uniwersalny. Aby umożliwić komunikację multimetru RIGOL z moim programem, musiałem wykonać następujące kroki na komputerze:
- Zainstalowałem oprogramowanie do komunikacji NI VISA1.
- Zainstalowałem bibliotekę PyVISA2 dla języka Python, która zapewnia obsługę tej komunikacji z poziomu kodu programu.
Poniżej zamieszczam kod programu w Pythonie. Zawiera on instrukcje dotyczące ewentualnych zmian i dopasowania do konkretnej instalacji.
from fileinput import filename
from pathlib import Path
import time
from xml.dom.expatbuilder import TEXT_NODE
import numpy as np
import pandas as pd
import logging
import pyvisa
import matplotlib.pyplot as plt
#from keithley2600 import Keithley2600, ResultTable
#import serial
import sys
import os
from datetime import datetime
import msvcrt
from matplotlib.ticker import EngFormatter
import re
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
class StreamToLogger(object):
"""
Fake file-like stream object that redirects writes to a logger instance.
"""
def __init__(self, logger, level):
self.logger = logger
self.level = level
self.linebuf = ''
def write(self, buf):
for line in buf.rstrip().splitlines():
self.logger.log(self.level, line.rstrip())
def flush(self):
pass
dir = os.path.dirname(os.path.abspath(__file__))
ln = dir + '\\' + Path(__file__).stem + '.log'
lf = '%(asctime)s:%(name)s:%(levelname)s: %(message)s'
logging.basicConfig(level=logging.INFO, format=lf, filename=ln);
consola = logging.StreamHandler()
consola.setFormatter(logging.Formatter(lf))
logging.getLogger('').addHandler(consola)
sys.stderr = StreamToLogger(logging.getLogger(''),logging.ERROR)
formatter_eng = EngFormatter(sep="", places=1)
logging.info("Start")
rig = None
def InitDevice():
global rig
try:
rm = pyvisa.ResourceManager()
for rr in rm.list_resources():
print(rr)
# do odczytu temperatury PT100 tylko DM3068. ..58 nie działa :READ?
#rig = rm.open_resource('TCPIP0::192.168.0.214::inst0::INSTR') #
rig = rm.open_resource('USB0::0x1AB1::0x0C94::DM3O201300270::INSTR')
logging.info("Połączyłem się z RIGOLEM ")
#print("Ustawiono RIGOL na ", rig.query("*IDN?"))
except:
raise Exception("Nie mogłem połączyć się z RIGOLEM")
def odczyt_temp_rig():
global rig
ts = rig.query(":READ?") # spacja przed :READ błąd w firmware
#print('>>>>>',ts)
ts=re.sub("#\w*","",ts) # dla cmd Agilent jest przedrostek #xxxxx który trzeba usunąć.
#print(ts)
t = float(ts)
return(t)
fig = None
def Graf():
global fig
global ax1
global df
if fig == None:
fig, ax = plt.subplots(figsize=(10, 8))
else:
plt.cla()
fig.texts.clear()
if not(df.empty):
if len(df.columns)>1:
l = df.columns
else:
l = df.columns[0]
plt.plot(df, label = l)
title = f'{prefix} {pomiar}'
plt.xlabel("Czas")
plt.ylabel("Temp")
plt.grid()
plt.title(title)
h, l = fig.gca().get_legend_handles_labels()
plt.legend(reversed(h), reversed(l), loc = 'upper left') #plt.legend()
fig.text(1, 0, "{}/{}".format(prefix,sufix), fontsize=8, ha='right', va='bottom', wrap=False)
fig.text(0, 0, datetime.now(), fontsize=8, ha='left', va='bottom', wrap=False)
dts = datetime.now().strftime("%H:%M:%S")
tt = round(t,2)
fig.text(0.5, 0, f'{dts} {tt}°C {licznik}', fontsize=44, ha='center', va='bottom', wrap=False)
dts = datetime.now().strftime("%H:%M:%S")
fig.canvas.manager.set_window_title(title)
plt.draw()
plt.pause(1)
pomiar_co = 1 #sec
prefix = "Rigol PT100"
pomiar = "przet C-SiC R62"
pomiar ='kala'
sufix = f"co {pomiar_co}s"
InitDevice()
t = odczyt_temp_rig()
d = {'Temp': pd.Series(t, index=[pd.Timestamp.now()])}
df = pd.DataFrame()
licznik = 0
logging.info("Zaczynam {}".format(pomiar))
while True:
plt.pause(pomiar_co)
t = odczyt_temp_rig()
d = pd.DataFrame({'Temp': pd.Series(t, index=[pd.Timestamp.now()])})
if not(df.empty):
#df = df.append(pd.DataFrame(d))
df = pd.concat([df,d])
else:
df = d.copy()
df.index.name = 'Czas'
Graf()
dts = datetime.now().strftime("%y%m%d-%H")
#n = f"{dir}\dane\{prefix}-{pomiar}-{dts}-{sufix}-{licznik}"
n = f"{dir}\dane\{prefix}-{pomiar}-{dts}-{sufix}"
fig.savefig(n+'.png')
# fig.savefig(n+'.pdf')
df.to_csv(n+'.csv', sep = ';', decimal = '.', index=True)
licznik +=1
logging.info("Koniec")
plt.show()
Program generuje różne dane (grafiki, tabele) i logi, które są uporządkowane w odpowiednich katalogach. Robię to, aby pomiary (dane) były odpowiednio identyfikowane i uporządkowane. Przy tego typu pomiarach bardzo szybko przybywa danych, a ich szybka identyfikacja upraszcza ich późniejsze wykorzystanie.
