Schlagwort-Archive: Matlab

Kleines Bastelprojekt zur Sommerzeit

Solarmodul

Als Mini – Bastelprojekt zur Sommerzeit bezeichne ich folgende Bastelei. Ein kleines monokristallines Solarmodul mit der Bezeichnung „SM 6“ von einem bekannten, großen Elektronikdistributor der mit „C“ beginnt und mit „d“ endet, spielt in dem Projekt die Hauptrolle. Das Modul hat eine Nennleistung von 6Wp bei einem maximalen Strom von 320mA. Die Nennspannung liegt bei 17,3V. Die Leerlaufspannung beträgt 20,8V. Die Siliziumzellen sind in einer EVA (Ethylen-Viny-Acetat) Kunststoffplatte eingebettet und UV-und feuchtigkeitsbeständig. Das ganze Modul ist ca. 25cm x 25 cm groß. Es ist also ideal geeignet, um die Energie zum Betreiben von USB-Geräten bereitzustellen. Hierbei habe ich zum Beispiel an WIFI-IP-Cams gedacht. Auch das Laden von Smartphones ode Tablets sollte damit möglich sein.

Um das nun auch durchführen zu können, muss aus der Nennspannung der Photovoltaikzelle die Betriebsspannung des USB-Standards (5V) erzeugt werden. Das könnte man jetzt ganz einfach mit einem 7805er Regler machen und die Differenz dabei in Wärme umwandeln. Doch das ist die, so ziemlich ineffizienteste Möglichkeit, die Energie des Panels in ein Handy zu bekommen.
Zum einen ist der Innenwiderstand des Panels von der Lichtintensität abhängig, was einen großen Einfluss auf den Wirkungsgrad bei nicht angepassten Lastwiderständen hat. Zum anderen ist ein Längsregler ein Energievernichter, da die Differenz zwischen Eingangsspannung und geregelter Ausgangsspannung bei Stromfluß in Verlustleistung, also Wärme umgewandelt wird. Hier ist man mit einem Schaltwandler (Buck-Converter) besser bedient.
 
In einem einfachen Laboraufbau kann das Verhalten des Panels untersucht werden. Dazu wird die Leerlaufspannung des Panels bei unterschiedlicher Beleuchtungsstärke gemessen. Anschliessend wird das Panel mit unterschiedlichen Widerstandswerten belastet und der Strom durch die Last, sowie die Spannung am Panel gemessen. Die Messwerte werden aufgezeichnet und der Ri (Innenwiderstand der Quelle) berechnet. Der nachfolgende Stromlaufplan zeigt den Messaufbau:
Messaufbau – Schaltung
Als Amperemeter dient ein Agilent- und als Voltmeter ein Keithley 2701 Tischmultimeter. Diese Messgeräte können beide über SCPI-Befehle gesteuert werden. Als Schnittstelle ist  jeweils ein LAN-Port vorhanden. Das macht es einfach, über einen PC und ein geeignetes Script, einen automatisierten Messablauf zu realisieren. Und da Matlab eine sehr bequeme Möglichkeit bietet, zu scripten, wird es auch gleich verwendet. Um in einem Labor messen zu können und in etwa die selben Umgebungsbedingungen zu haben, wird anstelle der Sonne eine Tischlampe mit Halogenglühbirne verwendet. Die Helligkeit der Lampe wird einfach durch die Versorgung mit einem Labornetzgerät von 0-13V eingestellt. Natürlich kann auch das Labornetzgerät per Matlab gesteuert werden.
Messaufbau mit Lampe als „Sonne“

Die Lampe ist in einem Abstand von 25cm mittig über dem Panel platziert. Um ein Gefühl zu bekommen, welche Beleuchtungsstärke mit der Lampe erreicht wird, wird mit einem Luxmeter eine Referenzmessung gemacht. Das heißt, die Lampe fährt die Leistungsrampe von 0-13V durch und das Luxmeter misst die Beleuchtungsstärke im Abstand von 25cm unter der Lampe. Das Ganze wird in 0.5V Schritten aufgelöst. Daraus ergibt sich eine Kurve, die so aussieht:

Spannung an der Lampe ergibt Beleuchtungsstärke

