line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Tribology::Lubricant; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Tribology::Lubricant - Data type that represents a Lubricant class. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 DESCRIPTION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
This class, given technical data based on lubricant TDS/PDS documents assists in calculation of various Rheologic characteristics of the lubricant. Such as: |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=over 4 |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=item * |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
V-T behavior (C) using B equation |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=item * |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Calculate viscosity at a given temperature ( C ) when any of two calibration points are known |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=item * |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Calculate viscosity index using ASTM D2270's B and B procedures ( C ) |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=item * |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
Lookup B and B constants of the lubricant using ASTM D2270 Table and using linear interoplation whenever neccessary ( C ) |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=back |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 SYNOPSIS |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
require Tribology::Lubricant; |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# We already have viscosity at 40C and 100C. |
36
|
|
|
|
|
|
|
my $lub = Tribology::Lubricant->new({ |
37
|
|
|
|
|
|
|
label => "Naphthenic spindle oil", |
38
|
|
|
|
|
|
|
visc40 => 30, |
39
|
|
|
|
|
|
|
visc100 => 100 |
40
|
|
|
|
|
|
|
}); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Viscosity @ 50C: |
43
|
|
|
|
|
|
|
my $visc50 = $lub->visc(50); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Viscosity index (VI) |
46
|
|
|
|
|
|
|
my $vi = $lub->vi; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Viscosity-temperature constant: |
49
|
|
|
|
|
|
|
my $vtc = $lub->vtc; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# m-value, aka V-T behavior coefficient |
52
|
|
|
|
|
|
|
my $m = $lub->m; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# To draw the V-T (hyperbolic) graph of this particular lubricant we can generate data-points, say, from -20 to +100: |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
my @data_points; |
57
|
|
|
|
|
|
|
for my $T(-20..100) { |
58
|
|
|
|
|
|
|
push @data_points, [$T, $lub->visc($T)]; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Now you may pass @data_points to either GDGrap(Perl) or Highcharts(JS). |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=cut |
64
|
|
|
|
|
|
|
|
65
|
1
|
|
|
1
|
|
55584
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
22
|
|
66
|
1
|
|
|
1
|
|
3
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
18
|
|
67
|
1
|
|
|
1
|
|
3
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1389
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
our $VERSION = '0.03'; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head2 new(\%attr) |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Constructor. Following attributes (all optional) can be passed: |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=over 4 |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item label |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
Arbitrary label of the lubricant. Used in graph data or report tables, charts |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item visc40, visc100 |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Viscosity @ 40 and 100 degrees Celcius. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item vi |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Viscosity index of the lubricant. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item density |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Specific gravity of the lubricant at a given temperature point. Must be passed a hashref of Temprature-Density values. Density |
92
|
|
|
|
|
|
|
must be in kg/cm3. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=back |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
B C and C are just convenience attributes, since they are most widely given in product TDSs. |
97
|
|
|
|
|
|
|
If you don't have calibration points at these temperatures IGNORE these attributes. Instead, |
98
|
|
|
|
|
|
|
create empty constructor, set the calibration values you already have using C method. Such as: |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
my $lubricant = Tribology::Lubricant->new({label => "Hypothetical lubricant"}); |
101
|
|
|
|
|
|
|
$lubricant->visc(50, 80); |
102
|
|
|
|
|
|
|
$lubricant->visc(100, 5.23); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=cut |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub new { |
107
|
9
|
|
|
9
|
1
|
1961
|
my ( $class, $arg ) = @_; |
108
|
|
|
|
|
|
|
|
109
|
9
|
|
100
|
|
|
26
|
$arg ||= {}; |
110
|
|
|
|
|
|
|
|
111
|
9
|
|
|
|
|
34
|
my %internals = ( |
112
|
|
|
|
|
|
|
__visc_calibration_points => {}, |
113
|
|
|
|
|
|
|
%$arg |
114
|
|
|
|
|
|
|
); |
115
|
|
|
|
|
|
|
|
116
|
9
|
100
|
|
|
|
26
|
if ( defined( $internals{visc40} ) ) { |
117
|
7
|
|
|
|
|
14
|
$internals{__visc_calibration_points}{40} = $internals{visc40}; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
9
|
50
|
|
|
|
25
|
if ( defined $internals{visc100} ) { |
121
|
0
|
|
|
|
|
0
|
$internals{__visc_calibration_points}{100} = $internals{visc100}; |
122
|
|
|
|
|
|
|
} |
123
|
9
|
|
|
|
|
26
|
return bless( \%internals, $class ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=head2 label($new_label) |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Returns and/or sets label of the lubricant |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=cut |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub label { |
133
|
16
|
|
|
16
|
1
|
250
|
my ( $self, $new_label ) = @_; |
134
|
|
|
|
|
|
|
|
135
|
16
|
50
|
|
|
|
25
|
if ($new_label) { |
136
|
0
|
|
|
|
|
0
|
$self->{label} = $new_label; |
137
|
|
|
|
|
|
|
} |
138
|
16
|
|
|
|
|
49
|
return $self->{label}; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 visc($T, $cst) |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Given temperature ($T) in celcius returns kinematic viscosity in cst. If such value was not given to the constructor it attempts to calculate |
144
|
|
|
|
|
|
|
this number using B equation. For this to be possible at least two calibration points must be given to C or two calibration |
145
|
|
|
|
|
|
|
points must be set using two-argument syntax of C. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
If second argument is passed sets the viscosity point and returns the value $cst as is. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# 1.10 (eni), bo'yi ( 2.27 ) |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub visc { |
154
|
7127
|
|
|
7127
|
1
|
336930
|
my ( $self, $T, $cst ) = @_; |
155
|
|
|
|
|
|
|
|
156
|
7127
|
50
|
|
|
|
8583
|
unless ( defined $T ) { |
157
|
0
|
|
|
|
|
0
|
croak "visc(): usage error"; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
7127
|
100
|
|
|
|
7794
|
if ( defined $cst ) { |
161
|
18
|
|
|
|
|
36
|
$self->{__visc_calibration_points}{$T} = $cst; |
162
|
18
|
|
|
|
|
45
|
return $cst; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# If this calibration point was already given just return it: |
166
|
7109
|
100
|
|
|
|
10464
|
if ( my $visc = $self->{__visc_calibration_points}{$T} ) { |
167
|
5715
|
|
|
|
|
19438
|
return $visc; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# We have to attempt to calculate the viscosity at this given temp |
171
|
|
|
|
|
|
|
|
172
|
1394
|
|
|
|
|
1216
|
my @calibrations = @{ $self->__calibration_points(2) }; |
|
1394
|
|
|
|
|
2042
|
|
173
|
1393
|
50
|
|
|
|
2402
|
unless ( scalar(@calibrations) == 2 ) { |
174
|
0
|
|
|
|
|
0
|
croak "visc(): Not enough calibration points to complete Ubbelohde-Walter equation"; |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
1393
|
|
|
|
|
1496
|
my $c1_temp = $calibrations[0][0]; |
178
|
1393
|
|
|
|
|
1279
|
my $c1_cst = $calibrations[0][1]; |
179
|
|
|
|
|
|
|
|
180
|
1393
|
|
|
|
|
1110
|
my $c2_temp = $calibrations[1][0]; |
181
|
1393
|
|
|
|
|
1330
|
my $c2_cst = $calibrations[1][1]; |
182
|
|
|
|
|
|
|
|
183
|
1393
|
|
|
|
|
1911
|
my $vtc = $self->vtc; |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
#my $b = ( log( log( $c1_cst + $vtc ) ) - log( log( $c2_cst + $vtc ) ) ) / ( log($c2_temp) - log($c1_temp) ); |
186
|
1393
|
|
|
|
|
1892
|
my $m = $self->m; |
187
|
1393
|
|
|
|
|
2695
|
my $a = log( log( $c2_cst + $vtc ) / log(10) ) / log(10) + ( $m * log($c2_temp) / log(10) ); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
#carp "\$c2_cst = $c2_cst"; |
190
|
|
|
|
|
|
|
#carp "\$c2_temp = $c2_temp"; |
191
|
|
|
|
|
|
|
#carp "\$a = $a"; |
192
|
|
|
|
|
|
|
#carp "\$m = $m"; |
193
|
|
|
|
|
|
|
#carp "\$vtc = $vtc"; |
194
|
|
|
|
|
|
|
|
195
|
1393
|
|
|
|
|
1313
|
my $c = $a * 100; |
196
|
1393
|
|
|
|
|
1181
|
my $d = $m * 25; |
197
|
|
|
|
|
|
|
|
198
|
1393
|
|
|
|
|
1824
|
my $visc = exp(1)**( log(10) * exp(1)**( ( ( $c * log(10) ) / 100 ) - ( ( $d * log( __c2k($T) ) ) / 25 ) ) ) - 0.7; |
199
|
|
|
|
|
|
|
|
200
|
1393
|
|
|
|
|
2735
|
$self->{__visc_calibration_points}{$T} = $visc; |
201
|
1393
|
|
|
|
|
2947
|
return $visc; |
202
|
|
|
|
|
|
|
} ## end sub visc |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 m() |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Heart of the B equation. This is the coeffient that characterises V-T behavior of oils. It's a double-logarithmic V-T graph slope. |
207
|
|
|
|
|
|
|
It requires at least two calibration points be present, or must be calculatable to work. Otherwise it throws error (croaks). |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=cut |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub m { |
212
|
1407
|
|
|
1407
|
1
|
1301
|
my $self = shift; |
213
|
|
|
|
|
|
|
|
214
|
1407
|
|
|
|
|
1534
|
my $calibrations = $self->__calibration_points(2); |
215
|
|
|
|
|
|
|
|
216
|
1407
|
50
|
|
|
|
2043
|
unless ( scalar @$calibrations == 2 ) { |
217
|
0
|
|
|
|
|
0
|
croak "m(): at least 2 calibration points are required to properly calculate V-T slope (m)."; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
1407
|
|
|
|
|
1384
|
my $c1_temp = $calibrations->[0][0]; |
221
|
1407
|
|
|
|
|
1253
|
my $c1_cst = $calibrations->[0][1]; |
222
|
|
|
|
|
|
|
|
223
|
1407
|
|
|
|
|
1192
|
my $c2_temp = $calibrations->[1][0]; |
224
|
1407
|
|
|
|
|
1381
|
my $c2_cst = $calibrations->[1][1]; |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
#carp "c1_temp = $c1_temp\nc1_cst=$c1_cst\n"; |
227
|
|
|
|
|
|
|
#carp "c2_temp = $c2_temp\nc2_cst=$c2_cst\n"; |
228
|
|
|
|
|
|
|
|
229
|
1407
|
|
|
|
|
1610
|
my $vtc = $self->vtc; |
230
|
1407
|
|
|
|
|
5109
|
return ( log( log( $c1_cst + $vtc ) ) - log( log( $c2_cst + $vtc ) ) ) / ( log($c2_temp) - log($c1_temp) ) ; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head2 LH() |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Returns B and B values for the given lubricant. For this method to work lubricant's viscosity @ 100C must be known or calculatable. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=cut |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub LH { |
240
|
31
|
|
|
31
|
1
|
42
|
my ($self) = @_; |
241
|
|
|
|
|
|
|
|
242
|
31
|
|
|
|
|
42
|
my $cst100 = $self->visc(100); |
243
|
31
|
50
|
|
|
|
47
|
unless ($cst100) { |
244
|
0
|
|
|
|
|
0
|
croak "__LH(): Viscosity of the lubricant \@ 100C is unknown. Cannot proceed further"; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
31
|
50
|
|
|
|
60
|
if ( $cst100 < 2 ) { |
248
|
0
|
|
|
|
|
0
|
croak "__LH(): ASTM D2270 does not define VI for lubricants below 2cst \@ 100C"; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
31
|
100
|
|
|
|
58
|
if ( $cst100 > 70 ) { |
252
|
1
|
|
|
|
|
5
|
my $L = ( 0.8353 * ( $cst100**2 ) ) + 14.67 * $cst100 - 216; |
253
|
1
|
|
|
|
|
3
|
my $H = ( 0.1684 * ( $cst100**2 ) ) + 11.85 * $cst100 - 97; |
254
|
1
|
|
|
|
|
3
|
return ( $L, $H ); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
30
|
|
|
|
|
31
|
my ( @one_before, @one_after ); |
258
|
30
|
|
|
|
|
330
|
seek( DATA, 0, 0 ); |
259
|
30
|
|
|
|
|
504
|
while ( my $line = ) { |
260
|
17745
|
50
|
|
|
|
18623
|
next unless length($line); |
261
|
17745
|
100
|
|
|
|
19082
|
next if $line =~ m/^#/; |
262
|
17625
|
100
|
|
|
|
26637
|
next if $line =~ m/^\s*$/; |
263
|
|
|
|
|
|
|
|
264
|
12945
|
|
|
|
|
19860
|
my ( $visc, $L, $H ) = $line =~ m/^ |
265
|
|
|
|
|
|
|
([\d\.]+) \s+ ([\d\.]+) \s+ ([\d\.]+) |
266
|
|
|
|
|
|
|
\s* $/x; |
267
|
|
|
|
|
|
|
|
268
|
12945
|
50
|
66
|
|
|
25544
|
next unless ( $visc && $L && $H ); |
|
|
|
66
|
|
|
|
|
269
|
3225
|
100
|
|
|
|
4913
|
return ( $L, $H ) if ( $visc == $cst100 ); |
270
|
3212
|
100
|
|
|
|
3533
|
if ( $visc < $cst100 ) { |
271
|
3195
|
|
|
|
|
5173
|
@one_before = ( $visc, $L, $H ); |
272
|
3195
|
|
|
|
|
5483
|
next; |
273
|
|
|
|
|
|
|
} |
274
|
17
|
50
|
|
|
|
24
|
if ( $visc > $cst100 ) { |
275
|
17
|
|
|
|
|
27
|
push @one_after, $visc, $L, $H; |
276
|
17
|
|
|
|
|
19
|
last; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
17
|
50
|
33
|
|
|
37
|
unless ( @one_before && @one_after ) { |
281
|
0
|
|
|
|
|
0
|
croak "__LH(): has nothing to interoplate"; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
17
|
|
|
|
|
22
|
my $visc1 = $one_before[0]; |
285
|
17
|
|
|
|
|
15
|
my $visc2 = $one_after[0]; |
286
|
17
|
|
|
|
|
23
|
my $visc_delta = $visc2 - $visc1; |
287
|
|
|
|
|
|
|
|
288
|
17
|
|
|
|
|
17
|
my $L1 = $one_before[1]; |
289
|
17
|
|
|
|
|
16
|
my $L2 = $one_after[1]; |
290
|
17
|
|
|
|
|
31
|
my $L_delta = $L2 - $L1; |
291
|
|
|
|
|
|
|
|
292
|
17
|
|
|
|
|
18
|
my $H1 = $one_before[2]; |
293
|
17
|
|
|
|
|
18
|
my $H2 = $one_after[2]; |
294
|
17
|
|
|
|
|
20
|
my $H_delta = $H2 - $H1; |
295
|
|
|
|
|
|
|
|
296
|
17
|
|
|
|
|
18
|
my $L1_per_unit = $L_delta / $visc_delta; |
297
|
17
|
|
|
|
|
15
|
my $H1_per_unit = $H_delta / $visc_delta; |
298
|
|
|
|
|
|
|
|
299
|
17
|
|
|
|
|
20
|
my $L = $L1 + ( ( $cst100 - $visc1 ) * $L1_per_unit ); |
300
|
17
|
|
|
|
|
18
|
my $H = $H1 + ( ( $cst100 - $visc1 ) * $H1_per_unit ); |
301
|
|
|
|
|
|
|
|
302
|
17
|
|
|
|
|
46
|
return ( $L, $H ); |
303
|
|
|
|
|
|
|
} ## end sub LH |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub data_table { |
307
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
0
|
my @data = (); |
310
|
0
|
|
|
|
|
0
|
seek( DATA, 0, 0 ); |
311
|
0
|
|
|
|
|
0
|
while ( my $line = ) { |
312
|
0
|
0
|
|
|
|
0
|
next unless length($line); |
313
|
0
|
0
|
|
|
|
0
|
next if $line =~ m/^#/; |
314
|
0
|
0
|
|
|
|
0
|
next if $line =~ m/^\s*$/; |
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
0
|
my ( $visc, $L, $H ) = $line =~ m/^ |
317
|
|
|
|
|
|
|
([\d\.]+) \s+ ([\d\.]+) \s+ ([\d\.]+) |
318
|
|
|
|
|
|
|
\s* $/x; |
319
|
|
|
|
|
|
|
|
320
|
0
|
0
|
0
|
|
|
0
|
next unless ( $visc && $L && $H ); |
|
|
|
0
|
|
|
|
|
321
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
0
|
push @data, [$visc, $L, $H]; |
323
|
|
|
|
|
|
|
} |
324
|
0
|
|
|
|
|
0
|
return \@data; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=head2 vi() |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Returns viscosity index of the lubricant, if such is possible. Remember, for this to be possible |
330
|
|
|
|
|
|
|
calibration points at 40C and 100C must be available or calculatble. If it's impossible, it returns undef and writes a warning |
331
|
|
|
|
|
|
|
to STDERR. When checking for error you must check for C at return. |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=cut |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub vi { |
336
|
17
|
|
|
17
|
1
|
60
|
my ($self) = @_; |
337
|
|
|
|
|
|
|
|
338
|
17
|
|
|
|
|
30
|
my $vi = $self->__vi_lt_100; |
339
|
16
|
100
|
|
|
|
35
|
if ( $vi > 100 ) { |
340
|
12
|
|
|
|
|
30
|
$vi = $self->__vi_gt_100; |
341
|
|
|
|
|
|
|
} |
342
|
16
|
|
|
|
|
54
|
return $vi; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
sub log10 { |
346
|
36
|
|
|
36
|
0
|
43
|
my ($n) = @_; |
347
|
36
|
|
|
|
|
77
|
return ( log($n) / log(10) ); |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 vtc() |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Returns B used in B equation to better differentiate V-T behavior |
353
|
|
|
|
|
|
|
when the influence of temperature is low. This constant must be used to accurately (or properly) calculate C. |
354
|
|
|
|
|
|
|
To calculate this value properly we need to have calibration points at 40C and 100C. If either of these points are missing |
355
|
|
|
|
|
|
|
C defaults to 0.8. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
=cut |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub vtc { |
360
|
2816
|
|
|
2816
|
1
|
2648
|
my $self = shift; |
361
|
|
|
|
|
|
|
|
362
|
2816
|
|
|
|
|
2714
|
my $visc40 = $self->{__visc_calibration_points}{40}; |
363
|
2816
|
|
|
|
|
2587
|
my $visc100 = $self->{__visc_calibration_points}{100}; |
364
|
|
|
|
|
|
|
|
365
|
2816
|
100
|
66
|
|
|
6446
|
return 0.8 unless ( $visc40 && $visc100 ); |
366
|
2815
|
|
|
|
|
5864
|
return ( $visc40 - $visc100 ) / $visc40 ; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=head2 is_mineral |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
Based on the C constant or C attempts to guess if current instance represents a mineral oil. |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=cut |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
sub is_mineral { |
376
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
377
|
0
|
|
|
|
|
0
|
my $vi = $self->vi; |
378
|
0
|
|
|
|
|
0
|
die "work in progress"; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 INTERNALS |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head2 __c2k($T) |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
Given temperature in celcius converts it to Kelvin |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=cut |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
sub __c2k { |
390
|
6994
|
|
|
6994
|
|
7769
|
my ($c) = @_; |
391
|
6994
|
100
|
|
|
|
8523
|
unless (defined $c) { |
392
|
1
|
|
|
|
|
10
|
die "__c2k(): usage error"; |
393
|
|
|
|
|
|
|
} |
394
|
6993
|
|
|
|
|
11786
|
return ( $c + 273.15 ); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head2 __k2c($T) |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Given temperature in Kelvin converts it to celcius |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=cut |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub __k2c { |
404
|
0
|
|
|
0
|
|
0
|
my ($k) = @_; |
405
|
0
|
|
|
|
|
0
|
return ( $k - 273.15 ); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head2 __calibration_points($limit) |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Returns all known calibration points to the lubricant as array reference. If C<$limit> is given limits the result set to that many points. |
411
|
|
|
|
|
|
|
The points are guaranteed to be in ascending order by temperature. All temperature points are converted to Kelvin, since that's |
412
|
|
|
|
|
|
|
what all internal formulas rely on. |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=cut |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
sub __calibration_points { |
417
|
2801
|
|
|
2801
|
|
3049
|
my ( $self, $limit ) = @_; |
418
|
|
|
|
|
|
|
|
419
|
2801
|
|
|
|
|
2441
|
my @calibrations = ( sort { $a <=> $b } keys %{ $self->{__visc_calibration_points} } ); |
|
1612116
|
|
|
|
|
1198864
|
|
|
2801
|
|
|
|
|
27593
|
|
420
|
|
|
|
|
|
|
|
421
|
2801
|
|
|
|
|
9605
|
my $lowest_temp = $calibrations[0]; |
422
|
2801
|
|
|
|
|
2472
|
my $highest_temp = $calibrations[-1]; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
return [ |
425
|
2801
|
|
|
|
|
3330
|
[ __c2k($lowest_temp), $self->visc($lowest_temp) ], |
426
|
|
|
|
|
|
|
[ __c2k($highest_temp), $self->visc($highest_temp) ] |
427
|
|
|
|
|
|
|
]; |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=head2 __vi_lt_100() |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Uses algorithm described in B<5. Procedure A> section of ASTM D2270. When you use C it invokes either method |
433
|
|
|
|
|
|
|
accordingly. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=cut |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
sub __vi_lt_100 { |
438
|
17
|
|
|
17
|
|
25
|
my ($self) = @_; |
439
|
|
|
|
|
|
|
|
440
|
17
|
|
|
|
|
25
|
my $cst40 = $self->visc(40); |
441
|
16
|
|
|
|
|
23
|
my $cst100 = $self->visc(100); |
442
|
|
|
|
|
|
|
|
443
|
16
|
50
|
33
|
|
|
54
|
unless ( $cst40 && $cst100 ) { |
444
|
0
|
|
|
|
|
0
|
croak "vi2(): viscosities at 40C and 100C must be known or calculatable"; |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
|
447
|
16
|
|
|
|
|
28
|
my ( $L, $H ) = $self->LH; |
448
|
16
|
|
|
|
|
38
|
my $vi = ( ( $L - $cst40 ) / ( $L - $H ) ) * 100; |
449
|
|
|
|
|
|
|
|
450
|
16
|
|
|
|
|
60
|
return sprintf( "%d", $vi ); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=head2 __vi_gt_100() |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Uses algorithm described in B<6. Procedure B> section of ASTM D2270. When you use C it invokes either method |
456
|
|
|
|
|
|
|
accordingly. |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=cut |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub __vi_gt_100 { |
461
|
12
|
|
|
12
|
|
19
|
my ($self) = @_; |
462
|
|
|
|
|
|
|
|
463
|
12
|
|
|
|
|
20
|
my ( undef, $H ) = $self->LH; |
464
|
12
|
|
|
|
|
36
|
my $cst40 = $self->visc(40); |
465
|
12
|
|
|
|
|
18
|
my $cst100 = $self->visc(100); |
466
|
|
|
|
|
|
|
|
467
|
12
|
|
|
|
|
24
|
my $N = ( log10($H) - log10($cst40) ) / log10($cst100); |
468
|
12
|
|
|
|
|
31
|
my $vi = ( ( ( 10**$N ) - 1 ) / 0.00715 ) + 100; |
469
|
12
|
|
|
|
|
43
|
return sprintf( "%d", $vi ); |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head1 SEE ALSO |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
L, Second Edition by Wiley-VCH |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
1; |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
__DATA__ |