K = 1.3806503e-23 Q = 1.60217646e-19 class Interpolate def initialize @values = [] end def [](x0) j, k = -1, -1 @values.each_with_index do |(x, y), i| j = i if x0 >= x k = i if x0 < x and k == -1 end raise "can't interpolate :-( (lower bound?)" if j == -1 raise "can't interpolate :-( (upper bound?)" if k == -1 x1, y1 = @values[j] x2, y2 = @values[k] return (x0 - x1) * (y2 - y1)/(x2 - x1) + y1 end def []=(x, y) @values += [[x.to_f, y.to_f]] @values = @values.sort end end class Resistor attr_accessor :ohms, :kelvins def vn_root_hz Math::sqrt(4 * K * @kelvins * @ohms) end def to_f r.to_f end end class FirstOrderLPF def initialize @wc = 1.0 end def wc=(wc) @wc = wc.to_f end def fc=(fc) @wc = 2.0 * Math::PI * fc.to_f end def fc @wc / (2.0 * Math::PI) end def [](f) 1.0 / Math::sqrt((f / fc) ** 2 + 1.0) end end class Range def logmap(points) (1..points).map { |x| first * (last/first) ** ((x-1)/(points.to_f-1)) } end end opamp_vn = Interpolate.new opamp_in = Interpolate.new [ [10, 20e-9], [100, 12e-9], [1e3, 11e-9], [10e3, 9e-9], [101e3, 9e-9], ].each do |(f, a)| opamp_vn[f] = a end opamp_in[0] = 0.6e-15 opamp_in[101e3] = 0.6e-15 lpf = FirstOrderLPF.new rf = Resistor.new rf.ohms = 10e3 rf.kelvins = 295.0 cf = 800e-12 lpf.wc = 1/(rf.ohms * cf) (10..100e3).logmap(10).each do |f| k = lpf[f] puts [ f, opamp_vn[f], opamp_in[f]*rf.ohms, rf.vn_root_hz, lpf[f], ].map { |x| "%e" % [x] }.join(' ') end