| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Lab::Moose::Instrument::LinearStepSweep; | 
| 2 |  |  |  |  |  |  | $Lab::Moose::Instrument::LinearStepSweep::VERSION = '3.900'; | 
| 3 |  |  |  |  |  |  | #ABSTRACT: Role for linear step sweeps used by voltage/current sources. | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 7 |  |  | 7 |  | 4595 | use v5.20; | 
|  | 7 |  |  |  |  | 28 |  | 
| 6 | 7 |  |  | 7 |  | 44 | use Moose::Role; | 
|  | 7 |  |  |  |  | 27 |  | 
|  | 7 |  |  |  |  | 59 |  | 
| 7 | 7 |  |  | 7 |  | 37227 | use MooseX::Params::Validate; | 
|  | 7 |  |  |  |  | 22 |  | 
|  | 7 |  |  |  |  | 77 |  | 
| 8 | 7 |  |  | 7 |  | 3434 | use Lab::Moose::Instrument 'setter_params'; | 
|  | 7 |  |  |  |  | 23 |  | 
|  | 7 |  |  |  |  | 447 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | # time() returns floating seconds. | 
| 11 | 7 |  |  | 7 |  | 50 | use Time::HiRes qw/time usleep/; | 
|  | 7 |  |  |  |  | 22 |  | 
|  | 7 |  |  |  |  | 99 |  | 
| 12 | 7 |  |  | 7 |  | 1351 | use Lab::Moose 'linspace'; | 
|  | 7 |  |  |  |  | 18 |  | 
|  | 7 |  |  |  |  | 67 |  | 
| 13 | 7 |  |  | 7 |  | 72 | use Carp; | 
|  | 7 |  |  |  |  | 28 |  | 
|  | 7 |  |  |  |  | 4569 |  | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | requires qw/max_units_per_second max_units_per_step min_units max_units | 
| 16 |  |  |  |  |  |  | source_level cached_source_level source_level_timestamp/; | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | # Enforce max_units/min_units. | 
| 20 |  |  |  |  |  |  | sub check_max_and_min { | 
| 21 | 170 |  |  | 170 | 0 | 256 | my $self = shift; | 
| 22 | 170 |  |  |  |  | 248 | my $to   = shift; | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 170 |  |  |  |  | 5171 | my $min = $self->min_units(); | 
| 25 | 170 |  |  |  |  | 5103 | my $max = $self->max_units(); | 
| 26 | 170 | 50 |  |  |  | 565 | if ( $to < $min ) { | 
|  |  | 50 |  |  |  |  |  | 
| 27 | 0 |  |  |  |  | 0 | croak "target $to is below minimum allowed value $min"; | 
| 28 |  |  |  |  |  |  | } | 
| 29 |  |  |  |  |  |  | elsif ( $to > $max ) { | 
| 30 | 0 |  |  |  |  | 0 | croak "target $to is above maximum allowed value $max"; | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  | } | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | sub linear_step_sweep { | 
| 35 | 170 |  |  | 170 | 1 | 821 | my ( $self, %args ) = validated_hash( | 
| 36 |  |  |  |  |  |  | \@_, | 
| 37 |  |  |  |  |  |  | to      => { isa => 'Num' }, | 
| 38 |  |  |  |  |  |  | verbose => { isa => 'Bool', default => 1 }, | 
| 39 |  |  |  |  |  |  | setter_params(), | 
| 40 |  |  |  |  |  |  | ); | 
| 41 | 170 |  |  |  |  | 42252 | my $to             = delete $args{to}; | 
| 42 | 170 |  |  |  |  | 367 | my $verbose        = delete $args{verbose}; | 
| 43 | 170 |  |  |  |  | 629 | my $from           = $self->cached_source_level(); | 
| 44 | 170 |  |  |  |  | 6252 | my $last_timestamp = $self->source_level_timestamp(); | 
| 45 | 170 |  |  |  |  | 402 | my $distance       = abs( $to - $from ); | 
| 46 |  |  |  |  |  |  |  | 
| 47 | 170 |  |  |  |  | 539 | $self->check_max_and_min($to); | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 170 | 100 |  |  |  | 390 | if ( not defined $last_timestamp ) { | 
| 50 | 19 |  |  |  |  | 67 | $last_timestamp = time(); | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | # Enforce step size and rate. | 
| 54 | 170 |  |  |  |  | 5341 | my $step = abs( $self->max_units_per_step() ); | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 170 |  |  |  |  | 5393 | my $rate = abs( $self->max_units_per_second() ); | 
| 57 | 170 | 50 |  |  |  | 435 | if ( $step < 1e-9 ) { | 
| 58 | 0 |  |  |  |  | 0 | croak "step size must be > 0"; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 170 | 50 |  |  |  | 374 | if ( $rate < 1e-9 ) { | 
| 62 | 0 |  |  |  |  | 0 | croak "rate must be > 0"; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 170 |  |  |  |  | 599 | my @steps = linspace( | 
| 66 |  |  |  |  |  |  | from         => $from, to => $to, step => $step, | 
| 67 |  |  |  |  |  |  | exclude_from => 1 | 
| 68 |  |  |  |  |  |  | ); | 
| 69 |  |  |  |  |  |  |  | 
| 70 | 170 |  |  |  |  | 280 | my $time_per_step; | 
| 71 | 170 | 100 |  |  |  | 354 | if ( $distance < $step ) { | 
| 72 | 167 |  |  |  |  | 337 | $time_per_step = $distance / $rate; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  | else { | 
| 75 | 3 |  |  |  |  | 10 | $time_per_step = $step / $rate; | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  |  | 
| 78 | 170 |  |  |  |  | 520 | my $time = time(); | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 170 | 50 |  |  |  | 462 | if ( $time < $last_timestamp ) { | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # should never happen | 
| 83 | 0 |  |  |  |  | 0 | croak "time error"; | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | # Do we have to wait to enforce the maximum rate or can we start right now? | 
| 87 | 170 |  |  |  |  | 320 | my $waiting_time = $time_per_step - ( $time - $last_timestamp ); | 
| 88 | 170 | 100 |  |  |  | 416 | if ( $waiting_time > 0 ) { | 
| 89 | 3 |  |  |  |  | 25784 | usleep( 1e6 * $waiting_time ); | 
| 90 |  |  |  |  |  |  | } | 
| 91 | 170 |  |  |  |  | 775 | $self->source_level( value => shift @steps, %args ); | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | # enable autoflush | 
| 94 | 170 |  |  |  |  | 863 | my $autoflush = STDOUT->autoflush(); | 
| 95 | 170 |  |  |  |  | 6239 | for my $step (@steps) { | 
| 96 | 36 |  |  |  |  | 365446 | usleep( 1e6 * $time_per_step ); | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | #  YokogawaGS200 has 5 + 1/2 digits precision | 
| 99 | 36 | 50 |  |  |  | 355 | if ($verbose) { | 
| 100 | 0 |  |  |  |  | 0 | printf( | 
| 101 |  |  |  |  |  |  | "Sweeping to %.5g: Setting level to %.5e          \r", $to, | 
| 102 |  |  |  |  |  |  | $step | 
| 103 |  |  |  |  |  |  | ); | 
| 104 |  |  |  |  |  |  | } | 
| 105 | 36 |  |  |  |  | 318 | $self->source_level( value => $step, %args ); | 
| 106 |  |  |  |  |  |  | } | 
| 107 | 170 | 50 |  |  |  | 432 | if ($verbose) { | 
| 108 | 0 |  |  |  |  | 0 | print " " x 70 . "\r"; | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | # reset autoflush to previous value | 
| 112 | 170 |  |  |  |  | 567 | STDOUT->autoflush($autoflush); | 
| 113 | 170 |  |  |  |  | 11093 | $self->source_level_timestamp( time() ); | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | 1; | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | __END__ | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | =pod | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | =encoding UTF-8 | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =head1 NAME | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | Lab::Moose::Instrument::LinearStepSweep - Role for linear step sweeps used by voltage/current sources. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =head1 VERSION | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | version 3.900 | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | =head1 METHODS | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | =head2 linear_step_sweep | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | $source->linear_step_sweep( | 
| 138 |  |  |  |  |  |  | to => $new_level, | 
| 139 |  |  |  |  |  |  | timeout => $timeout # optional | 
| 140 |  |  |  |  |  |  | ); | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | =head1 REQUIRED METHODS | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | The following methods are required for role consumption: | 
| 145 |  |  |  |  |  |  | C<max_units_per_second, max_units_per_step, min_units, max_units, | 
| 146 |  |  |  |  |  |  | source_level, cached_source_level, source_level_timestamp > | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | This software is copyright (c) 2023 by the Lab::Measurement team; in detail: | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | Copyright 2017-2018  Simon Reinhardt | 
| 153 |  |  |  |  |  |  | 2020       Andreas K. Huettel | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 157 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | =cut |