Re: Prefered resistor range

From: Larry Brasfield (donotspam_larry_brasfield_at_hotmail.com)
Date: 03/15/05


Date: Mon, 14 Mar 2005 22:57:32 -0800


"Rheilly Phoull" <Rheilly@bigpong.com> wrote in
 message news:39ndaaF64dibcU1@individual.net...
> 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: donotspam_larry_brasfield@hotmail.com
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__


Relevant Pages

  • Asthetics in Perl
    ... my $oper = shift @ARGV; ... sub product ... if ($oper eq "sum") ...
    (perl.beginners)
  • Re: How to make only one thread sleep?
    ... # Frequency to scan inbound directory ... sub monitor_loop { ... && exit 1; ... my $digest = shift; ...
    (comp.lang.perl.misc)
  • Passing variables from one subroutine to another....
    ... and modified it to what I have below so that instead of one sub ... my $host_id = shift; ... Prev by Date: ...
    (perl.beginners)
  • Re: conflicting errors
    ... sub data_for_path { ... my $path = shift; ... You normally don't need to return undef, perl will do the right thing and correctly distinguish between list and scalar context. ...
    (perl.beginners)
  • Re: both 1 and not-1?
    ... is_filtered doesn't modify $visit -- or does it? ... sub add_to_array{ ... my $visit = shift; ... value undef, so yes is_filtered can modify $visit. ...
    (comp.lang.perl.misc)

Loading