File Coverage

blib/lib/Lab/Moose/Instrument/KeysightB2901A.pm
Criterion Covered Total %
statement 37 49 75.5
branch n/a
condition n/a
subroutine 14 17 82.3
pod 5 10 50.0
total 56 76 73.6


line stmt bran cond sub pod time code
1             package Lab::Moose::Instrument::KeysightB2901A;
2             $Lab::Moose::Instrument::KeysightB2901A::VERSION = '3.881';
3             #ABSTRACT: Agilent/Keysight B2901A voltage/current sourcemeter.
4              
5 2     2   2913 use v5.20;
  2         8  
6              
7              
8 2     2   12 use Moose;
  2         4  
  2         17  
9 2     2   15786 use MooseX::Params::Validate;
  2         5  
  2         22  
10             use Lab::Moose::Instrument
11 2     2   1054 qw/validated_getter validated_setter setter_params/;
  2         5  
  2         136  
12 2     2   596 use Lab::Moose::Instrument::Cache;
  2         6  
  2         28  
13 2     2   1675 use Carp;
  2         7  
  2         149  
14 2     2   17 use namespace::autoclean;
  2         6  
  2         14  
15              
16             extends 'Lab::Moose::Instrument';
17              
18             has [qw/max_units_per_second max_units_per_step min_units max_units/] =>
19             ( is => 'ro', isa => 'Num', required => 1 );
20              
21             has source_level_timestamp => (
22             is => 'rw',
23             isa => 'Num',
24             init_arg => undef,
25             );
26              
27             has verbose => (
28             is => 'ro',
29             isa => 'Bool',
30             default => 1
31             );
32              
33             sub BUILD {
34 1     1 0 6 my $self = shift;
35              
36 1         11 $self->clear();
37 1         10 $self->cls();
38             }
39              
40             around default_connection_options => sub {
41             my $orig = shift;
42             my $self = shift;
43             my $options = $self->$orig();
44             my $usb_opts = {
45             vid => 0x0957, pid => 0x8b18, # Agilent vid!
46             reset_device => 0
47             , # Problem of the B2901A: https://community.keysight.com/thread/36706
48             };
49             $options->{USB} = $usb_opts;
50             $options->{'VISA::USB'} = $usb_opts;
51             return $options;
52             };
53              
54              
55             sub source_function_query {
56 2     2 0 1589 my ( $self, %args ) = validated_getter( \@_ );
57              
58 2         1010 my $value = $self->query( command => "SOUR:FUNC:MODE?", %args );
59 2         7 $value =~ s/["']//g;
60 2         8 return $self->cached_source_function($value);
61             }
62              
63             sub source_function {
64 2     2 0 5127 my ( $self, $value, %args ) = validated_setter( \@_ );
65 2         14 $self->write( command => "SOUR:FUNC:MODE $value", %args );
66 2         12 $self->cached_source_function($value);
67             }
68              
69             # Concurrent sense is always ON for the B2901A
70             sub sense_function_concurrent_query {
71 1     1 0 4 return 1;
72             }
73              
74             sub sense_function_concurrent {
75 0     0 0 0 croak "Concurrent sense is always ON";
76             }
77              
78              
79             sub set_level {
80 1     1 1 18 my ( $self, $value, %args ) = validated_setter(
81             \@_,
82             value => { isa => 'Num' },
83             );
84              
85 1         40 return $self->linear_step_sweep(
86             to => $value, verbose => $self->verbose,
87             %args
88             );
89             }
90              
91              
92             sub get_measurement {
93 0     0 1 0 my ( $self, %args ) = validated_getter( \@_ );
94 0         0 my $meas = $self->query( command => ':MEAS?', %args );
95 0         0 my $elements = $self->query( command => ':FORM:ELEM:SENS?' );
96 0         0 my @elements = split /,/, $elements;
97 0         0 my @meas_values = split /,/, $meas;
98 0         0 my %result = map { $_ => shift @meas_values } @elements;
  0         0  
99 0         0 return \%result;
100             }
101              
102             #
103             # Aliases for Lab::XPRESS::Sweep API
104             #
105              
106              
107             sub cached_level {
108 1     1 1 11 my $self = shift;
109 1         8 return $self->cached_source_level(@_);
110             }
111              
112              
113             sub get_level {
114 1     1 1 4 my $self = shift;
115 1         7 return $self->source_level_query(@_);
116             }
117              
118              
119             sub set_voltage {
120 0     0 1   my $self = shift;
121 0           my $value = shift;
122 0           return $self->set_level( value => $value );
123             }
124              
125             with qw(
126             Lab::Moose::Instrument::Common
127             Lab::Moose::Instrument::SCPI::Sense::Function::Concurrent
128             Lab::Moose::Instrument::SCPI::Sense::Protection
129             Lab::Moose::Instrument::SCPI::Sense::Range
130             Lab::Moose::Instrument::SCPI::Sense::NPLC
131             Lab::Moose::Instrument::SCPI::Source::Function
132             Lab::Moose::Instrument::SCPI::Source::Level
133             Lab::Moose::Instrument::SCPI::Source::Range
134             Lab::Moose::Instrument::LinearStepSweep
135             );
136              
137             after source_level => sub {
138             my $self = shift;
139              
140             # B2901A (with GPIB) accepts "SOUR:VOLT:LEV" in a faster rate than
141             # it can set the value. Slow it down by doing a query after each set.
142             $self->source_level_query();
143             };
144              
145             __PACKAGE__->meta()->make_immutable();
146              
147             1;
148              
149             __END__
150              
151             =pod
152              
153             =encoding UTF-8
154              
155             =head1 NAME
156              
157             Lab::Moose::Instrument::KeysightB2901A - Agilent/Keysight B2901A voltage/current sourcemeter.
158              
159             =head1 VERSION
160              
161             version 3.881
162              
163             =head1 SYNOPSIS
164              
165             use Lab::Moose;
166              
167             my $source = instrument(
168             type => 'KeysightB2901A',
169             connection_type => 'LinuxGPIB',
170             connection_options => {gpib_address => 15},
171             # mandatory protection settings
172             max_units_per_step => 0.001, # max step is 1mV/1mA
173             max_units_per_second => 0.01,
174             min_units => -10,
175             max_units => 10,
176             );
177              
178             ### Sourcing
179              
180              
181             # Source voltage
182             $source->source_function(value => 'VOLT');
183             $source->source_range(value => 210);
184            
185             # Step-sweep to new level.
186             # Stepsize and speed is given by (max|min)_units* settings.
187             $source->set_level(value => 9);
188              
189             # Get current level from device cache (without sending a query to the
190             # instrument):
191             my $level = $source->cached_level();
192              
193             ### Measurement
194              
195             The B2901A provides a concurrent SENSE subsystem. See also L<Lab::Moose::Instrument::SCPI::Sense::Function::Concurrent>.
196              
197             # Measure current
198             $source->sense_function_on(value => ['CURR']);
199             $source->sense_function(value => 'CURR');
200             # Set measurement range to 100nA
201             $source->sense_range(value => 100e-9);
202             # Use measurement integration time of 2 NPLC
203             $source->sense_nplc(value => 2);
204             # Set compliance limit to 10nA
205             $source->sense_protection(value => 10e-9);
206            
207             # Get measurement sample
208             my $sample = $source->get_measurement();
209             my $current = $sample->{CURR};
210             # print all entries in sample (Voltage, Current, Resistance, Timestamp):
211             use Data::Dumper;
212             print Dumper $sample;
213              
214             =head1 NOTES
215              
216             There are problems with the USB connection:
217             L<https://community.keysight.com/thread/36706>. GPIB works fine.
218              
219             =head1 METHODS
220              
221             Used roles:
222              
223             =over
224              
225             =item L<Lab::Moose::Instrument::Common>
226              
227             =item L<Lab::Moose::Instrument::SCPI::Sense::Function::Concurrent>
228              
229             =item L<Lab::Moose::Instrument::SCPI::Sense::Protection>
230              
231             =item L<Lab::Moose::Instrument::SCPI::Sense::Range>
232              
233             =item L<Lab::Moose::Instrument::SCPI::Sense::NPLC>
234              
235             =item L<Lab::Moose::Instrument::SCPI::Source::Function>
236              
237             =item L<Lab::Moose::Instrument::SCPI::Source::Level>
238              
239             =item L<Lab::Moose::Instrument::SCPI::Source::Range>
240              
241             =item L<Lab::Moose::Instrument::LinearStepSweep>
242              
243             =back
244              
245             =head2 set_level
246              
247             $source->set_level(value => $new_level);
248              
249             Go to new level. Sweep with multiple steps if the distance between current and
250             new level is larger than C<max_units_per_step>.
251              
252             =head2 get_measurement
253              
254             my $sample = $source->get_measurement();
255             my $current = $sample->{CURR};
256              
257             Do new measurement and return sample hashref of measured elements.
258              
259             =head2 cached_level
260              
261             my $current_level = $source->cached_level();
262              
263             Get current value from device cache.
264              
265             =head2 get_level
266              
267             my $current_level = $source->get_level();
268              
269             Query current level.
270              
271             =head2 set_voltage
272              
273             $source->set_voltage($value);
274              
275             For XPRESS voltage sweep. Equivalent to C<< set_level(value => $value) >>.
276              
277             =head1 COPYRIGHT AND LICENSE
278              
279             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
280              
281             Copyright 2018-2019 Simon Reinhardt
282             2020 Andreas K. Huettel
283              
284              
285             This is free software; you can redistribute it and/or modify it under
286             the same terms as the Perl 5 programming language system itself.
287              
288             =cut