Jetzt kann die Messung beginnen. Als Lastwiderstand werden manuell Widerstände an das Panel geschaltet und Strom und Spannung bei jeder Helligkeitsstufe gemessen. Es sind elf Lastwiderstandswerte die von 4.7 Ohm bis 220 Ohm reichen nacheinander angeschlossen. Eine Leerlaufmessung wird dann natürlich ohne Lastwiderstand gemacht. Folgender Graph zeigt den errechneten Innenwiderstand bei zwei Lasten des Panels über den Helligkeitsverlauf der Lampe in Lux und im weiteren Graph über die Spannung an der Lampe(für die bessere Skalierung). Den Innenwiderstand einer Quelle errechnet man aus der Leerlaufspannung der Quelle abzüglich der Spannung unter Last, dividiert durch den Strom. Mit der Differenz der Leerlauf und Lastspannung erhält man also den Spannungsabfall am Innenwiderstand. Da im Lastfall auch der Strom bekannt ist, braucht man nur mehr das Ohm´sche Gesetz anzuwenden, um den Widerstandswert zu erhalten…

Innenwiderstand vs. Beleuchtungsstärke
Innenwiderstand vs. Spannung an der Lampe

Da jetzt einige Klarheiten über das Verhalten der PV-Zelle beseitigt wurden, kann ich noch kurz über den Aufbau des Spannungswandlers berichten. Wie schon zuvor angekündigt, ist ein Schaltwandler der effizientere Weg, die Energie an den Verbraucher anzupassen. Hier kommt ein LM2596S zum Einsatz. Der LM 2596 ist ein „Simple Switcher Power Converter, der mit 150kHz schaltet und ein Last mit 3A versorgen kann.) Hier eine Übersicht der Funktionen:

  • 3.3-V, 5-V, 12-V, and Adjustable Output Versions
  • Adjustable Version Output Voltage Range: 1.2-V to 37-V ± 4% Maximum
    Over Line and Load Conditions
  • Available in TO-220 and TO-263 Packages
  • 3-A Output Load Current
  • Input Voltage Range Up to 40 V
  • Excellent Line and Load Regulation Specifications
  • 150-kHz Fixed-Frequency Internal Oscillator
  • TTL Shutdown Capability
  • Low Power Standby Mode, IQ, Typically 80μA
  • Uses Readily Available Standard Inductors
  • Thermal Shutdown and Current-Limit Protection

(Quelle: Datenblatt des Herstellers TEXAS Instrument)

Mit diesem Schaltwandler und noch ein paar wenigen anderen Komponenten lässt sich schnell eine Schaltung zusammenzimmern und mit dem Layouttool „Eagle“ in eine Platine verwandeln. Diese Schaltung ist aber so einfach aufgebaut, dass sie lediglich mit den Vorzügen des LM2596 möglichst effizent arbeitet, aber kein Powertracking durchführt. Das heisst, die Last, die die Schaltung für die Solarzelle darstellt wird nicht an den Innenwiderstand der Solarzelle angepasst.

 

Schaltbild des DC-DC Converters

Aus dieser Schaltung wurde dann ein einfaches Layout erstellt, eine Platine geätzt und diese bestückt. Eine USB-Buchse am Ausgang ermöglicht das direkte Ansschliessen von USB-Geräten. Um das Ganze auch einwenig vernünftig aussehen zu lassen habe ich der Platine noch ein kleines Kunsstoffgehäuse gespendet…

Messung der Beleuchtungsstärke

Messaufbau
Schaltbare Lastwiderstände
Layout am Computer
Folie zum Erstellen der Printplatte
Geätzte PCB
Bestückte PCB
Fertige Schaltung

Datenknoten mit Arduino

Leider sind die Abstände, in denen ich einwenig Zeit finde, einen neuen Beitrag für den Blog zu schreiben, nicht kürzer geworden. Aber einen Beitrag pro Monat zu posten, halte ich ein… 🙂

Dieses Mal ist es kein retro Bastelprojekt aus den heimischen Gefielden oder eine Restauration eines alten Gerätes, sondern wieder etwas zum Thema Arduino. Die Idee – es soll ein Sensor gebaut werden, der wie immer, eine physikalische Größe in ein elektrisches Signal umwandelt. Das ist jetzt nichts Besonderes und um welche Art von Sensor es sich handeln wird, werde ich vorerst noch nicht beschreiben. Aber es soll nicht ein Sensorboard geben, sondern viele. Und diese Sensorboard kurz „Sensoren“ sollen in einer zweidimensionalen Matrix miteinander vernetzt werden. Man kann sich das inetwa vorstellen wie ein Schachbrett, wobei jedes der Schachbrettfelder einen Sensor darstellt. Dieses Netzwerk an Sensoren – also Sensorknoten – soll dann über eine Übergabestelle mit einem Rechner verbunden sein und die Sensordaten des jeweiligen Feldes ausgeben. Es soll dann auch möglich sein, einzelne Felder aus dem Netzwerk zu entfernen ohne dass das verbleibende Netzwerk seine Funktion verliert.

