Resistor search in Ruby

Here’s a short snippet I wrote the other day. I think it’s a good illustration of Ruby’s potential for short scripts.

I needed to set the resistor divider to get 5.4V out of an adjustable LDO regulator (a REG102-A). The output voltage is set as:

V_{out} = left( 1 + frac{R1}{R2}right) V_{ref}

For the REG102, V_{ref} = 1.26V, and the bias current was about right if R1 and R2 were both in the order of 1-10K.

On the other hand, I had a big bag of completely unsorted SMD resistors. Somewhere in there was a nice combination that would give me the voltage I wanted.

The script reads a list of resistor values (one per line) from a file (by default ‘r.txt’). The output looks like:

Have these resistors: 0.91, 2.2, 4.7, 6.81, 8.06, 10.0, 11.5, 15.0, 22.0, 24.9, 30.0, 33.0, 35.7, 40.2, 42.2, 47.0, 51.0, 53.6, 56.0, 68.0, 100.0, 215.0, 226.0
Searching for Vtarget = 5.4
R1	R2	vout	error
24.90	8.06	5.15	-0.05
68.00	22.00	5.15	-0.05
6.81	2.20	5.16	-0.04
35.70	11.50	5.17	-0.04
47.00	15.00	5.21	-0.04
215.00	68.00	5.24	-0.03
15.00	4.70	5.28	-0.02
22.00	6.81	5.33	-0.01
33.00	10.00	5.42	+0.00
226.00	68.00	5.45	+0.01
100.00	30.00	5.46	+0.01
51.00	15.00	5.54	+0.03
40.20	11.50	5.66	+0.05

The code loads the resistors from the file, and removes duplicates, then calculates Vout for every permutation. It then deletes any permutations which don’t get within 5% of the desired voltage, and sorts and prints the results.

As a side note, it doesn’t matter than the resistors are given in Kohms (or Ohms, or MOhms, etc) because they’re divided in the script, as long as they’re in the same units.

Yes, it’s non-optimized because it does build an enormous list of possibilities, then throws the vast majority away. Even a simple permutation like not calculating Vout if R2 > R1 would eliminate many possible pairings.

But, there you go.

#!/usr/bin/env ruby

TARGETV = 5.4

filename = ARGV.pop || "r.txt"
r = ($File.open( filename ) { |f| f.readlines.map { |l| l.to_f } }).sort.uniq

puts "Have these resistors: " + r.join(', ')
puts "Searching for Vtarget = #{TARGETV}"

vals =  r.permutation(2).map { |res|
  vout = 1.26 * (1 + res[0]/res[1])
  error = (vout-TARGETV)/TARGETV 
  res+[vout, error]
}.delete_if { |res| (res[3]).abs > 0.05
}.sort { |a,b| a[2] <=> b[2] }


puts %w( R1 R2 vout error ).join("t")
vals.each { |v|
  puts "%.2ft%.2ft%.2ft%+.2f" % v
}

Leave a Reply

Your email address will not be published. Required fields are marked *