File Coverage

blib/lib/Lab/Instrument/Lakeshore33x.pm
Criterion Covered Total %
statement 11 352 3.1
branch 0 228 0.0
condition 0 156 0.0
subroutine 4 35 11.4
pod 13 31 41.9
total 28 802 3.4


line stmt bran cond sub pod time code
1             package Lab::Instrument::Lakeshore33x;
2             $Lab::Instrument::Lakeshore33x::VERSION = '3.880';
3             #ABSTRACT: Lakeshore 33x Temperature controller
4              
5 1     1   1843 use v5.20;
  1         4  
6              
7 1     1   5 use strict;
  1         11  
  1         24  
8 1     1   5 use Lab::Instrument;
  1         5  
  1         19  
9 1     1   4 use warnings;
  1         2  
  1         5513  
10              
11              
12             our @ISA = ('Lab::Instrument');
13              
14             our %fields = (
15             supported_connections => [ 'GPIB', 'VISA' ],
16              
17             # default settings for the supported connections
18             connection_settings => {
19             gpib_board => 0,
20             gpib_address => undef,
21             timeout => 1
22             },
23              
24             device_settings => {
25              
26             },
27              
28             device_cache => {
29             T => undef,
30             setpoint => undef,
31             range => undef,
32             },
33              
34             device_cache_order => [ 'function', 'range' ],
35             request => 0
36             );
37              
38             sub new {
39 0     0 1   my $proto = shift;
40 0   0       my $class = ref($proto) || $proto;
41 0           my $self = $class->SUPER::new(@_);
42 0           $self->${ \( __PACKAGE__ . '::_construct' ) }(__PACKAGE__);
  0            
43              
44 0           return $self;
45             }
46              
47             sub get_value {
48 0     0 0   my $self = shift;
49              
50 0           return $self->get_T(@_);
51             }
52              
53             sub get_T {
54              
55 0     0 1   my $self = shift;
56 0           my ( $channel, $tail ) = $self->_check_args( \@_, ['channel'] );
57              
58 0 0         if ( not defined $channel ) {
    0          
59 0           $channel = "A";
60             }
61             elsif ( not $channel =~ /\b(A|a|B|b)\b/ ) {
62 0           die
63             "unexpected value ($channel) for CHANNEL in sub get_T. Expected values are A or B.";
64             }
65              
66 0           return $self->query( "KRDG? $channel", $tail );
67             }
68              
69             sub set_T {
70 0     0 1   my $self = shift;
71 0           return $self->set_setpoint(@_);
72             }
73              
74             sub get_setpoint {
75              
76 0     0 0   my $self = shift;
77              
78 0           my ( $loop, $tail ) = $self->_check_args( \@_, ['loop'] );
79              
80 0 0 0       if ( not defined $loop ) {
    0          
81 0           $loop = 1;
82             }
83             elsif ( $loop != 1 and $loop != 2 ) {
84 0           die
85             "unexpected value ($loop) for LOOP in sub get_setpoint. Expected values are 1 or 2.";
86             }
87              
88 0           return $self->query("SETP? $loop");
89             }
90              
91             sub set_setpoint {
92 0     0 0   my $self = shift;
93              
94 0           my ( $setpoint, $loop, $tail )
95             = $self->_check_args( \@_, [ 'value', 'loop' ] );
96              
97 0 0 0       if ( not defined $loop ) {
    0          
98 0           $loop = 1;
99             }
100             elsif ( $loop != 1 and $loop != 2 ) {
101 0           die
102             "unexpected value ($loop) for LOOP in sub set_T. Expected values are 1 or 2.";
103             }
104              
105 0 0 0       if ( $setpoint < 0 or $setpoint > 300 ) {
106 0           die
107             "unexpected value ($setpoint) for SETPOINT in sub set_T. Expected values are between 0...300 K.";
108             }
109              
110 0           return $self->query( "SETP $loop,$setpoint; SETP? $loop", $tail );
111              
112             }
113              
114             sub set_range {
115 0     0 1   my $self = shift;
116 0           my $range = shift;
117              
118 0 0         if ( $range =~ /\b(OFF|off)\b/ ) {
    0          
    0          
    0          
119 0           $range = 0;
120             }
121             elsif ( $range =~ /\b(LOW|low)\b/ ) {
122 0           $range = 1;
123             }
124             elsif ( $range =~ /\b(MEDIUM|medium|MED|med)\b/ ) {
125 0           $range = 2;
126             }
127             elsif ( $range =~ /\b(HIGH|high)\b/ ) {
128 0           $range = 3;
129             }
130             else {
131 0           die
132             "unexpected value ($range) for RANGE in sub set_range. Expected values are OFF, LOW, MEDIUM, HIGH.";
133             }
134              
135             # set range
136 0           return $self->query("RANGE $range; RANGE?");
137              
138             }
139              
140             sub get_range {
141 0     0 0   my $self = shift;
142 0           my ($tail) = $self->_check_args( \@_, [] );
143 0           my $range = $self->query( "RANGE?", $tail );
144              
145 0 0         if ( $range == 0 ) {
    0          
    0          
    0          
146 0           $range = 'OFF';
147             }
148             elsif ( $range == 1 ) {
149 0           $range = 'LOW';
150             }
151             elsif ( $range == 2 ) {
152 0           $range = 'MEDIUM';
153             }
154             elsif ( $range == 3 ) {
155 0           $range = 'HIGH';
156             }
157             else {
158 0           die
159             "unexpected value ($range) for RANGE in sub set_range. Expected values are OFF, LOW, MEDIUM, HIGH.";
160             }
161             }
162              
163       0 0   sub set_heatercontrol {
164              
165             }
166              
167             sub set_control_mode {
168              
169 0     0 0   my $self = shift;
170              
171 0           my ( $mode, $loop, $tail )
172             = $self->_check_args( \@_, [ 'value', 'loop' ] );
173              
174 0 0 0       if ( not defined $loop ) {
    0          
175 0           $loop = 1;
176             }
177             elsif ( $loop != 1 and $loop != 2 ) {
178 0           die
179             "unexpected value ($loop) for LOOP in sub set_control_mode. Expected values are 1 or 2.";
180             }
181              
182 0 0         if ( $mode =~ /\b(MANUAL|manual|MAN|man)\b/ ) {
    0          
    0          
    0          
    0          
    0          
183 0           $mode = 1;
184             }
185             elsif ( $mode =~ /\b(ZONE|zone)\b/ ) {
186 0           $mode = 2;
187             }
188             elsif ( $mode =~ /\b(OFF|off)\b/ ) {
189 0           $mode = 3;
190             }
191             elsif ( $mode =~ /\b(AUTO_PID|auto_pid)\b/ ) {
192 0           $mode = 4;
193             }
194             elsif ( $mode =~ /\b(AUTO_PI|auto_pi)\b/ ) {
195 0           $mode = 5;
196             }
197             elsif ( $mode =~ /\b(AUTO_P|auto_p)\b/ ) {
198 0           $mode = 6;
199             }
200             else {
201 0           die
202             "unexpected value ($mode) for CONTROL MODE in sub set_controlmode. Expected values are MANUAL, ZONE, AUTO_PID, AUTO_PI, AUTO_P and OFF.";
203             }
204              
205 0           return $self->query("CMODE $loop,$mode; CMODE? $loop");
206              
207             }
208              
209             sub get_control_mode {
210 0     0 0   my $self = shift;
211 0           my ( $loop, $tail ) = $self->_check_args( \@_, ['loop'] );
212              
213 0 0         if ( not defined $loop ) {
214 0           $loop = 1;
215             }
216              
217 0           return $self->query( "CMODE? $loop", $tail );
218             }
219              
220             sub get_R {
221              
222 0     0 1   my $self = shift;
223 0           my ( $channel, $tail ) = $self->_check_args( \@_, ['channel'] );
224              
225 0 0         if ( not defined $channel ) {
    0          
226 0           $channel = "A";
227             }
228             elsif ( not $channel =~ /\b(A|a|B|b)\b/ ) {
229 0           die
230             "unexpected value ($channel) for CHANNEL in sub get_R. Expected values are A or B.";
231             }
232              
233 0           return $self->query( "SRDG? $channel", $tail );
234             }
235              
236             sub set_control_loop {
237              
238 0     0 0   my $self = shift;
239              
240 0           my ( $channel, $loop, $units, $powerup, $display, $tail )
241             = $self->_check_args(
242             \@_,
243             [ 'channel', 'loop', 'units', 'powerup', 'display' ]
244             );
245              
246             # loop optinal parameter; Usually you alwas want to use control loop 1
247             # units optinal parameter; 1 == Kelvin, 2 == Celsius, 3 == sensor units
248             # powerup optinal parameter; 0 == power up enable off, 1 == power up enable on
249             # display optinal parameter; 1 == current, 2 == power
250              
251 0 0 0       if ( not defined $loop ) {
    0          
252 0           $loop = 1;
253             }
254             elsif ( $loop != 1 and $loop != 2 ) {
255 0           die
256             "unexpected value ($loop) for LOOP in sub set_control_loop. Expected values are 1 or 2.";
257             }
258              
259 0 0 0       if ( not defined $units ) {
    0 0        
    0          
    0          
    0          
260 0           $units = 1;
261             }
262             elsif ( $units =~ /\b(KELVIN|kelvin|K|k)\b/ ) {
263 0           $units = 1;
264             }
265             elsif ( $units =~ /\b(CELSIUS|celsius|C|c)\b/ ) {
266 0           $units = 2;
267             }
268             elsif ( $units =~ /\b(SENSOR|sensor|S|s)\b/ ) {
269 0           $units = 3;
270             }
271             elsif ( $units != 1 and $units != 2 and $units != 3 ) {
272 0           die
273             "unexpected value ($units) for UNITS in sub set_control_loop. Expected values are KELVIN, CELSIUS or SENSOR.";
274             }
275              
276 0 0 0       if ( not defined $powerup ) {
    0          
    0          
    0          
277 0           $powerup = 1;
278             }
279             elsif ( $powerup =~ /\b(ON|on)\b/ ) {
280 0           $powerup = 1;
281             }
282             elsif ( $powerup =~ /\b(OFF|off)\b/ ) {
283 0           $powerup = 0;
284             }
285             elsif ( $powerup != 0 and $powerup != 1 ) {
286 0           die
287             "unexpected value ($powerup) for POWERUP in sub set_control_loop. Expected values are ON or OFF.";
288             }
289              
290 0 0 0       if ( not defined $display ) {
    0          
    0          
    0          
291 0           $display = 2;
292             }
293             elsif ( $display =~ /\b(CURRENT|current)\b/ ) {
294 0           $display = 1;
295             }
296             elsif ( $display =~ /\b(POWER|power)\b/ ) {
297 0           $display = 2;
298             }
299             elsif ( $display != 1 and $display != 2 ) {
300 0           die
301             "unexpected value ($display) for DISPLAY in sub set_control_loop. Expected values are CURRENT or POWER.";
302             }
303              
304 0 0         if ( not $channel =~ /\b(A|a|B|b)\b/ ) {
305 0           die
306             "unexpected value ($channel) for CHANNEL in sub set_control_loop. Expected values are 'A' or 'B'.";
307             }
308              
309             # set control loop:
310 0           $loop = $self->query(
311             "CSET $loop, $channel, $units, $powerup, $display; CSET? $loop",
312             $tail
313             );
314              
315 0           my @loop = split( /, /, $loop );
316 0           return @loop;
317              
318             }
319              
320             sub get_control_loop {
321 0     0 0   my $self = shift;
322              
323 0           my ( $loop, $tail ) = $self->_check_args( \@_, ['loop'] );
324              
325 0 0 0       if ( not defined $loop ) {
    0          
326 0           $loop = 1;
327             }
328             elsif ( $loop != 1 and $loop != 2 ) {
329 0           die
330             "unexpected value ($loop) for LOOP in sub set_control_loop. Expected values are 1 or 2.";
331             }
332              
333 0           my $result = $self->query( "CSET? $loop", $tail );
334              
335 0           return split( /, /, $result );
336              
337             }
338              
339             sub set_input_curve {
340              
341 0     0 1   my $self = shift;
342              
343 0           my ( $channel, $curve, $tail )
344             = $self->_check_args( \@_, [ 'channel', 'curve' ] );
345              
346 0 0 0       if ( not defined $curve and not defined $channel ) {
    0 0        
    0          
347 0           die
348             "too fiew parameters given in sub set_input_curve. Expected parameters are CHANNEL and CURVE.";
349             }
350             elsif ( not $channel =~ /\b(A|a|B|b)\b/ ) {
351 0           die
352             "unexpected value ($channel) for CHANNEL in sub set_input_curve. Expected values are 'A' or 'B'.";
353             }
354             elsif ( $curve < 0 and $curve > 41 ) {
355 0           die
356             "unexpected value ($curve) for CURVE in sub set_input_curve. Expected values are between 0 ... 41.";
357             }
358 0           return $self->query("INCRV $channel,$curve; INCRV? $channel");
359             }
360              
361             sub get_input_curve {
362 0     0 0   my $self = shift;
363 0           my ( $channel, $tail ) = $self->_check_args( \@_, ['channel'] );
364              
365 0 0         if ( not $channel =~ /\b(A|a|B|b)\b/ ) {
366 0           die
367             "unexpected value ($channel) for CHANNEL in sub set_input_curve. Expected values are 'A' or 'B'.";
368             }
369              
370 0           return $self->query( "INCRV? $channel", $tail );
371             }
372              
373             sub set_remote {
374 0     0 0   my $self = shift;
375              
376 0           my ( $mode, $tail ) = $self->_check_args( \@_, ['mode'] );
377              
378 0 0         if ( not defined $mode ) {
    0          
    0          
    0          
379              
380             }
381             elsif ( $mode =~ /\b(LOCAL|local)\b/ ) {
382 0           $mode = 0;
383             }
384             elsif ( $mode =~ /\b(REMOTE|remote)\b/ ) {
385 0           $mode = 1;
386             }
387             elsif ( $mode =~ /\b(LOCK|lock)\b/ ) {
388 0           $mode = 2;
389             }
390             else {
391 0           die
392             "unexpected value ($mode) for MODE in sub set_remote. Expected values are between LOCAL, REMOTE and LOCK.";
393             }
394              
395 0           $mode = $self->query("MODE $mode; MODE?");
396              
397 0 0         if ( $mode == 0 ) {
    0          
    0          
398 0           $mode = "LOCAL";
399             }
400             elsif ( $mode == 1 ) {
401 0           $mode = "REMOTE";
402             }
403             elsif ( $mode == 2 ) {
404 0           $mode = "LOCK";
405             }
406              
407 0           return $mode;
408             }
409              
410             sub get_remote {
411 0     0 0   my $self = shift;
412              
413 0           my ($tail) = $self->_check_args( \@_, [] );
414              
415 0           my $mode = $self->query( "MODE?", $tail );
416              
417 0 0         if ( $mode == 0 ) {
    0          
    0          
418 0           $mode = "LOCAL";
419             }
420             elsif ( $mode == 1 ) {
421 0           $mode = "REMOTE";
422             }
423             elsif ( $mode == 2 ) {
424 0           $mode = "LOCK";
425             }
426              
427 0           return $mode;
428             }
429              
430             # Bin bis hier her gekommen
431              
432             sub set_PID {
433 0     0 1   my $self = shift;
434 0           my $P = shift;
435 0           my $I = shift;
436 0           my $D = shift;
437 0           my $loop = shift
438             ; # optinal parameter; Usually you alwas want to use control loop 1
439              
440 0 0 0       if ( not defined $loop
    0 0        
    0 0        
    0 0        
    0 0        
      0        
441             and not defined $D
442             and not defined $I
443             and not defined $P ) {
444 0           $loop = 1;
445 0           my $PID = $self->query("PID $loop, $P, $I, $D; PID?");
446 0           chomp $PID;
447 0           chomp $PID;
448 0           my @PID = split( /, /, $PID );
449              
450 0           return @PID;
451             }
452             elsif ( not defined $loop
453             and not defined $D
454             and not defined $I
455             and ( $P == 1 or $P == 2 ) ) {
456 0           $loop = $P;
457 0           my $PID = $self->query("PID $loop, $P, $I, $D; PID?");
458 0           chomp $PID;
459 0           chomp $PID;
460 0           my @PID = split( /, /, $PID );
461              
462 0           return @PID;
463             }
464             elsif ( not defined $loop and not defined $D ) {
465 0           die
466             "too fiew parameters given in sub set_PID. Expected parameters are P, I, D.";
467             }
468             elsif ( not defined $loop ) {
469 0           $loop = 1;
470             }
471             elsif ( $loop != 1 and $loop != 2 ) {
472 0           die
473             "unexpected value ($loop) for LOOP in sub set_PID. Expected values are between 1 and 2.";
474             }
475              
476             # else {
477             # die "unexpected values in sub set_PID.";
478             # }
479              
480 0 0 0       if ( $D < 0 or $D > 200 ) {
    0 0        
    0 0        
481 0           die
482             "unexpected value ($D) for D in sub set_PID. Expected values are between 0 and 200.";
483             }
484             elsif ( $I < 0.1 or $I > 1000 ) {
485 0           die
486             "unexpected value ($I) for I in sub set_PID. Expected values are between 0.1 and 1000.";
487             }
488             elsif ( $P < 0.1 or $P > 1000 ) {
489 0           die
490             "unexpected value ($P) for P in sub set_PID. Expected values are between 0.1 and 1000.";
491             }
492             else {
493 0           my $PID = $self->query("PID $loop, $P, $I, $D; PID? $loop");
494 0           chomp $PID;
495 0           chomp $PID;
496 0           my @PID = split( /, /, $PID );
497              
498 0           return @PID;
499             }
500              
501             }
502              
503             sub set_zone {
504              
505 0     0 0   my $self = shift;
506 0           my $zone = shift;
507 0           my $t_limit = shift;
508 0           my $P = shift;
509 0           my $I = shift;
510 0           my $D = shift;
511 0           my $range = shift;
512 0           my $man_output = shift; # optional parameter, usually zero
513 0           my $loop = shift
514             ; # optinal parameter; Usually you alwas want to use control loop 1
515              
516 0 0 0       if ( defined $zone and ( $zone < 1 or $zone > 10 ) ) {
      0        
517 0           die
518             "unexpected value ($zone) for ZONE in sub set_zone. Expected values are all integer values from 1 to 10.";
519             }
520              
521 0 0 0       if ( not defined $loop ) {
    0          
522 0           $loop = 1;
523             }
524             elsif ( $loop != 1 and $loop != 2 ) {
525 0           die
526             "unexpected value ($loop) for LOOP in sub set_zone. Expected values are 1 or 2.";
527             }
528              
529 0 0 0       if ( not defined $man_output ) {
    0          
530 0           $man_output = 0;
531             }
532             elsif ( $man_output < 0 or $man_output > 100 ) {
533 0           die
534             "unexpected value ($man_output) for MANUAL OUTPUT in sub set_zone. Expected values are between 0 ... 100 %.";
535             }
536              
537 0 0 0       if ( not defined $range
      0        
      0        
      0        
538             and not defined $D
539             and not defined $I
540             and not defined $P
541             and not defined $t_limit ) {
542 0           return;
543             }
544              
545 0 0         if ( not defined $range ) {
546 0           die
547             "too fiew parameters given for sub set_zone. Expected parameters are ZONE, T_LIMIT, P, I, D, RANGE and optional <MAN_OUTPUT> and <LOOP>.";
548             }
549              
550 0 0 0       if ( $t_limit < 0 or $t_limit > 300 ) {
    0 0        
    0 0        
    0 0        
551 0           die
552             "unexpected value ($t_limit) for T_LIMIT in sub set_zone. Expected values are between 0 and 300 K.";
553             }
554             elsif ( $D < 0 or $D > 200 ) {
555 0           die
556             "unexpected value ($D) for D in sub set_zone. Expected values are between 0 and 200.";
557             }
558             elsif ( $I < 0.1 or $I > 1000 ) {
559 0           die
560             "unexpected value ($I) for I in sub set_zone. Expected values are between 0.1 and 1000.";
561             }
562             elsif ( $P < 0.1 or $P > 1000 ) {
563 0           die
564             "unexpected value ($P) for P in sub set_zone. Expected values are between 0.1 and 1000.";
565             }
566              
567 0 0         if ( $range =~ /\b(OFF|off)\b/ ) {
    0          
    0          
    0          
568 0           $range = 0;
569             }
570             elsif ( $range =~ /\b(LOW|low)\b/ ) {
571 0           $range = 1;
572             }
573             elsif ( $range =~ /\b(MEDIUM|medium|MED|med)\b/ ) {
574 0           $range = 2;
575             }
576             elsif ( $range =~ /\b(HIGH|high)\b/ ) {
577 0           $range = 3;
578             }
579             else {
580 0           die
581             "unexpected value ($range) for RANGE in sub set_zone. Expected values are OFF, LOW, MEDIUM, HIGH.";
582             }
583              
584             # set zone:
585 0           $zone
586             = $self->query(
587             "ZONE $loop, $zone, $t_limit, $P, $I, $D, $man_output, $range; ZONE?"
588             );
589 0           chomp $zone;
590 0           chomp $zone;
591 0           my @zone = split( /, /, $zone );
592 0           return @zone;
593              
594             }
595              
596             sub set_heateroutput {
597              
598 0     0 0   my $self = shift;
599 0           my $output = shift;
600 0           my $loop = shift
601             ; # optinal parameter; Usually you alwas want to use control loop 1
602              
603 0 0 0       if ( not defined $loop ) {
    0          
604 0           $loop = 1;
605             }
606             elsif ( $loop != 1 and $loop != 2 ) {
607 0           die
608             "unexpected value ($loop) for LOOP in sub set_heater_output. Expected values are 1 or 2.";
609             }
610              
611 0 0 0       if ( not defined $output ) {
    0          
612 0           $output = $self->query("Mout? $loop");
613 0           chomp $output;
614 0           chomp $output;
615 0           return $output;
616             }
617             elsif ( $output >= 0 and $output <= 100 ) {
618 0           $output = $self->query("MOUT $loop, $output; Mout? $loop");
619 0           chomp $output;
620 0           chomp $output;
621 0           return $output;
622             }
623             else {
624 0           die
625             "unexpected value ($output) for OUTPUT in sub set_heater_output. Expected values are between 0 ... 100 % of full heater range.";
626             }
627              
628             }
629              
630             sub set_input_sensor {
631              
632 0     0 0   my $self = shift;
633 0           my $channel = shift;
634 0           my $sensor_type = shift;
635 0           my $compensation = shift;
636              
637             # check input parameter:
638              
639 0 0         if ( not defined $channel ) {
    0          
640 0           $channel = $self->query(
641             "INTYPE $channel, $sensor_type, $compensation; INTYPE? $channel");
642 0           chomp $channel;
643 0           chomp $channel;
644 0           my @channel = split( /, /, $channel );
645 0           return @channel;
646             }
647             elsif ( not $channel =~ /\b(A|a|B|b)\b/ ) {
648 0           die
649             "unexpected value ($channel) for CHANNEL in sub set_input_sensor. Expected values are 'A' or 'B'.";
650             }
651              
652 0 0 0       if ( not defined $sensor_type ) {
    0          
653              
654             # 0 = Silicon Diode
655             # 1 = GaAlAs Diode
656             # 2 = Platinum 100/250 O
657             # 3 = Platinum 100/500 O
658             # 4 = Platinum 1000 O
659             # 5 = NTC RTD 75mV 7.5 kO
660             # 6 = Thermocouple 25 mV
661             # 7 = Thermocouple 50 mV
662             # 8 = NTC RTD 75mV 75 O
663             # 9 = NTC RTD 75mV 750 O
664             # 10 = NTC RTD 75mV 7.5 kO
665             # 11 = NTC RTD 75mV 75 kO
666             # 12 = NTC RTD 75mV Auto
667              
668 0           $sensor_type = 12;
669              
670             }
671             elsif ( not( $sensor_type >= 1 and $sensor_type <= 12 ) ) {
672 0           die
673             "unexpected value ($sensor_type) for SENSOR_TYPE in sub set_input_sensor. Expected values are all integervalues between 0 ... 12.";
674             }
675              
676 0 0 0       if ( not defined $compensation ) {
    0          
    0          
    0          
677 0           $compensation = 0; # 0 == OFF, 1 == ON
678             }
679             elsif ( $compensation =~ /\b(ON|on)\b/ ) {
680 0           $compensation = 1;
681             }
682             elsif ( $compensation =~ /\b(OFF|off)\b/ ) {
683 0           $compensation = 0;
684             }
685             elsif ( $compensation != 0 and $compensation != 1 ) {
686 0           die
687             "unexpected value ($compensation) for COMPENSATION in sub set_input_sensor. Expected values are ON or OFF.";
688             }
689              
690             # set input sensor:
691              
692 0           $channel = $self->query(
693             "INTYPE $channel, $sensor_type, $compensation; INTYPE? $channel");
694 0           chomp $channel;
695 0           chomp $channel;
696 0           my @channel = split( /, /, $channel );
697 0           return @channel;
698              
699             }
700              
701             sub set_filter {
702              
703 0     0 0   my $self = shift;
704 0           my $channel = shift;
705 0           my $points = shift;
706 0           my $window = shift;
707              
708 0           my $active = 1; # set the filter active after changing parameters
709              
710             # check input paramters:
711 0 0 0       if ( defined $channel and not $channel =~ /\b(A|a|B|b)\b/ ) {
712 0           die
713             "unexpected value ($channel) for CHANNEL in sub set_filter. Expected values are between 'A' and 'B'.";
714             }
715              
716 0 0 0       if ( not defined $window
    0 0        
    0 0        
    0          
717             and not defined $points
718             and not defined $channel ) {
719 0           die
720             "too fiew parameters given. Expected parameters are CHANNEL, POINTS, <WINDOW>";
721             }
722             elsif ( not defined $window and not defined $points ) {
723 0           my $filter = $self->query("FILTER? $channel");
724 0           chomp $filter;
725 0           chomp $filter;
726              
727 0           my @filter = split( /, /, $filter );
728              
729 0 0         if ( $filter[0] == 0 ) {
730 0           $filter[0] = 'OFF';
731             }
732             else {
733 0           $filter[0] = 'ON';
734             }
735              
736 0           return @filter;
737              
738             }
739             elsif ( not defined $window ) {
740 0           $window = 1;
741             }
742             elsif ( $window < 1 or $window > 10 ) {
743 0           die
744             "unexpected value ($window) for WINDOW in sub set_filter. Expected values are between 1 .. 10 % of full scale reading limits.";
745             }
746              
747 0 0         if ( $points =~ /\b(OFF|off)\b/ ) {
748 0           my $filter = $self->query("FILTER? $channel");
749 0           chomp $filter;
750 0           chomp $filter;
751 0           my @filter = split( /, /, $filter );
752              
753 0           $active = 0;
754 0           $points = $filter[1];
755 0           $window = $filter[2];
756              
757             }
758 0 0 0       if ( $points < 2 or $points > 64 ) {
759 0           die
760             "unexpected value ($points) for POINTS in sub set_filter. Expected values are between 2 .. 64.";
761             }
762              
763             # set filter paramters:
764              
765 0           my $filter = $self->query(
766             "FILTER $channel,$active,$points,$window; FILTER? $channel");
767 0           chomp $filter;
768 0           chomp $filter;
769 0           my @filter = split( /, /, $filter );
770              
771 0 0         if ( $filter[0] == 0 ) {
772 0           $filter[0] = 'OFF';
773             }
774             else {
775 0           $filter[0] = 'ON';
776             }
777              
778 0           return @filter;
779              
780             }
781              
782             sub config_sweep {
783 0     0 1   my $self = shift;
784 0           my $setpoint = shift;
785 0           my $rate = shift;
786 0           my $loop = shift
787             ; # optinal parameter; Usually you alwas want to use control loop 1
788              
789 0 0 0       if ( not defined $loop ) {
    0          
790 0           $loop = 1;
791             }
792             elsif ( $loop != 1 and $loop != 2 ) {
793 0           die
794             "unexpected value ($loop) for LOOP in sub config_sweep. Expected values are 1 or 2.";
795             }
796              
797 0 0 0       if ( not defined $rate or $rate < 0.1 or $rate > 100 ) {
    0 0        
      0        
      0        
798 0           die
799             "unexpected value ($rate) for RATE in sub config_sweep. Expected values are between 0...100 K/min.";
800             }
801             elsif ( not defined $setpoint or $setpoint < 0 or $setpoint > 300 ) {
802 0           die
803             "unexpected value ($setpoint) for SETPOINT in sub config_sweep. Expected values are between 0...300 K.";
804             }
805              
806 0           $rate = $self->query("RAMP $loop,0,$rate; RAMP? $loop");
807 0           $setpoint = $self->query("SETP $loop,$setpoint; SETP? $loop");
808              
809 0           return $setpoint, $rate;
810              
811             }
812              
813             sub trg {
814 0     0 1   my $self = shift;
815 0           my $loop = shift
816             ; # optinal parameter; Usually you alwas want to use control loop 1
817              
818 0 0 0       if ( not defined $loop ) {
    0          
819 0           $loop = 1;
820             }
821             elsif ( $loop != 1 and $loop != 2 ) {
822 0           die
823             "unexpected value ($loop) for LOOP in sub trg. Expected values are 1 or 2.";
824             }
825              
826 0           my $rate = $self->query("RAMP? $loop");
827 0           $rate = $self->write("RAMP $loop,1,$rate");
828              
829 0           return 1;
830              
831             }
832              
833             sub halt {
834              
835 0     0 1   my $self = shift;
836 0           my $loop = shift
837             ; # optinal parameter; Usually you alwas want to use control loop 1
838              
839 0 0 0       if ( not defined $loop ) {
    0          
840 0           $loop = 1;
841             }
842             elsif ( $loop != 1 and $loop != 2 ) {
843 0           die
844             "unexpected value ($loop) for LOOP in sub halt. Expected values are 1 or 2.";
845             }
846              
847 0           my $rate = $self->query("RAMP? $loop");
848 0           $rate = $self->write("RAMP $loop,0,$rate");
849              
850             # get control loop channel
851 0           my @channel = $self->set_control_loop();
852 0           my $channel = $channel[0];
853              
854             # get current temperature
855 0           my $temperature_now = $self->get_T($channel);
856 0           $self->set_T($temperature_now);
857              
858             # stop sweeping
859 0           $rate = $self->write("RAMP $loop,0,0.1");
860              
861 0           return 1;
862             }
863              
864             sub active {
865              
866 0     0 1   my $self = shift;
867 0           my $loop = shift
868             ; # optinal parameter; Usually you alwas want to use control loop 1
869              
870 0 0 0       if ( not defined $loop ) {
    0          
871 0           $loop = 1;
872             }
873             elsif ( $loop != 1 and $loop != 2 ) {
874 0           die
875             "unexpected value ($loop) for LOOP in sub active. Expected values are 1 or 2.";
876             }
877              
878 0           my $status = $self->query('RAMPST? $loop');
879 0           chomp $status;
880 0           chomp $status;
881 0           return $status;
882             }
883              
884             sub wait {
885              
886 0     0 1   my $self = shift;
887 0           my $loop = shift
888             ; # optinal parameter; Usually you alwas want to use control loop 1
889              
890 0 0 0       if ( not defined $loop ) {
    0          
891 0           $loop = 1;
892             }
893             elsif ( $loop != 1 and $loop != 2 ) {
894 0           die
895             "unexpected value ($loop) for LOOP in sub active. Expected values are 1 or 2.";
896             }
897              
898 0           print "waiting for the temperature sweep to end.";
899 0           while ( $self->active() ) {
900 0           print $self->get_T('A') . ", " . $self->get_T('B') . "\n";
901             }
902              
903 0           return;
904              
905             }
906              
907             sub id {
908 0     0 1   my $self = shift;
909 0           $self->query('*IDN?');
910             }
911              
912             sub reset {
913              
914 0     0 0   my $self = shift;
915 0           $self->write("*RST");
916              
917             }
918              
919             sub factory_reset {
920              
921 0     0 0   my $self = shift;
922 0           $self->write("DFLT 99");
923              
924             }
925              
926             1;
927              
928             __END__
929              
930             =pod
931              
932             =encoding UTF-8
933              
934             =head1 NAME
935              
936             Lab::Instrument::Lakeshore33x - Lakeshore 33x Temperature controller
937              
938             =head1 VERSION
939              
940             version 3.880
941              
942             =head1 SYNOPSIS
943              
944             use Lab::Instrument::Lakeshore33x;
945             my $lake=new Lab::Instrument::Lakeshore33x($gpib_board,$gpib_address);
946              
947             $temp = $lake->get_T();
948             $r = $lake->get_R();
949              
950             .
951              
952             =head1 DESCRIPTION
953              
954             The Lab::Instrument::Lakeshore33x class implements an interface to the
955             Lakeshore 33x AC Resistance Bridge.
956              
957             .
958              
959             =head1 CONSTRUCTOR
960              
961             $lake=new Lab::Instrument::Lakeshore33x($gpib_board,$gpib_address);
962              
963             .
964              
965             =head1 METHODS
966              
967             =head2 get_T
968              
969             $t = $lake->get_T(<$channel>);
970              
971             Reads temperature in Kelvin (only possible if temperature curve is available, otherwise returns zero).
972              
973             =over 4
974              
975             =item $channel
976              
977             CHANNEL is an optinal parameter to select the sensor channel (A/B) for the measurement.
978             If not defined the default channel 'A' will be selected. Possible values are 'A' and 'B'.
979              
980             =back
981              
982             .
983              
984             =head2 get_R
985              
986             $t = $lake->get_R(<$channel>);
987              
988             Reads resistance in Ohm.
989              
990             =over 4
991              
992             =item $channel
993              
994             CHANNEL is an optinal parameter to select the sensor channel (A/B) for the measurement.
995             If not defined the default channel 'A' will be selected. Possible values are 'A' and 'B'.
996              
997             =back
998              
999             .
1000              
1001             =head2 set_T
1002              
1003             $sp = $lake->set_T($setpoint, <$loop>);
1004              
1005             Set new temperature SETPOINT for temperature control loop $loop. Returns the new setpoint.
1006             If no parameters are given, the currently valid SETPOINT will be returned.
1007              
1008             =over 4
1009              
1010             =item $setpoint
1011              
1012             New temperature Setpoint.
1013              
1014             =item $loop
1015              
1016             Optional prameter to select the temperature control loop for which the new setting will be valid.
1017             If not defined the default value $loop = 1 will be selected.
1018             Possible values are '1' and '2'.
1019              
1020             =back
1021              
1022             .
1023              
1024             =head2 set_range
1025              
1026             $heater_range = $lake->set_range($range);
1027              
1028             Set the HEATER RANGE.
1029              
1030             =over 4
1031              
1032             =item $range
1033              
1034             RANGE can be 'OFF', 'LOW', 'MEDIUM' or 'HIGH'.
1035              
1036             =back
1037              
1038             .
1039              
1040             =head2 set_input_curve
1041              
1042             $lake->set_input_curve($channel, $curve);
1043              
1044             Set for SENSOR CHANNEL $channel the resistance-to-temperatur CURVE with the internal storage number $curve.
1045              
1046             =over 4
1047              
1048             =item $channel
1049              
1050             CHANNEL selects the SENSOR CHANNEL and can be 'A' or 'B'.
1051              
1052             =item $curve
1053              
1054             CURVE reverse to one ov the internally stored resistance-to-temperatur CURVES and can be 0 .. 41.
1055              
1056             =back
1057              
1058             .
1059              
1060             =head2 set_PID
1061              
1062             @PID = $lake->set_PID($P,$I,$D);
1063              
1064             Set new values for the PID temperature control circuit.
1065              
1066             =over 4
1067              
1068             =item $P
1069              
1070             The PROPORTIONAL term, also called gain must have a value greater then zero for the control loop to operate. It's maximum value is 1000.
1071              
1072             =item $I
1073              
1074             The INTEGRAL term looks at error over time to build the integral contribution to the output. Values are 0.1 ... 1000.
1075              
1076             =item $D
1077              
1078             The DERIVATIVE term acts aon the change in error with time to make its contribution to the output. Values: 0 ... 200.
1079              
1080             =back
1081              
1082             .
1083              
1084             =head2 config_sweep
1085              
1086             $lake->config_sweep($setpoint, $rate);
1087              
1088             Predefine a temperature sweep.
1089              
1090             =over 4
1091              
1092             =item $setpoint
1093              
1094             Predefine the temperature target setpoint for a temperatue sweep. Values 0 .. 300 K.
1095              
1096             =item $rate
1097              
1098             Predefine sweep rate for a temperature sweep. Values 0.1 ... 100 K/minute.
1099              
1100             =back
1101              
1102             .
1103              
1104             =head2 trg
1105              
1106             $lake->trg();
1107              
1108             Start a predefined temperature sweep.
1109              
1110             =head2 halt
1111              
1112             $lake->halt();
1113              
1114             Stop running temperature sweep.
1115              
1116             =head2 active
1117              
1118             $lake->active();
1119              
1120             Returns 1 if a temperature sweep is running and 0 if not.
1121              
1122             =head2 wait
1123              
1124             $lake->wait();
1125              
1126             Wait until the currently active temperature sweep has been finished.
1127              
1128             =head2 id
1129              
1130             $id=$sr780->id();
1131              
1132             Returns the instruments ID string.
1133              
1134             .
1135              
1136             =head1 CAVEATS/BUGS
1137              
1138             probably many
1139              
1140             .
1141              
1142             =head1 SEE ALSO
1143              
1144             =over 4
1145              
1146             =item Lab::Instrument
1147              
1148             =back
1149              
1150             =head1 COPYRIGHT AND LICENSE
1151              
1152             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
1153              
1154             Copyright 2013-2014 Christian Butschkow
1155             2016 Simon Reinhardt
1156             2017 Andreas K. Huettel
1157             2019 Simon Reinhardt
1158             2020 Andreas K. Huettel
1159              
1160              
1161             This is free software; you can redistribute it and/or modify it under
1162             the same terms as the Perl 5 programming language system itself.
1163              
1164             =cut