Das ganze System soll möglichst einfach und günstig aufgebaut werden. Und so ist schnell ein Systemkonzept entstanden, in dem die Knoten über den I²C Bus kommunizieren und ihre Daten zu einem Master senden. Das folgende Diagramm soll das verdeutlichen.

Dieses Konzept, so dachte ich mir, lässt sich am einfachsten mit einem ATmega Microcontroller realisieren. Der hat genügend IO´s, einen I²C Bus und UART onboard, ebenso auch analoge Eingänge und benötigt wenig Bauteilperipherie, um ihn in einem eigenen Layout zum Leben zu erwecken. Und es gibt nichts schnelleres, so einen Testaufbau eines solchen Knotennetzwerks zu realisieren, als die gut bekannten Arduino Developmentboards zu benutzen. Ich habe die günstigste Variante für einen Testaufbau gewählt -> den Chinanachbau vom ArduinoUno (Joy-IT UNO) mit dem Atmga328 im gesockelten DIL Gehäuse.

Joy-It Uno Boards

Im Bild sind zehn Stück dieser Microcontrollerboards zu sehen. Von denen soll einer als Bus-Master und neun Stück als Slaves eingesetzt werden. Jeder dieser Slaves hat natürlich eine eindeutige Bus-Adresse, die im System nur einmal vorkommt. Im Testaufbau wird diese Busadresse über den Programmcode fest vergeben, da ohnehin jeder Arduino einmal mit dem Rechner verbunden werden muß, um den Programm-Upload durchzuführen. Das soll natürlich später anders aussehen. Denn der Arduino wird auf den Atmega328 Chip, seinen Quarz und die paar Widerstände reduziert auf dem Sensorboard mit gelayoutet. Programmiert soll der Chip dann über die ISP Pins werden. Da bei vielen Boards natürlich nicht jedes Mal der Programmcode individuell angepasst wird und alle das gleiche Flashfile erhalten sollen, will ich die Sensoradresse mit einem 7Bit Dipschalter einstellen. Ein 4021 Cmos  Static Shift Register soll die Bits nach nach dem Einschalten des Controllers auslesen und seriell in den Controller schieben. Der daraus resultierende Wert steht dann in einer Variable als Busadresse zu Verfügung.

Jeder dieser Slaves mit seiner individellen Busadresse wird nun vom Masterknoten der Reihe nach abgefragt, welchen Zustand er hat und ob er einen Ausgang schalten soll, oder nicht. Das bedeutet, der Knoten hat lediglich einen DO (Digitalen Ausgang) mit dem er beispielsweise eine LED aus- und einschalten kann und einen oder mehrere DI (Digitalen Eingang) der einen Zustand, zum Beispiel eines einfachen Schalters abfragt. Diese Funktionen werden in 2 Bits eines Bytes gespeichert. Ein weiteres Byte dient zur Übertragung der Busadresse. Es werden also zwei Bytes über den Bus geschickt. Das untenstehende Bild zeigt den Testaufbau mit den „UNO-Boards“

Alle Arduinos sind mit I²C Datenbus und Spannungsversorgung verbunden

Der Ablauf läuft wie folgt:

MASTER:
Der Masterknoten sendet nach der Reihe an alle Slave-Adressen eine Anfrage und einen Schaltbefehl (der kommt für alle Knoten von einem TEST-Tastereingang am Master) für den LED-Ausgang des Knotens und sieht ob eine Antwort zurückkommt oder nicht. Wenn keine Antwort kommt, ist der Knoten nicht im Netz oder defekt. Kommt eine Antwort, so besteht diese aus der Adresse des Knotens und seinem Statusbyte. Diese Informationen werden über ein RS232 Terminal an den, am Master angeschlossenen Rechner übertragen. So kann dort beispielsweise über eine Visualisierung mittels (NI LabView, oder Matlab o.ä.) der Schaltzustand jedes einzelnen Knotens  am Bildschirm angezeigt werden. Mit einer Anpassung des MasterProgrammes ist es auch möglich, die LED-Ausgänge der Slaves über den Rechner zu schalten.

SLAVE:
Wenn der Masterknoten vom Slave Daten anfordert, so sendet der Slave zwei Bytes zurück. Wobei Byte0 wieder die Slave ID (also Busadresse ist) und Byte1 die Daten. Byte1 besteht eigentlich aus nur zwei Bit, die wie folgt kodiert sind (in dezimaler Darstellung):
 0 = LED aus | Sensor nicht ausgelöst
 1 = LED ein | Sensor nicht ausgelöst
 2 = LED aus | Sensor ausgelöst
 3 = LED ein | Sensor ausgelöst

