C#, SCPI și Agilent DSO-X 2002A

Acest articol este tradus de aici. Varianta inițială în limba română a a fost publicată pe site-ul yo3iti.ro. Articolul a fost început pe 19 ianuarie 2013 și lăsat în stadiul de ciornă. De câteva zile am fost ocupat cu un mic program în C# și asta a reprezentat o ocazie perfectă de a reveni la acest articol.

OK, treaba stă așa: osciloscopul meu, un superb Agilent DSO-X 2002A, este un instrument compatibil cu standardele SCPI. Pentru cei care au urmărit articolele de pe blog-ul meu în limba engleză — pe alauda.ro — motivul pentru care m-am chinuit (cu succes) să fac un driver de Mac pentru osciloscop a fost dorința de a încerca protocoalele SCPI în mod nativ pe OS X. Agilent nu are drivere pentru Mac, doar pentru Windows. Nu au oferit nici librării SCPI pentru Mac. Deși aplicațiile abundă pentru Windows, portarea lor pe Mac este — poate — doar un vis frumos. Și nerealist.

SCPI este abrevierea pentru Standard Commands for Programmable Instruments. Definește un set sintactic și comenzi ce pot fi utilizate pentru controlul instrumentelor de măsură și control. Practic, este un set de comenzi standardizate care pot fi utilizate de oricine dorește să automatizeze controlul instrumentelor de măsură, de pildă multimetre, osciloscoape, analizoare de spectru, generatoare de semnal etc. Este pur și simplu un standard software cu o sintaxă bazată pe comenzi text — ASCII — și, drept consecință, comenzile pot fi atașate oricărui limbaj de programare precum BASIC, C, C++, C# etc. Iată, de exemplu, rutina de setup pe care am scris-o în programul meu (limbaj C#):

/**
* Sets the scope parameters
* */
public void scopeSetup()
{
string strResults;
double fResult;

// set labels
myDSOX.myScope.Transport.Command.Invoke(":DISPlay:LABel ON");
myDSOX.myScope.SCPI.CHANnel.LABel.Command(1, "Meas.Ch.");
myDSOX.myScope.SCPI.CHANnel.LABel.Command(2, "Ref.Ch.");

// set scope trigger mode
myDSOX.myScope.SCPI.TRIGger.MODE.Command("EDGE");
myDSOX.myScope.SCPI.TRIGger.MODE.Query(out strResults);
Console.WriteLine("Trigger Mode: {0}", strResults);

// set EDGE trigger source; channel 1 --> yellow; channel 2 --> green
myDSOX.myScope.SCPI.TRIGger.EDGE.SOURce.Command("CHANnel2");
myDSOX.myScope.SCPI.TRIGger.EDGE.SOURce.Query(out strResults);
Console.WriteLine("Trigger edge source: {0}", strResults);

// set EDGE trigger level
myDSOX.myScope.SCPI.TRIGger.EDGE.LEVel.Command(1.5, "CHANnel2");
myDSOX.myScope.SCPI.TRIGger.EDGE.LEVel.Query("CHANnel2", out fResult);
Console.WriteLine("Trigger edge level: {0:F2}", fResult);

// set EDGE trigger slope type
myDSOX.myScope.SCPI.TRIGger.EDGE.SLOPe.Command("POSitive");
myDSOX.myScope.SCPI.TRIGger.EDGE.SLOPe.Query(out strResults);
Console.WriteLine("Trigger edge slope: {0}", strResults);

// set acquisition type
myDSOX.myScope.SCPI.ACQuire.TYPE.Command("AVERage");
myDSOX.myScope.SCPI.ACQuire.COUNt.Command(8);
myDSOX.myScope.SCPI.ACQuire.TYPE.Query(out strResults);
Console.WriteLine("Acquire mode: {0}", strResults);

// save scope configuration
string[] strScopeConfigurationArray;
myDSOX.myScope.SCPI.SYSTem.SETup.Query(out strScopeConfigurationArray);
}// end private static scopeSetup()

SCPI poate fi utilizat cu cele mai importante platforme integrate de măsurare și testare, de pildă LabWindows/CVI, LabView, MATLAB, Microsoft Visual Studio sau VEE de la Agilent. SCPI nu depinde de hardware. String-urile SCPI pot fi trimise prin orice interfață-instrument. Se comportă la fel de bine prin GPIB, RS-232, VXIBus sau rețele (LAN). Pentru informații suplimentare puteți consulta link-urile furnizate la sfârșitul acestui articol (vezi mai jos).

Driverul OS X este încă în faza de prototip, având încă de lucru la librăriile integrate. Este incredibil cât de mult timp poate să ia dezvoltarea unui driver, asta în principal fiindcă procesul de testare și debugging nu se supune acelorași reguli ca în cazul programării uzuale, a aplicațiilor-client. Ca atare, am luat hotărârea că este timpul să ofer o șansă limbajului C#, să programez pe o altă platformă (Windows). Am comis un fel de sacrilegiu fiindcă de aproape douăzeci de ani nu programez decât nativ în C, Objective-C și C++ pentru Mac… Ei bine, am început de la zero și mărturisesc că am reușit să mă auto–impresionez:

