energy note

色々と勉強中なので備忘録として。

合成抵抗の組み合わせを求めるプログラム

2021/6/14更新
↓内容を大きく変更しました。
energy-note.hatenablog.com


M5Stack Creativity Contest に間に合いませんでしたが、ちょっとした測定器みたいのをM5Stackで作っています。
そこで、AD変換したりするときに、分圧したりすると思いますが、微妙な値の抵抗値になったりします。9.8kΩとか・・・あとオペアンプ回路で使うときなどなど。
じゃぁ合成抵抗でいいじゃん!とネットのツールとかで合成抵抗を算出します、的なやつでやってもE12系列とかなんとか・・・
いやいや、全然抵抗そろえてないし・・・
しかも、金皮抵抗が限られた値しか持っていなかったり、ってか、E〇〇系列なんて考えて抵抗そろえてないし!

ということで、勉強も兼ねてPythonで合成抵抗の組み合わせを求めるプログラムを作ってみました。
合成抵抗で考えられる構成がこんなもんですか。
f:id:energy_note:20200927232018p:plain
f:id:energy_note:20200927232042p:plain
f:id:energy_note:20200927232053p:plain
このようにいろいろな並列、直列の組み合わせが考えられます。いや、厳密に言ったらもっとたくさんありますが、実用的な範囲と大変さでこの3つとします。
並列構成要素外直列数とか読み方が適切かは知りませんが、パラメータ設定の時の文言となっています
※私は旧JISが頭から抜けない派なので、旧JISで表記します

まぁどれだけ微妙な抵抗値に対して精度を求めるかにもよりますが、基板上であまりごちゃごちゃした並列直列抵抗なんて組みたくありません。
ですので2並列2直列とかぐらいが実用的かなぁとは思いますが、手持ちの抵抗値の関係とかで微妙になってしまったりするかもしれませんので、自由度を持たせた設計にしてみました。

import pandas as pd
import itertools
from tqdm import tqdm

#---------------------------------パラメータ
#持っている抵抗値
have_value = [1,2,5.1,10,20,51,100,200,510,1000,2000,5100,10000,20000,75000,100000,200000,750000,1000000]
#求めたい抵抗値Ω
set_value = 9880
#許容誤差±Ω
allowable_error = 10
#最大並列数
max_para = 2
#最大直列数(並列構成要素)
max_seri = 2
#並列構成要素外直列数
max_seri_out = 2
#---------------------------------

df = pd.DataFrame(columns=['合成抵抗値', '組み合わせ', '直列', '誤差', '誤差絶対値'])

#渡されたリストの並列合成抵抗を求める
def parallel(array):
    r = 0
    for i in array:
        #直列の場合
        if type(i) is tuple:
            comp = sum(i)
        else:
            comp = i
        r += 1 / comp
    return(1 / r)

#セット値より低い保有抵抗値をリストアップ
seri_out_listup = [i for i in have_value if i<set_value]
#指定直列数で組み合わせる
seri_out_list1 = []
for i in range(max_seri_out):
    seri_out_list1 += list(itertools.combinations_with_replacement(seri_out_listup,i+1))

#組み合わせの合計がセット値より高かったら除外
tmp = []
for i in seri_out_list1:
    if sum(i)<set_value:
        tmp.append(i)
#合計値が被る直列組み合わせは除外
seri_out_list = []
tmp1 = []
for i in tmp:
    b = sum(i)
    if b not in tmp1:
        seri_out_list.append(i)
    tmp1.append(b)

#並列構成要素外直列数がない場合も考える
seri_out_list.append((0,))

#直列数の組み合わせを作る
s_list2 = []
sum_list = []
s_list=[]
if max_seri<=1:
    s_list2 = []
else:
    for i1 in range(max_seri-1):
        #直列組み合わせをリスト化する
        s_list += list(itertools.combinations_with_replacement(have_value,i1+2))
    for i in s_list:
        b = sum(i)
        if b not in sum_list:
            s_list2.append(i)
        sum_list.append(b)

#考えうる組み合わせをリスト化
r_list=[]
for i2 in range(max_para):
    #持っている抵抗値と直列組み合わせからの組み合わせをリスト化する
    r_list += list(itertools.combinations_with_replacement(have_value + s_list2,i2+1))

#合成抵抗値算出
for i3 in tqdm(r_list):
    #並列構成要素外直列数を含むループ
    for i4 in seri_out_list:
        seri_out_tmp = sum(i4)
        com = parallel(i3)
        ##並列構成要素外直列数がある場合、判定から引く
        diff = com - (set_value - seri_out_tmp)
        #指定した差に収まっているか
        if abs(diff)<=allowable_error:
            er_set = round(diff * 100 / set_value,5)
            #条件に合うデータをデータフレームに格納
            df = df.append({'合成抵抗値': round(com+seri_out_tmp,6), '組み合わせ': i3, '直列':i4, '誤差': er_set, '誤差絶対値': abs(er_set)}, ignore_index=True)

#重複するデータを除去
df = df.drop_duplicates(subset='合成抵抗値')
#誤差でソート
df.sort_values('誤差絶対値', inplace=True)
#インデックスの振り直し
df = df.reset_index(drop=True)

#たぶん使っても上位10個くらいだろう
if len(df['合成抵抗値'])<10:
    cnt = len(df['合成抵抗値'])
else:
    cnt = 10
print('計算結果数:',len(df['合成抵抗値']),'組み合わせ')
#結果表示
for i in range(cnt):
    print('合成抵抗値:'+str(df['合成抵抗値'][i])+' 組み合わせ:'+str(df['組み合わせ'][i])+'+'+str(df['直列'][i])+' 誤差:'+str(df['誤差'][i])+'%')

Python3+Jupyter Notebookで作成しています。
仕事柄SEでもないので読みにくい、効率の悪いコードになってそうで、ガチエンジニアの方々からしたらツッコミどころのあるコードだと思いますがご了承を・・・(もしこういう方法がある、ここはこうしたほうがいい、などご指摘もらえたら勉強になります・・・)

have_valueに持っている抵抗値をリスト形式の単位はΩで記入します。
求めたい抵抗値と許容誤差±を単位をΩで記入します。
最大並列数や最大直列数(並列構成要素)、並列構成要素外直列数とかは上記の画像の通りです。
あとは実行してもらえると誤差が低い順から10個表示されます。dfデータフレームにすべての計算結果が入っています。

例えばこのような出力の場合、
((10, 10000), (5100, 750000))+(1,)
f:id:energy_note:20200929223608p:plain
こうなります。

最大並列数と最大直列数(並列構成要素)を3以上にして手持ちの抵抗が10種類とかになるとかなりの数、普通に数百万組み合わせとかを計算させることになりますので、時間がかかってしまいます。

一応、チェックはしてありますが、念のため検算はしてから接続しますようお願いします。
使用個数制限とかつけるのもありだなぁ。とか考えてしまうといつになっても完成しないので今回はこれで完了。
(並列構成要素外直列数を5以上にして手持ち抵抗が多くなると、並列なしの直列だけで大体の値が片付いてしまうという現象もw)