Der Programmcode als Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// I2C Slave Code
// 16.05.2018 
// ver 1.3
#include <Wire.h>
#define ADDRESS 2     // adresse des slave knotens
#define PAYLOAD_SIZE 2 // anzahl der bytes  die vom masterknoten zu erwarten sind
int LED=12;            // indicator led an pin D12
int SENSOR = 8;        // sensor input an pin D8
bool actionState=0;      // sensor zustand
int busstatus;  // statusvariable 
                       // 0 = LED aus | sensor nicht belegt
                       // 1 = LED ein | sensor nicht belegt
                       // 2 = LED aus | sensor belegt
                       // 3 = LED ein | sensor belegt
 
bool sensled=0;          // sensor LED
byte nodePayload[PAYLOAD_SIZE];

void setup()
{
  pinMode(LED, OUTPUT);         //sensorLED
  pinMode(SENSOR, INPUT);       //Sensor 
  Wire.begin(ADDRESS);          // Activate I2C network
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent); // auf master anforderung warten
                      //  // debug interface
                      //  Serial.begin(9600); 
}

// *********************************mainloop****************************************************
void loop()
{ 
  delay(5);
  
   if(sensled){digitalWrite(LED, HIGH);}
         else{digitalWrite(LED, LOW);}

  actionState = digitalRead(SENSOR);  //Sensoreingang abfragen        
   if((actionState==1)&&(sensled==1)) {busstatus=3;}
   else if ((actionState==0)&&(sensled==1)) {busstatus=1;}
   else if ((actionState==1)&&(sensled==0)) {busstatus=2;}
   else if ((actionState==0)&&(sensled==0)) {busstatus=0;}

                      //  Serial.println("######################");
                      //  Serial.print("busstatus neu setzen ");
                      //  Serial.println(busstatus);
                      //  Serial.print("sensled LED            ");
                      //  Serial.println(sensled);
                      //  Serial.print("actionState           ");
                      //  Serial.println(actionState);
                      //  Serial.println("######################");
  nodePayload[0] = ADDRESS;                  // Adresse in byte0 zurücksenden.  
  nodePayload[1] = busstatus;                //byte 1 ist die statusinfo der LED
}



// *********************************************************************************************
void requestEvent()
{ Wire.write(nodePayload,PAYLOAD_SIZE);  
  Serial.println("bytes status schreiben");
  Serial.println(nodePayload[0]);
  Serial.println(nodePayload[1]);
  delay(5);
}

// *********************************************************************************************
void receiveEvent(int bytes)  //einen wert vom I2C lesen
      
{
  
  busstatus = Wire.read(); //If the value received was true turn the led on, otherwise turn it off  
                              //  Serial.println("status empfangen");
                              //  Serial.println(busstatus);
  if((busstatus==1)||(busstatus==3)){sensled = 1;}
                                else{sensled = 0;}
                                              
}

 

Die Busadresse ist in diesem Slave-Code noch individuell einzugeben. In der nächsten Version ist dann der vorherbeschriebene „Serializer“ der parallelen Dip-Schaltervariante implementiert. Das folgende Codebeispiel ist von Masterknoten, der die Slaves ausliest und mittel Prüftaster ein LEDmuster an die Sensorslaves sendet:

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// I2C masterknoten 
// 16.05.2018 
// ver 1.2
// changes abfrage wenn kein knoten am bus dann 255 ausgeben
#include <Wire.h>

#define busbytes 2          // wievele byte vom I2C knoten zu erwarten sind
#define maxKNOTEN  10       // anzahl der zu scannenden slaves
#define startKNOTEN 2       // startadresse der slaves
#define DELAY 5             // einfach ein delay ....

int i; int j=0;
int buttonPin = 12;
int testbut = 0; int anim = 0;
int buttonState = 0;
int DATEN[busbytes];
int adresse; int busstatus;  
byte sensorbelegt; byte ledsensoron;

                       // 0 = LED aus | Sensor nicht belegt
                       // 1 = LED ein | Sensor nicht belegt
                       // 2 = LED aus | Sensor belegt
                       // 3 = LED ein | Sensor belegt

int leddat1[] = {1,1,1,1,0,1,1,1,1}; // -
int leddat2[] = {0,0,0,0,1,0,0,0,0}; // |

void setup()
{
  Serial.begin(9600);  
  Serial.println("MASTER-KNOTEN");
  Serial.print("Maximum Slaveknoten: ");
  Serial.println(maxKNOTEN);
  Serial.print("Datengroesse in byte: ");
  Serial.println(busbytes);
  Serial.println("***********************");
  
  Wire.begin();                 // Activate I2C link
  pinMode(buttonPin, INPUT);    // test-tastereingang festlegen
}