Prototipul meu de aplicație SCPI pe C# — pentru controlul osciloscopului. Toate bune și frumoase până aici.

Prototipul meu de aplicație SCPI pe C# — pentru controlul osciloscopului. Toate bune și frumoase până aici. Pentru a o vizualiza mai clar și mai mare, dați click pe imagine.

Având în vedere că este prima — PRIMA !! — mea încercare în C#, cu un volum total de 12 ore de lucru (în special serile, după ce-mi terminam sarcinile de la serviciu), cred că m-am descurcat destul de bine. Și, sincer, acum înțeleg de ce sunt atât de mulți programatori care cântă osanalele C#: este un limbaj de programare ideal pentru crearea rapidă a unor aplicații de complexitate simplă sau medie, într-un mediu vizual extrem de bogat (Visual Studio). Ce face aplicația: se conectează la osciloscop (pe baza unui string de identificare), realizează niște măsurători care sunt stocate într-o colecție volatilă și afișate pe un grafic. Interconectarea cu osciloscopul se poate observa în imaginea de mai jos:

Schema de conectare pentru testele SCPI. Din păcate, osciloscopul nu este prevăzut cu sarcină de 50Ω integrată pe intrări (seria 3000 are așa ceva). Ca atare, valorile măsurate nu sunt cele corecte. Dar ilustrează principiul de funcționare, ceea ce mă interesează mai mult decât precizia măsurătorilor în momentul de față. În centrul imaginii se poate observa inductanța de 10 μH, așezată în adaptor. Am utilizat o pereche de cabluri Pomona, de 12

Schema de conectare pentru testele SCPI. Din păcate, osciloscopul nu este prevăzut cu sarcină de 50Ω integrată pe intrări (seria 3000 are așa ceva). Ca atare, valorile măsurate nu sunt cele corecte. Dar ilustrează principiul de funcționare, ceea ce mă interesează mai mult decât precizia măsurătorilor în momentul de față. În centrul imaginii se poate observa inductanța de 10 μH, așezată în adaptor. Am utilizat o pereche de cabluri Pomona, de 12″ (30cm), recent achiziționate de la DigiKey. Excepționale cabluri, apropos. Pentru a o vizualiza mai clar și mai mare, dați click pe imagine.

Una dintre limitările osciloscoapelor Agilent din seria 2000 este lipsa opțiunii unui terminator de 50Ω în paralel pe intrare, selectabil software, din meniul de setare a intrărilor sondelor. Această funcționalitate este disponibilă de la seria de osciloscoape 3000 în sus. Ca atare, valorile măsurate sunt echivalente celor determinate pe un circuit deschis (cu impedanță infinită), deci mai mari decât în realitate. Din punct de vedere al prototipului nu este important fiindcă m-a interesat — deocamdată — doar testarea cu succes a interacțiunii software–aparat. Apropos: știe cineva de unde pot cumpăra terminatori coliniari de 50Ω ? Nu de tipul paralel. Dintr-ăia am.

Iată, de pildă, cum arată graficul tensiunii la bornele unui inductor de 10 μH în intervalul 1 MHz – 20 MHz:

Graficul valorilor tensiunii la bornele unei inductanțe de 10μH pentru un sweep în frecvență de la 1 MHz la 20 MHz, 1 Vpp. Modul de achiziție normal. A se observa valoarea la rezonanță pentru un circuit R-L serie echivalent. Linia graficului apare neuniformă din cauza achiziției la rezoluție ridicată.

Graficul valorilor tensiunii la bornele unei inductanțe de 10μH pentru un sweep în frecvență de la 1 MHz la 20 MHz, 1 Vpp. Modul de achiziție normal. A se observa valoarea la rezonanță pentru un circuit R-L serie echivalent. Linia graficului apare neuniformă din cauza achiziției la rezoluție ridicată. Pentru a o vizualiza mai clar și mai mare, dați click pe imagine.

Ca o chestiune secundară (dar importantă) clasa Chart din .NET este absolut superbă ! Mi-aș dori să existe ceva similar și la Apple, având în vedere că framework-urile nu includ o clasă pentru crearea rapidă a graficelor și flexibilitate/ simplitate la includerea obiectelor de tip grafic în aplicații. Deasemenea, nu există o clasă dedicată conexiunilor seriale sau USB (modelare la nivel obiect). Microsoft oferă nativ așa ceva în C#, ca atare aplicațiile care se bazează pe comunicare serială sunt extrem de ușor de realizat, obiectele de tip serial și USB fiind, de fapt, abstractizări de nivel înalt care maschează complexitatea nivelelor inferioare de comunicare cu hardware-ul. Nu spun că există vreun avantaj evident, deși faptul că ai posibilitatea de a modela un întreg nivel de abstractizare direct în C sau C++ este un atu nu de neglijat (pentru Apple, mă refer). Dar uneori ai nevoie de soluții rapide, simple și ieftine, pentru probleme de doi lei. Nu să stai zile întregi lovindu-te cu capul de pereți cătând soluții la probleme low–level…

