From 0e8096b0663b793a30973d5904e1f02f083436a2 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Wed, 11 May 2022 19:35:03 -0700 Subject: Initial commit. --- lace.rb | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 lace.rb (limited to 'lace.rb') diff --git a/lace.rb b/lace.rb new file mode 100644 index 0000000..f6f871d --- /dev/null +++ b/lace.rb @@ -0,0 +1,290 @@ +require "bigdecimal" +require "set" + +module Lace + + extend self + + def en(series, sigfigs, n) + return BigDecimal((10.0**Math.log10(n.to_f**series.to_f).round.to_f)**(1.0/series.to_f), sigfigs).round + end + + HISTORIC_E24_FIX_TABLE = { + Math.log10(2.6) => Math.log10(2.7), + Math.log10(2.9) => Math.log10(3.0), + Math.log10(3.2) => Math.log10(3.3), + Math.log10(3.5) => Math.log10(3.6), + Math.log10(3.8) => Math.log10(3.9), + Math.log10(4.2) => Math.log10(4.3), + Math.log10(4.6) => Math.log10(4.7), + } + def historic_e24_fix(n) + exp, rem = Math.log10(n).divmod(1) + HISTORIC_E24_FIX_TABLE.each do | accurate, historic | + rem = historic if (rem - accurate).abs <= 0.0001 + end + return (10 ** (exp + rem)).round + end + + def e3(n) + return historic_e24_fix(en(3, 2, n)) + end + + def e6(n) + return historic_e24_fix(en(6, 2, n)) + end + + def e12(n) + return historic_e24_fix(en(12, 2, n)) + end + + def e24(n) + return historic_e24_fix(en(24, 2, n)) + end + + def e48(n) + return en(48, 3, n) + end + + def e96(n) + return en(96, 3, n) + end + + def e192(n) + return en(192, 3, n) + end + + class Netlist + + attr_reader :components + attr_reader :nets + + def initialize(&p) + @components = {} + @nets = {} + + edit(&p) if p + end + + def merge_nets(a, b) + into = @nets[[a.object_id, b.object_id].min] + if a.name + raise "Nets #{into.name} and #{a.name} merged!" if into.name and into.name != a.name + into.name = a.name + end + if b.name + raise "Nets #{into.name} and #{b.name} merged!" if into.name and into.name != b.name + into.name = b.name + end + @nets[a.object_id] = into + @nets[b.object_id] = into + return into + end + + def edit(&p) + instance_eval &p + end + + def comp(*args) + c = Component.new(self, *args) + @components[c.object_id] = c + end + + def net(*args) + n = Net.new(self, *args) + @nets[n.object_id] = n + end + + def real_refs + refs = {} + counters = {} + seen = Set.new + @components.each do | id, comp | + next if seen.member?(comp.object_id) + seen.add(comp.object_id) + counter = counters[comp.refbase] || 1 + counters[comp.refbase] = counter + 1 + ref = "#{comp.refbase}#{counter}" + refs[ref] = comp + end + return refs + end + + def real_nets(refs) + n = 1 + nets = {} + seen = Set.new + @nets.each do | id, net | + next if seen.member?(net.object_id) + seen.add(net.object_id) + name = net.name + unless name + name = "$unnamed#{n}" + n += 1 + end + raise "Multiple disconnected nets named #{name}" if nets.member?(name) + nodes = [] + refs.each do | ref, comp | + comp.pins.each do | pin, pinnet | + nodes << {:ref => ref, :pin => pin} if @nets[pinnet].object_id == net.object_id + end + end + nets[name] = nodes if nodes.size > 1 + end + return nets + end + + def real + refs = real_refs + nets = real_nets(refs) + return [refs, nets] + end + + def kicad(stream=$stdout) + refs, nets = real + stream.write(<