//#####################################################################################################
void loop()
    
{
  for (int Knotenadresse = startKNOTEN;         //alle knoten scannen
           Knotenadresse <= maxKNOTEN; 
           Knotenadresse++) 

        
    //################################################################################################       
    { 
     // testbut = 0;  
     anim = 0;   
    Wire.requestFrom(Knotenadresse, busbytes);        // daten vom jeweiligen knoten anfordern
                                                 
           DATEN[0]=255; DATEN[1]=255;   // wenn kein knoten dann auf 255 setzen    
          if(Wire.available() == busbytes) {                                    // wenn knoten und daten dann
            for (i = 0; i < busbytes; i++) DATEN[i] = Wire.read();          // daten holen (zuerst busID, dann daten)
           // for (j = 0; j < busbytes; j++) Serial.println(DATEN[j]);        // daten an rs232 ausgeben   
          }            

//            Serial.println(Knotenadresse);
//            Serial.println(DATEN[0]);
//            Serial.println(DATEN[1]);
//            Serial.println(" ");
           
            adresse=DATEN[0]; 
            busstatus=DATEN[1];
           
            if(busstatus == 0)       {sensorbelegt=false;  ledsensoron=false;}
            else if (busstatus == 1) {sensorbelegt=false;  ledsensoron=true;}
            else if (busstatus == 2) {sensorbelegt=true;  ledsensoron=false;}
            else if (busstatus == 3) {sensorbelegt=true;  ledsensoron=true;}
      
         //################################################################################################
         //Testbutton Status lesen und variable testbut entsprechend setzen
       
          buttonState = digitalRead(buttonPin);               //tastereingang einlesen
          if(buttonState == HIGH){                            //wenn taster aktiv dann variable anim setzen
          anim = 1;
          //delay(5); 
          }
            
//            //debug debuginfo tasterstatus auf rs232 ausgeben
//            Serial.println("#######################");
//            Serial.print("Knoten Adresse    :");
//            Serial.println(adresse);
//            Serial.print("Busstatus         :");
//            Serial.println(busstatus);
//            
//            Serial.println("----------------");
//            Serial.print("Fliese belegt    :");
//            Serial.println(sensorbelegt);
//            Serial.print("LED Fliese       :");
//            Serial.println(ledsensoron);
//            Serial.print("#######################");
//            Serial.println(" ");
      
          //################################################################################################
          //Testbutton Status an jeweiligen knoten senden
      
          Wire.beginTransmission(Knotenadresse);           // transmit to device actual in for loop
          //anim schreiben
                    
           if (anim==0) {testbut=leddat1[j]; j++;}
                   else {testbut=leddat2[j]; j++;}
           if (j>8){j=0;}
          
          Wire.write(testbut);                             // senden des tasterstatus
          Wire.endTransmission();                          // ende gelände mit uerbertragung
       
          delay(DELAY);
          

    }
   
}

 

Mit dieser Anordnung ist es jetzt möglich alle Arduinos und deren Eingang auszulesen bzw. die LED über den Bus zu steuern. Im nächsten Schritt wird ein „Sensor“ gebaut, eine Platine gelayoutet und der ArduinoUno auf seinen Microcontroller reduziert. Darüber werde ich in einem der nächsten Posts berichten…

 

 

 

Langzeitmessungen mit Keithley und Matlab

Keithley2000 Tischmultimeter

Ein alter Begleiter im Bereich Messgeräte ist das Tischmultimeter von Keithley. In unseren Labors  werden vorwiegend die Typen der 2000er Serie eingesetzt. Es gibt sie in unterschiedlichen Ausstattungsvarianten betreffend der Schnittstellen zur Aussenwelt. Hier ist GBIP-Bus natürlich ein Standard, ebenso wie RS232. Die neueren Geräte besitzen mittlerweile ein LAN Interface mit dem eine Kommunikation über das InternetProtokoll möglich ist. Über jede dieser Schnittstellen kann über „Standard Commands for Programmable Instruments“ (SCPI) mit dem Gerät kommuniziert werden. In diesem Beispiel werde ich das Keithley 2000 über Matlab ansteuern und zyklisch über einen längeren Zeitraum Messwerte auslesen, diese in Matlab speichern und schlußendlich in einem Plot ausgeben – quasi einen simplen Datalogger konfigurieren. Der Zweck dieses Aufbaus ist es, den Spannungsverlauf (bzw. auch Strom) eines Akkus bzw. Batterie eines Low-Energie Device zu erfassen.

