我想生成一些二进制数组来控制没有控制器的LED的亮度。我不会在微控制器上产生脉冲宽度(这会占用应该用于其他事情的指令周期),而是将它们硬编码为查找表,并反复循环遍历二进制数组,设置在指令处开启或关闭LED。
假设我有一个4的数组长度,我将有5个亮度级别:
{{ 0, 0, 0, 0 },
{ 1, 0, 0, 0 },
{ 1, 0, 1, 0 },
{ 1, 1, 1, 0 },
{ 1, 1, 1, 1 }}
请注意,我试图在整个阵列中尽可能均匀地分布1,这并非总是可行,但人眼不应该看到小的异常。
假设我的数组长度为8,我希望亮度为5/8:
{ 1, 0, 1, 1, 0, 1, 1, 0 };
这似乎是一个很好的传播,但我也可以使用:
{ 1, 0, 1, 1, 1, 0, 1, 0 };
哪个更好?当然,平均亮度是相同的。从一个州到另一个州的变化数量也是相同的。标准偏差是相同的。但是,查看运行,第一个示例的运行长度方差要小得多,这意味着它更均匀,因此更好。
反正。我需要一个算法来生成给定长度和亮度的这些数组。如果可能,算法应找到一个最佳阵列 - 尽可能均匀的阵列。
它并不像听起来那么简单。说实话,我很想写一个比较所有可能性的蛮力算法并返回最佳。
我甚至考虑整合一个整数编程模型,但这对于这个问题似乎有些过分。
除非有人有更好的主意?
修改
事实证明,{ 1, 1, 1, 1, 0, 0, 0, 0 }
与{ 1, 0, 1, 0, 1, 0, 1, 0 }
具有相同的运行差异,因此指标需要稍微复杂一点,因为第二个示例明显优于第一。 (对于更长的阵列长度,1可能会看到一些LED闪烁)。
答案 0 :(得分:2)
好在这里。基本上,您要做的是最小化0或1的最大运行长度。一般的想法是分发我们可以做的。剩下的就是把它塞进前面。
N =总位数 n =#1s
void pwm(int N, int n, char* z = 0) {
if (n == 0) {
// degenerate case!
for (int i = 0; i < N; i++) {
printf("0");
}
printf("\n");
return;
} else if (n == N) {
// degenerate case!
for (int i = 0; i < N; i++) {
printf("1");
}
printf("\n");
return;
}
int m = N - n;
int sep = m/n;
int rem = m%n;
int pre;
int i,j;
std::list<char> clist;
if (z == 0) {
// if more 1 than 0, then flip
if (sep > 0) pwm(N,n,"01");
else pwm(N,N-n,"10");
return;
}
pre = sep/2;
for (j = 0; j < pre; j++)
clist.push_back(z[0]);
if (rem > 0) {
clist.push_back(z[0]);
rem--;
}
for (i = 0; i < n; i++) {
if (i!=0) {
for (j = 0; j < sep; j++)
clist.push_back(z[0]);
if (rem > 0) {
clist.push_back(z[0]);
rem--;
}
}
clist.push_back(z[1]);
}
for (j = 0; j < sep-pre; j++)
clist.push_back(z[0]);
// output the data so we can see
char* res = new char[N+1];
memset(res, ' ', N);
res[N] = 0;
char* u = res;
for (std::list<char>::iterator cli = clist.begin(); cli != clist.end(); cli++) {
(*u) = *cli;
u++;
}
printf("%s\n", res);
delete [] res;
}
这是N = 25的输出:
0000000000000000000000000
0000000000001000000000000
0000001000000000001000000
0000100000001000000010000
0001000001000001000001000
0010000100001000010000100
0010001000100010001000100
0010001000100010010010010
0010010010010010010010010
0100100100100100100101010
0100100100100101010101010
0100100101010101010101010
0101010101010101010101010
1010101010101010101010101
1011011010101010101010101
1011011011011010101010101
1011011011011011011010101
1101101101101101101101101
1101110111011101101101101
1101110111011101110111011
1101111011110111101111011
1110111110111110111110111
1111011111110111111101111
1111110111111111110111111
1111111111110111111111111
答案 1 :(得分:0)
假设你需要在n个点的网格中点亮k个点。您可以遵循以下概率方法。
remk=k
remn=n
for i in range(n):
x[i] = 1 if rand()< remk*1.0/remn else 0
remk-=x[i]
remn-=1
x是包含照明布置的数组。