5

私は最近、8 ビット マイクロ コントローラーを搭載した LED で遊んでいます。場合によっては、パルス幅変調の純粋なソフトウェア実装を使用して LED の明るさを制御する必要があります。これは、オンとオフの時間の比率を急速に変化させてライトをオン/オフすることです。これは、明るさが約 5% になるまでうまく機能し、ストロボが目に不快なちらつきを感じ始めます。

PWM をループとして実装し、0 から 255 までの各数値をステップ実行して、その瞬間にライトをオンまたはオフに設定します。値 20 に設定されたライトは、最初の 20 ループでオンになり、その後オフになります。

これらの数値をシャッフルする優れた関数を探しているので、0、1、2、3 をループする代わりに、私のループは可能性のプールから半ランダムにサンプリングできます。時間の経過に伴う全体的な明るさは同じですが、明るさの値が 20 のライトは、1 回点灯してループの大部分でオフになるのではなく、256 のループにまたがって数十回ほどオンとオフを切り替える場合があります。これにより、ループの実行が少し遅くなっても、ちらつきの影響が軽減されます。

優れたディザリング関数は、すべての 8 ビット数値で呼び出されたときに、8 ビット範囲内のすべての数値を返す必要があります。したがって、ランダムではなく、シャッフルするだけで、重複する数字を生成しない必要もあります。似たような数字を連続させない方がいいですし、それぞれの数字の差は大きいほうがいいですし、理想は64~127くらいだと思います。

制限も興味深いものです。これはタイム クリティカルなアプリケーションです。加算、減算、およびビット単位の演算には 1 任意単位の時間、乗算には 2 単位、除算には 4 単位のコストがかかります。浮動小数点数は問題外であり、中間数で使用される 8 ビットの倍数ごとにコストが約 2 倍になります。ルックアップ テーブルは可能ですが、デバイスの総メモリ容量の約半分を使用します。したがって、高速アルゴリズムは再利用性に最適ですが、事前計算するスペースがある場合は、高品質の低速アルゴリズムも非常に役立ちます。

アイデアや考えを手伝ってくれてありがとう。:)

4

2 に答える 2

5

例: 8 ビット レジスタ内の 5 ビット ディザに位相アキュムレータを使用する場合、デューティ = 1 ~ 31 [% = デューティ / (1 << ビット)]。

// Easier to do in assembly, where there is access to the carry flag
unsigned bits = 5;  // states = 1 << bits
unsigned carry = 7; // keep carry bit within an 8 bit register, limits bits
unsigned frq = ((1 << carry) * duty) / (1 << bits); // More than 8 bit intermediate value
unsigned phs = 0;
for (i = 0; i < (1 << bits); i++) {
    phs += frq;  // Carry is high bit
    output((phs >> carry) & 1);  // Output carry
    phs &= (1 << carry) - 1;  // Discard carry
}

ディザ パターンは次のようになります。

00: 00000000000000000000000000000000
01: 00000000000000000000000000000001
02: 00000000000000010000000000000001
03: 00000000001000000000010000000001
04: 00000001000000010000000100000001
05: 00000010000010000001000001000001
06: 00000100001000010000010000100001
07: 00001000010001000010001000010001
08: 00010001000100010001000100010001
09: 00010001001000100100010010001001
10: 00010010010010010001001001001001
11: 00100100100100100100100100100101
12: 00100101001001010010010100100101
13: 00101001010010100101001010010101
14: 00101010010101010010101001010101
15: 00101010101010100101010101010101
16: 01010101010101010101010101010101
17: 01010101010101011010101010101011
18: 01010101101010110101010110101011
19: 01010110101101011010110101101011
20: 01011011010110110101101101011011
21: 01011011011011011011011011011011
22: 01101101101101110110110110110111
23: 01101110110111011011101101110111
24: 01110111011101110111011101110111
25: 01110111101110111101110111101111
26: 01111011110111110111101111011111
27: 01111101111101111110111110111111
28: 01111111011111110111111101111111
29: 01111111110111111111101111111111
30: 01111111111111110111111111111111
31: 01111111111111111111111111111111

十分な幅の整数がない場合 (または、乗算も除算もない場合はアセンブラーで)、一度に 1 ビットずつループで frq を計算する必要がある場合があります。

必要に応じて、ディザ パターンを事前に計算し、ルックアップ テーブルの定数としてコード化することができます。

2 の累乗のパターンのみノイズがありません。オーディオまたは RF 合成を行っていない限り、これは問題になりません。そうでなければ、他のパターンにはバーディーがあります。パターンを一度出力した後にパターン ビットの順序をスクランブルすると、ノイズが追加されますが、バーディーは削除されます。これには、ビットの追加も削除も行わない (1 と 0 の数はそのままで、順序が変わるだけの) 長い繰り返し周期を持つ LFSR 関数を使用できます。

60 Hz のフレーム レートで完全なパターンを出力するには、60 Hz * (1 << ビット) = 1.92 kHz のディザ周波数が必要であることに注意してください。おそらく、(1 << ビット) = 32 Hz のように、ちらつきのない LED のディザ周波数をはるかに低くすることができます。実験!

于 2016-03-08T05:09:06.927 に答える
5

100% 正しく理解しているとは言えませんが、基本的には、256 を除算しない数値は、256 を法としてそれ自体に加算し続けると、数値のグループ 0..255 が生成されると思います 。抽象代数クラスからのいくつかのフラッシュバック。 ..

このような:

s = {}

n = 157
for i in range(0, 256):
   s[n] = True
   print n
   n += 157
   n %= 256

print "check: has to be 256: ", len(s) 

編集:分布をより「ランダム」にするために、小さなジェネレーターを大きなジェネレーターに置き換えました。

于 2012-04-06T03:26:58.440 に答える