Rückseite des Keithley 2000
GPIB Interface (IEEE488)
RS232 Schnittstelle

In diesem Beispiel werde ich die serielle Datenübertragung per klassischer RS232 Schnittstelle verwenden, da diese für meine Anwendung vollkommen ausreicht. Zudem kann ich mir die Installation der Treiberpakete für das GPIP-USB Interface ersparen. 🙂 Da viele der aktuellen Rechner und Laptops auch keine RS232 Ports mehr haben, muß ein USB-RS232 Adapter (beispielsweise FTDI232 etc.) her.

USB-RS232 Adaper am Keithley2000

Ist die Verbindung zwischen dem Multimeter und dem Rechner hergestellt, kann, wie in diesem Beispiel, über ein Matlabscript kommuniziert werden. Dem Keithley muß nur mehr mitgeteilt werden, dass es über die serielle Schnittstelle „sprechen“ soll. Die folgenden Code-Schnipsel zeigen, wie man einfach über SCPI Daten auslesen kann:


serialObject = instrfind('Type', 'serial', 'Port', 'COM26', 'Tag', '');
%serialPort = 'COM23';
%serialObject = serial(serialPort,'BaudRate',9600, 'DataBits',8);

if isempty(serialObject)
serialObject = serial('COM26','BaudRate',57600, 'DataBits',8);
else
fclose(serialObject);
serialObject = serialObject(1)
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Sourcemeter 2000 setup
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fopen(serialObject)
% fprintf(serialObject,':*RST')

time = now;
voltage = 0;
%%
figureinstanz = figure('NumberTitle','off',...
'Name','Spannungslogg',...
'Color',[0 0 0],'Visible','off');
plotinstanz = plot(voltage,time,'Color','red');

%% Messzeit und evtl Messintervall
stoptime = 10; %60 seconds
timeInterval = 1; % brauch' ma jetzt nicht

% Messgeraet einstellen
fprintf(serialObject,':SOUR:FUNC:MODE CURR'); % current source selection.
fprintf(serialObject,':SOUR:CURR:MODE FIXED'); % changes voltage mode to fixed
fprintf(serialObject,':SOUR:CURR:LEV 0'); % sets current to 0

fprintf(serialObject,':SENS:FUNC &quot;VOLT&quot;');
fprintf(serialObject,':SENS:VOLT:PROT 4');
%fprintf(serialObject,':SENS:CURR:RANG:AUTO ON');
fprintf(serialObject,':SENS:VOLT:RANG 10');
fprintf(serialObject,':FORM:ELEM VOLT');

% %fprintf(serialObject,':TRAC:COUN 1');
% %fprintf(serialObject,':TRAC:FEED:CONT NEV');
%
%
% fprintf(serialObject,':TRAC:CLE');
%
% fprintf(serialObject,':TRAC:POIN 10');
% fprintf(serialObject,'TRAC:FEED:SENS');
% fprintf(serialObject,'TRAC:FEED:CONT NECT');
% fprintf(serialObject,'TRIG:COUN 10');
% fprintf(serialObject,':OUTP ON');
%
% fprintf(serialObject,':INIT');
% fprintf(serialObject,':TRACE:DATA?');

%% Daten abholen
count = 1; voltage(1)=4
tic;
time=toc;
% while time&lt;=stoptime
while voltage&gt;=1.5
% fprintf(serialObject,':INIT');
% fprintf(serialObject,':TRAC:FEED SENS');
% fprintf(serialObject,':TRAC:DATA?');
%
fprintf(serialObject,':READ?');
voltage(count) = fscanf(serialObject,'%f');
time(count) = toc;
set(plotinstanz,'YData',voltage,'XData',time);
set(figureinstanz,'Visible','on');
pause(timeInterval);
count = count +1;
end

figure(1);
plot(time,voltage);
grid on; hold on;
xlabel('Zeit [s]'); ylabel('Batteriespannung [V]')
title('Spannungsverlauf Batterie 3V Lithium (2032 mit Modul) im default mode');

% fprintf(serialObject,':OUTP OFF');
%% Put the instrument in local mode
fprintf(serialObject,'SYSTEM:LOCAL');
fclose(serialObject);

Wie so ein Datalog dann aussieht ist in der folgenden Grafik dargestellt. Hier ist der Spannungsverlauf einer nahezu entladenen Batterie bis zum Abschalten des Verbrauchers über die Zeit aufgezeichnet worden.

LCR-Meter über Matlab auslesen

LCR-Meter 4297A Agilent

