Rheilly Phoull said:
G'Day All, Hi.
I seem to have lost the formula that calculates the 1% 'preferred' range of
resitors.
Can anyone help out please ??
I have appended a very handy Perl script I wrote to
deal with not knowing all (or having forgot some) of
the 1% values. It also finds pairs of values to get
closer values than the standard spreads allow.
(This is useful when using 0.1% parts)
Run it without arguments for invocation tips.
Get Perl at
www.activestate.com .
--
--Larry Brasfield
email:
[email protected]
Above views may belong only to me.
============== script only follows ================
#!/usr/bin/perl
my $usage = <<'_';
Usage:
stdvals tolerance
or
stdvals tolerance value [2a|2p|2r]
or
stdvals -n decsplit
_
my $pick = shift;
my %stdsplits = (
3 => '50%',
6 => '20%',
12 => '10%',
24 => '5%',
96 => '1%',
);
my %digits = (
3 => 2,
6 => 2,
12 => 2,
24 => 2,
96 => 3
);
# Unfortunately, the lower tolerances do not derive mathematically.
%fudge2digits = (
'1.0' => '1.0',
'1.1' => '1.1',
'1.2' => '1.2',
'1.3' => '1.3',
'1.5' => '1.5',
'1.6' => '1.6',
'1.8' => '1.8',
'2.0' => '2.0',
'2.2' => '2.2',
'2.4' => '2.4',
'2.6' => '2.7',
'2.9' => '3.0',
'3.2' => '3.3',
'3.5' => '3.6',
'3.8' => '3.9',
'4.2' => '4.3',
'4.6' => '4.7',
'5.1' => '5.1',
'5.6' => '5.6',
'6.2' => '6.2',
'6.8' => '6.8',
'7.5' => '7.5',
'8.3' => '8.2',
'9.1' => '9.1',
);
my %stdtols;
map {
my $tol = $stdsplits{$_};
$stdtols{$tol} = $_;
} keys %stdsplits;
my $decsplit;
my $tolerance;
my $sigdigits;
sub saydec {
print "Standard decade splits are: ", join(' ', sort keys %stdsplits), "\n";
}
sub saytol {
print "Standard tolerances are: ", join(' ', sort keys %stdtols), "\n";
}
if (!$pick) {
print $usage;
&saytol;
&saydec;
exit 1;
}
if ($pick =~ m/^\d+$/) {
if ($decsplit = $stdtols{$pick.'%'}) {
$tolerance = $pick.'%';
}
else {
print $usage;
&saytol;
exit 1;
}
}
elsif ($pick eq '-n' && ($tolerance = $stdsplits{$pick = shift})) {
print "Standard $tolerance values:\n";
$decsplit = $pick;
}
else {
print $usage;
&saydec;
exit 1;
}
my $target = shift;
my $parts = shift;
my $combine = undef;
if (! $parts) { $parts = 1; }
else {
unless ($parts =~ s/([apr])$/$combine=$1,''/e) {
print $usage;
print "Specify 2a, 2p or 2r as a combination method.\n";
exit 1;
}
}
$sigdigits = $digits{0+$decsplit};
my @values = ();
my $loginc = log(10) / $decsplit;
my $fmt = sprintf("%%%1d.%1df", $sigdigits+1, $sigdigits-1);
for (my $i = 0; $i < $decsplit; ++$i) {
my $value = sprintf($fmt, exp($i * $loginc));
if ($sigdigits < 3) {
$value = $fudge2digits{$value};
}
if (! $target) {
my $sep = (($i+1) % 12)? " " : "\n";
print "$value$sep";
}
else {
push(@values, $value + 0.0);
}
}
exit 0 unless $target;
push(@values, 10.0);
my %multsuf = (
'f' => 1e-15,
'p' => 1e-12,
'n' => 1e-9,
'u' => 1e-6,
'm' => 1e-3,
'k' => 1e3,
'K' => 1e3,
'M' => 1e6,
'G' => 1e9,
'T' => 1e12,
);
sub floor {
my $v = shift;
if ($v >= 0) { return int($v); }
else { return -1 - int(-$v); }
}
sub unsuffix {
my $tv = shift;
my $mult = 1;
my $suf;
if ($tv =~ s/([kKnupfmMGT])$/$suf=$1,''/e) {
$mult = $multsuf{$suf};
}
else { $suf = ''; }
return $tv * $mult;
}
sub closest {
my $tv = shift;
$tv = &unsuffix($tv);
if ($tv <= 0) { return undef; }
my $prescale = &floor(log($tv) / log(10));
$prescale = 10 ** $prescale;
my $findv = $tv / $prescale;
my $bestv = undef;
for (my $i = 0; $i < $decsplit; ++$i) {
my $lo = $values[$i];
my $hi = $values[$i+1];
if ($findv >= $lo && $findv < $hi) {
my $gm = sqrt($lo * $hi);
$bestv = ($findv < $gm)? $lo : $hi;
last;
}
}
return $bestv *= $prescale;
}
if ($parts == 1) {
print &closest($target), "\n";
}
sub gapprox {
my ($tv, $scale, $rtvbase, $rtvadj) = @_;
my $vb = &closest($scale * $tv);
my $va = 1.0/$tv - 1.0/$vb;
if ($va > 0) {
$va = &closest(1.0/$va);
$$rtvbase = $vb;
$$rtvadj = $va;
return 1.0/(1.0/$vb + 1.0/$va);
}
else {
$$rtvbase = $vb;
$$rtvadj = undef;
return $vb;
}
}
sub zapprox {
my ($tv, $scale, $rtvbase, $rtvadj) = @_;
$$rtvbase = &closest($scale * $tv);
my $va = $tv - $$rtvbase;
if ($va > 0) {
$$rtvadj = &closest($va);
return $$rtvbase + $$rtvadj;
}
else {
$$rtvadj = 0;
return $$rtvbase;
}
}
sub rapprox {
my ($rv, $scale, $rtvbase, $rtvadj) = @_;
$$rtvbase = &closest($scale * $rv);
$$rtvadj = &closest($$rtvbase / $rv);
return $$rtvbase / $$rtvadj;
}
if ($parts == 2) {
my $tv = &unsuffix($target);
if ($combine eq 'p') {
my ($tvbase, $tvadj);
my $bestratio = 2.0;
my $bestgot = undef;
my $bestscale = undef;
for (my $scale = 1.00; $scale < 1.5; $scale += 0.01) {
my ($tvb, $tva);
my $tvgot = &gapprox($tv, $scale, \$tvb, \$tva);
next unless $tvgot;
my $ratio = $tvgot / $tv;
if ($ratio < 1) { $ratio = 1.0 / $ratio; }
if ($ratio < $bestratio) {
$tvbase = $tvb;
$tvadj = $tva;
$bestratio = $ratio;
$bestgot = $tvgot;
}
}
my $adjv = defined($tvadj)? sprintf("%g",$tvadj) : 'none';
printf("Approximate %g as 1(1/%g + 1/%s), yielding %g (ratio = %6.4f)\n",
$tv, $tvbase, $adjv, $bestgot, $bestratio);
}
if ($combine eq 'a') {
my ($tvbase, $tvadj);
my $bestratio = 2.0;
my $bestgot = undef;
my $bestscale = undef;
for (my $scale = 1.0; $scale > 0.7; $scale -= 0.01) {
my ($tvb, $tva);
my $tvgot = &zapprox($tv, $scale, \$tvb, \$tva);
my $ratio = $tvgot / $tv;
if ($ratio < 1) { $ratio = 1.0 / $ratio; }
if ($ratio < $bestratio) {
$tvbase = $tvb;
$tvadj = $tva;
$bestratio = $ratio;
$bestgot = $tvgot;
}
}
printf("Approximate %g with (%g + %g), yielding %g (ratio = %6.4f)\n",
$tv, $tvbase, $tvadj, $bestgot, $bestratio);
}
if ($combine eq 'r') {
my ($tvbase, $tvadj);
my $bestratio = 2.0;
my $bestgot = undef;
my $bestscale = undef;
for (my $scale = 0.34; $scale < 3.4; $scale += 0.01) {
my ($tvb, $tva);
my $tvgot = &rapprox($tv, $scale, \$tvb, \$tva);
my $ratio = $tvgot / $tv;
if ($ratio < 1) { $ratio = 1.0 / $ratio; }
if ($ratio < $bestratio) {
$tvbase = $tvb;
$tvadj = $tva;
$bestratio = $ratio;
$bestgot = $tvgot;
}
}
printf("Approximate ratio %8.6f with (%g / %g), yielding %g\n",
$tv, $tvbase, $tvadj, $bestgot);
}
}
if ($parts > 2) {
print "Sorry, not doing more than 2 parts yet.\n";
}
__END__