Last active
July 1, 2017 10:06
-
-
Save hejmsdz/c9e33d610ff61bd79d29a51a668556a4 to your computer and use it in GitHub Desktop.
Resistance calculator with LaTeX-compatible step by step derivation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'set' | |
def ohm(value, decimals=2) | |
value.round(decimals).to_s.sub('.', ',').sub(/,0+$/, '') << " \\Omega" | |
end | |
def frac(num, den) | |
"\\frac{#{num}}{#{den}}" | |
end | |
class BaseResistor | |
def value_str | |
ohm(value) | |
end | |
end | |
class Resistor < BaseResistor | |
attr_reader :sym, :value, :derived | |
def initialize(sym, value) | |
@sym = sym | |
@value = value | |
@derived = true | |
end | |
def syms | |
Set.new([sym]) | |
end | |
def inspect | |
"R_#{@sym}" | |
end | |
def full_sym | |
inspect | |
end | |
end | |
class Connection < BaseResistor | |
attr_reader :derived | |
def initialize(contents) | |
@contents = contents | |
@derived = false | |
end | |
def syms | |
@contents.map(&:syms).reduce(:+) | |
end | |
def full_sym | |
sym | |
end | |
def sym | |
syms_list = syms.to_a.sort.join(",") | |
"R_(#{syms_list})" | |
end | |
def inspect | |
name = self.class.name.to_s.downcase | |
contents = @contents.map(&:inspect).join(", ") | |
"#{name}(#{contents})" | |
end | |
def write_value | |
puts "#{sym} = #{derive_value} = #{value_str}" | |
end | |
def derive | |
derive_me | |
complex = @contents.select {|x| x.kind_of?(Connection) } | |
complex.each(&:derive) | |
@derived = true | |
write_value if @contents.all?(&:derived) | |
end | |
end | |
class Series < Connection | |
def value | |
@contents.map(&:value).reduce(:+) | |
end | |
def derive_me | |
terms = @contents.map(&:full_sym).join(' + ') | |
puts "#{sym} = #{terms}" | |
end | |
def derive_value | |
@contents.map(&:value_str).join(' + ') | |
end | |
end | |
class Parallel < Connection | |
def value | |
1.0 / @contents.map { |x| 1.0 / x.value }.reduce(:+) | |
end | |
def derive_me | |
terms = @contents.map { |x| frac(1, x.full_sym) }.join(' + ') | |
puts "#{sym} = #{frac(1, terms)}" | |
end | |
def derive_value | |
terms = @contents.map { |x| frac(1, x.value_str) }.join(' + ') | |
recipr = @contents.map { |x| 1.0 / x.value }.reduce(:+) | |
"#{frac(1, terms)} = #{frac(ohm(1, 0), recipr.round(4))}" | |
end | |
end | |
def method_missing(meth, *args, &block) | |
return unless meth.to_s.start_with? 'R' | |
Resistor.new(meth.to_s.sub(/^R/, ''), args[0]) | |
end | |
def series(*contents) | |
Series.new(contents) | |
end | |
def parallel(*contents) | |
Parallel.new(contents) | |
end | |
# Usage example | |
circuit = series(R1(30), parallel(R2(20), series(R3(10), R4(15))), R5(10)) | |
circuit.value | |
circuit.derive |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment