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.

  1. https://www.ni.com/en/support/downloads/drivers/download.ni-visa.html ↩︎
  2. https://pyvisa.readthedocs.io/en/latest/ ↩︎

Dodaj komentarz