Graficul valorilor tensiunii la bornele unei inductanțe de 10μH pentru un sweep în frecvență de la 1 MHz la 20 MHz, 1 Vpp. Graficul reprezintă media valorilor individuale, măsurate pe 8 cicluri consecutive. Din acest motivul, linia graficului apare mult mai uniformă decât în imaginea anterioară. A se observa valoarea la rezonanță pentru un circuit R-L serie echivalent.

Graficul valorilor tensiunii la bornele unei inductanțe de 10μH pentru un sweep în frecvență de la 1 MHz la 20 MHz, 1 Vpp. Graficul reprezintă media valorilor individuale, măsurate pe 8 cicluri consecutive. Din acest motivul, linia graficului apare mult mai uniformă decât în imaginea anterioară. A se observa valoarea la rezonanță pentru un circuit R-L serie echivalent. Pentru a o vizualiza mai clar și mai mare, dați click pe imagine.

Obiectivul principal al acestor experimente software este creșterea bazei de instrumentație de care dispun, cu un sistem software de control, flexibil și aflat sub controlul meu. De pildă, doresc să utilizez la maximum generatorul de semnal cu care este dotat osciloscopul. Prin SCPI se poate implementa o funcționalitate de sweep, se poate configura cu flexibilitate sporită funcția FFT etc. De pildă, pentru trei variabile frecvență: start (lowFrequency), stop (highFrequency) și un interval de incrementare (stepFrequency), rutina în C# ar fi:

int i = 0;
while (lowFrequency <= highFrequency)
{
Thread.Sleep(100);
// set start sweep frequency to low freq value
freqSweep.startSweep(lowFrequency);
// add each measured point to the collection
listDataSource.Add(new Record(i, lowFrequency, freqSweep.measureResults(channel)));
// end adding data
lowFrequency += stepFrequency;
// report progress if needed
//bw.ReportProgress(i);
++i;
}

unde freqSweep.measureResults(channel) este metoda care realizează măsurătoarea pe canalul osciloscopului channel; metoda este implementată în interiorul clasei freqSweep; măsurătoarea propriu-zisă și alocarea variabilelor se realizează în liniile evidențiate în codul de mai jos:

/**
* Realizează măsurătoarea pe canalul specificat
*/
public double measureResults(string channel)
{
double fResult;
myDSOX.myScope.SCPI.MEASure.SOURce.Command(channel, null);
myDSOX.myScope.SCPI.MEASure.VAMPlitude.Query(channel, out fResult);
Console.WriteLine("Amplitude : {0:F4}", fResult);
if (fResult > 1000)
return 0.0;
else
return fResult;
}// end public double measureResults

Bun. Atât pentru astăzi. Acest mic proiect oferă posibilități nelimitate de dezvoltare, dar, pe moment, rezultatele obținute m-au impresionat: am fost în stare să creez o aplicație perfect funcțională în mai puțin de două zile, în condițiile în care nu am avut anterior nici un fel de cunoștințe de C#. E drept, odată ce stăpânești un limbaj de programare orientat obiect, curba învățării altor limbaje similare este foarte abruptă, dar… totuși.

Limbajul C# m-a impresionat prin gradul de abstractizare și viteza cu care poți realiza o aplicație relativ complexă. E foarte posibil să îmi placă din ce în ce mai mult. Dar asta nu înseamnă că mă voi îndrăgosti de el. Nu. C-ul rămâne marea mea dragoste. 🙂

Lecturi suplimentare

  • SCPI pe Wikipedia; un foarte bun punct de pornire. O trecere în revistă a standard-ului SCPI, ceva istoric, rațiunea implementării SCPI, sintaxa comenzilor (subiecte de nivel înalt), argumente, abrevieri; nu prea în profunzime, dar suficient pentru început;
  • SCPI Consortium; parte a stie-ului web al IVI Foundation; SCPI Consortium a fost înghițit de IVI Foundation în 2002; s-au amalgamat în 2003; IVI Foundation este în prezent responsabilă de întreținerea specificațiilor SCPI;
  • National Instruments’ LabWindows/CVI;
  • LabView, MATLAB
  • MS Visual Studio
  • Agilent VEE
  • Open Source SCPI device library/ SCPI parser library — nu prea am înțeles la ce este utilă, poate vă prindeți voi; dar pare cool; un framework d-ăla adevărat, în C, de coșmar; he he 🙂 ; de explorat și — posibil — de exploatat 😀

Despre resursele de informații referitoare la librăriile software Agilent de funcții VISA (Virtual Instrument Software Architecture) și SCPI: cu începere de la versiunea 15.5 a suitei IO Libraries Suite, librăriile software Agilent sunt disponibile în variante pentru 32 și 64 de biți. Pute’i găsi informații referitoare la modul de utilizare a acestor librării pe sistemele de 64 biți căutând în fișierul help al suitei IO Libraries Suite 15.5 după termenul „64-bit”. Sunt dirponibile următoarele informații:

73s

Despre YO3ITI

Iubitor de pisici, muzică, foto. Măritat.