0

我想生成一些二进制数组来控制没有控制器的 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 }因此度量需要稍微复杂一些,因为第二个示例明显优于第一个示例。(对于更长的阵列长度,可能会看到一些 LED 闪烁,因为 1 会聚在一起)。

4

2 回答 2

2

好的,就是这样。基本上,您想要做的是最小化 0 或 1 的最大运行长度。总体思路是尽可能分配。剩下的,把它塞在前面。

N = # 总位数 n = # of 1

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
于 2013-01-10T01:42:55.053 回答
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 是包含照明布置的数组。

于 2013-01-10T01:22:36.800 回答