In diesem Post möchte ich mich einmal etwas anderem widmen. Es geht nicht um Retrotechnik, sondern um eine Kleinigkeit, die mir das Arbeiten im Büro erleichtert. Eines der vielen Messgeräte mit denen ich zu tun habe, ist ein Agilent LCR-Meter. Mit dem LCR-Meter 4297A kann man bekannterweise ja die Induktivität, die Kapazität, etc. von elektrischen Bauteilen und generell von Strukturen, die dem Bereich der Elektronik/Elektrotechnik zugeordnet sind, messen. Grob gesagt, der 4297A misst eigentlich nur Strom / Spannung, die Phasenlage  zwischen den beiden und die Energierichtung. Und das bei einer bestimmten Frequenz. Mathematisch werden dann aus diesen Paramatern alle Größen wie L,C,R,X,Y,Q,PHI,… errechnet und ausgegeben. Die Frequenz hier hierbei vom 1MHz bis 3GHz (in 100kHz Schritten) einstellbar. Idealerweise kann das Messgerät nicht nur in einem Frequenzpunkt messen, sondern auch in vielen. Mit „vielen“ ist hier gemeint, dass das Messgerät Frequenztabellen mit 32 Einträgen erzeugen kann. Von diesen Tabellen existieren acht Stück. So ist es möglich, den Verlauf einer gemessenen Größe in Form einer Kurve darzustellen. Allerdings ist das ziemlich umständlich. Die Inhalte der Tabellen müssen händisch (als „csv“ Dateien) Tabelle für Tabelle exportiert und gespeichert werden. Das bedeutet, jede Tabelle muss einzeln angewählt werden. Danach ist der Dialog „Export List View“ zu selektieren – dann ein Speicherpfad und Dateiname anzugeben. Erst jetzt werden die ersten 32 Datensätze exportiert. Dieser Vorgang ist insgesamt acht mal zu wiederholen. Gespeichert wird auf eine 3,5 Zoll Floppy Disc – das einzige verfügbare Medium. Man könnte den 4297A optiona auch in ein LAN hängen und eine Dateifreigabe einrichten. Der händische Export bleibt aber nicht erspart. Auf einem „normalen“ Rechner können die  .csv Files jetzt geöffnet werden. Die müssen dann im postprocessing händisch zusammengefügt werden. Erst jetzt kann aus den Daten ein Diagramm gebastelt werden. Hier bietet sich als Tool Matlab von Matworks an, das in unseren Laboren im Rahmen der Ausbildung häufig eingesetzt wird.

NI GPIB – USB Controller

Um diesen umständlichen Prozess wesentlich zu vereinfachen, habe ich ein kleines Skript erstellt, das über die SCPI – Befehle (Standard Commands for Progammable Instruments) mit dem Messgerät kommuniziert. Das soll heissen: Das Messgerät ist über einen GPIB-USB Controller mit einem PC verbunden. Auf dem PC befindet eine Matworks Matlab Installation samt den benötigten Toolboxen. Das Matlab-Script soll nun einfach die Tabellen der Reihe nach durchschalten und die Inhalte der einzelnen Parameter auslesen und einem Array speichern. Der Inhalt der Arrays wir dann direkt in einem Plot dargestellt. Diese Methode bedient sich aber nur der Inhalte der Tabellen. Es wäre natürlich auch möglich, über das Script in einer Schleife jede gewünschte Frequenz direkt einzustellen, die Messwerte auszulesen, die nächste Frequenz anzuwählen usw.  Das würde max. 29990 Punkte über den gesamten Frequenzbereich ergeben. Die acht Tabellen á 32 Punkte erlauben hingegen nur 256 Punkte. Das ist fürs erste aber ausreichend und auch viel schneller.

Transmission Line 50 Ohm mit Abschlusswiderstand
die Leitung ist terminiert

In dem Beispiel ist der Impedanzverlauf (Z-Verlauf) einer 50 Ohm Transmissionline dargestellt. Das Ende der Leitung ist dabei mit einem 50Ohm Widerstand abgeschlossen. Der Frequenzbereich ist 1MHz bis 3 GHz. Anders sieht es aus, wenn die Leitung offen oder kurz geschlossen ist. Die elektromagnetische Welle wird dann nicht, wie bei dem „gematchten“ System am Ende der Leitung in Wärmeenergie umgewandelt, sondern zurück in das System reflektiert.

die Leitung ist kurzgeschlossen

Das folgende ganz einfache Matlabscript ermöglicht das Auslesen der Messgeräteparameter. Das Script dient als Beispiel, wie man schnell zu den Messdaten kommt. Im Programmingmanual des Herstellers vom LCR-Meter sind alle SCPI Commandos und reichlich Beispiele angeführt, mit denen man mit dem Messgerät kommunizieren kann.


