最近常遇到板子上电源部分需要几个电阻分压器的情况,写了个小程序来实现在指定电阻阻值系列内(E6~E192),选择尽量少的电阻种类实现需要的分压比例。
测试于MATLAB 2012a/2014b和Octave。
程序第一部分定义了需要计算的分压比例、对应的允许误差、系统中已经存在的固定电阻、阻值系列、最大迭代次数。
之后生成电阻系列的所有阻值。E48~E192系列的阻值基本是按照对数排列的,用logspace生成即可;E6~E24系列是用E24的取值间隔选取得到的。
把阻值系列中所有可以得到的分压比例,按对目标分压比例的误差排列,选择出符合误差要求的部分。
最后对这些在误差范围内的选择做随机搜索,查找使用尽量少数量的电阻种类能够完成的一种组合。
input_list = ...
[5.0 / 0.8 - 1, 0.02; ...
1.0 / 0.6 - 1, 0.02; ...
1.8 / 0.83 - 1, 0.02; ...
2.5 / 0.6 - 1, 0.02; ...
3.3 / 0.6 - 1, 0.02];
fixed_list = ...
[12];
res_series_name = 48;
max_iter = 100000;
if res_series_name >= 48
res_series = floor(logspace(2, 3, res_series_name + 1) + 0.5)';
res_series = res_series(1: end - 1);
res_series(res_series == 919) = 920;
else
res_series = [100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300, 330, 360, 390, 430, 470, 510, 560, 620, 680, 750, 820, 910]';
res_series = res_series(1:24/res_series_name:24);
end
clear res_series_name;
results = [];
errors = [];
for i = 1:size(input_list, 1)
divider_ratio = input_list(i, 1);
max_error = input_list(i, 2);
if (divider_ratio >= 1)
R1 = kron(res_series, 10 .^ (floor(log10(divider_ratio)-1):floor(log10(divider_ratio)+1)));
R1 = R1(:);
R2 = res_series;
else
R1 = res_series;
R2 = kron(res_series, 10 .^ -(floor(log10(divider_ratio)-1):floor(log10(divider_ratio)+1)));
R2 = R2(:);
end
R1_temp = kron(R1, ones(size(R2)));
R2 = kron(ones(size(R1)), R2);
R1 = R1_temp;
clear R1_temp;
divider_array = R1 ./ R2;
[Y, I] = sort(abs(log(divider_array ./ divider_ratio)));
disp_num = find(Y <= log(1 + max_error), 1, 'last');
results{i} = uint32([R1(I(1:disp_num)), R2(I(1:disp_num))]);
errors{i} = Y(1:disp_num);
end
clear res_series divider_ratio max_error R1 R2 divider_array Y I disp_num;
for i = 1:length(fixed_list)
results{size(input_list, 1) + i} = [fixed_list(i), fixed_list(i)];
errors{ size(input_list, 1) + i} = 0;
end
num_of_pairs = uint32(size(results, 2));
num_of_input = uint32(zeros(1, num_of_pairs));
now_index = uint32(zeros(1, num_of_pairs));
R_output = uint32(zeros(num_of_pairs, 2));
error_output = zeros(num_of_pairs, 1);
R_max = 0;
for i = 1:num_of_pairs
R_max = max(R_max, max(max(results{i})));
end
for i = 1:num_of_pairs
for j = 1:size(results{i}, 1)
results{i} = [results{i}; ...
kron(double(results{i}(j, :)), ...
10 .^ (1:floor(log10(double(R_max) / ...
double(results{i}(j, 1)))))')];
errors{i} = [errors{i}; ...
kron(errors{i}(j), ...
ones(floor(log10(double(R_max) / ...
double(results{i}(j, 1)))), 1))];
end
end
clear R_max;
for i = 1:num_of_pairs
num_of_input(i) = size(results{i}, 1);
now_index(i) = randi(double(num_of_input(i)));
R_output(i, :) = results{i}(now_index(i), :);
error_output(i) = errors{i}(now_index(i));
end
now_num_of_res = num_of_pairs * 2 + 1;
now_max_error = inf;
% Loop
count = uint32(0);
count_to_disp = 1;
tic;
for count = 1:max_iter
% Select one pair of resistors to change
index_to_change = randi(double(num_of_pairs));
% Random
now_index(index_to_change) = randi(double(num_of_input(index_to_change)));
R_output(index_to_change, :) = results{index_to_change}(now_index(index_to_change), :);
error_output(index_to_change) = errors{index_to_change}(now_index(index_to_change));
% Check if it is the optimized selection
if (length(unique(R_output)) < now_num_of_res) || ...
((length(unique(R_output)) == now_num_of_res) && (max(error_output) < now_max_error))
now_num_of_res = length(unique(R_output));
now_max_error = max(error_output);
fprintf('Result of %g resistors in %g attempts:
', now_num_of_res, count);
for i = 1:num_of_pairs
fprintf('%8d %8d %8.2f%%
', R_output(i, 1), R_output(i, 2), error_output(i) * 100);
end
end
if (count >= count_to_disp)
fprintf('loop %g in %g seconds.
', count, toc);
count_to_disp = count_to_disp * 10;
end
end
clear i j;
clear num_of_pairs num_of_input;
clear now_index now_num_of_res now_max_error;
clear R_output error_output;
clear count count_to_disp max_iter;
clear index_to_change;
clear R_output error_output