%auslesen der agilent LCR Keule 4287A
%gekodet von ingmar bihlo Ende November 2017

%anschluss über gpib ni adapter
%LCR gpip adresse: 5
%%
%vorarbeiten an LCR Keule
%
% Es müssen 8 Tabellen mit je 32 Punkten definiert sein
% (power und average ist egal, wird nicht ausgelesen)
% die CALibration muss gemacht worden sein
% unter "measurement parameters" muessen vier parameter definiert sein
% zb. Z, qhi, R, L, etc... diese sind dann in den variablen param1 bis 4
% enthalten

%%

% gpib interface oeffnen und identifier lesen
g = gpib('ni', 0, 5);
g.InputBufferSize = 100000; % Set the buffer size
fopen(g);
fprintf(g, '*IDN?')
idn = fscanf(g);
fclose(g);

num1all=0; % initialisieren der variablen für den summenvector
num2all=0;
num3all=0;
num4all=0;
freq=0;

fopen(g);
%read list parameters (frequency points)
fprintf(g, ':SOUR:LIST?');
fpoint=fscanf(g);
listchar=strsplit(fpoint,',');
list=[cellfun(@str2num, listchar(:,1:end))]
clear listchat; clear fpoint;

%analyze list content
points=freq(1);

for i=1:8
%Tables selecten
fprintf(g, strcat(':SOUR:LIST:TABL 0',num2str(i)));
pause(1); %pause 1s zum umschalten der tabelle

%parameter1 abholen
fprintf(g, ':DATA:FDAT1?'); %parameter 1 anfragen
par1=fscanf(g); %parameter 1 holen

string1=strsplit(par1,','); %parameter 1 string nach komma zerlegen
%num1=[cellfun(@str2num, string1(:,1:end))] %parameter 1 strings in dec konvertieren
num1=[cellfun(@str2num, string1(:,1:end))];
num1all=[num1all,num1]; %parameter1 aktuell mit parameter1 aus vorherigem durchlauf concentenaten

fprintf(g, ':DATA:FDAT2?');
par2=fscanf(g);
string2=strsplit(par2,',');
num2=[cellfun(@str2num, string2(:,1:end))]
num2all=[num2all,num2];

fprintf(g, ':DATA:FDAT3?');
par3=fscanf(g);
string3=strsplit(par3,',');
num3=[cellfun(@str2num, string3(:,1:end))]
num3all=[num3all,num3];

fprintf(g, ':DATA:FDAT4?');
par4=fscanf(g);
string4=strsplit(par4,',');
num4=[cellfun(@str2num, string4(:,1:end))]
num4all=[num4all,num4];

%read list parameters (frequency points)
fprintf(g, ':SOUR:LIST?');
fpoint=fscanf(g);
listchar=strsplit(fpoint,',');
listraw=[cellfun(@str2num, listchar(:,1:end))];
list=listraw(:,2:end); %von pos2 das feld schreiben (an pos ist die anzahl der zeilen)

for c=1:3:96
freq=[freq,list(c)]; %von jedem 3. wert aus list ein neues array bilden
end

clear listchat; clear fpoint;

pause (1);
end

%%

%ausgabevariablen festlegen
frequency=freq(:,2:end);
param1=num1all(:,2:end);
param2=num2all(:,2:end);
param3=num3all(:,2:end);
param4=num4all(:,2:end);

%%
% Cell array richtig uma drahn
x1=param1(1:32);
y1=param1(33:256);
param1 = [y1 x1];

x2=param2(1:32);
y2=param2(33:256);
param2 = [y2 x2];

x3=param3(1:32);
y3=param3(33:256);
param3 = [y3 x3];

x4=param4(1:32);
y4=param4(33:256);
param4 = [y4 x4];
%%
%uerberflüssige variablen loeschen
clear c; clear i; clear list; %clear freq;
clear par1;clear par2;clear par3;clear par4;
clear string1;clear string2;clear string3;clear string4;
clear num1all;clear num2all;clear num3all;clear num4all;

fclose(g);

%plotten der ergebnisse
figure(1);
plot(frequency,param1);
grid on; hold on;
xlabel('Frequency [Hz]'); ylabel('Measurement Parameter1 |Z| [Ohm]');
title('Agilent LCR Keule');

figure(2);
plot(frequency,param2);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter2');
title('Agilent LCR Keule');

figure(3);
plot(frequency,param3);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter3');
title('Agilent LCR Keule');

figure(4);
plot(frequency,param4);
grid on; hold on;
xlabel('Frequency'); ylabel('Measurement Parameter4');
title('Agilent LCR Keule');