2012-04-06 3 views
4

J'ai beaucoup joué avec les LED récemment, alimenté par des microcontrôleurs 8 bits. Parfois, il est nécessaire d'utiliser des implémentations purement logicielles de Pulse Width Modulation pour contrôler la luminosité des LED - c'est-à-dire allumer et éteindre la lumière en variant rapidement le temps d'activation et de désactivation. Cela fonctionne très bien jusqu'à ce que je descende à environ 5% de luminosité, où le stroboscope commence à avoir l'air inconfortablement flickery à l'œil.Une fonction efficace de tramage unidimensionnel?

En implémentant le PWM comme une boucle, il parcourt chaque numéro de 0-255 pour allumer ou éteindre la lumière pour ce moment. Une lumière qui est réglée à la valeur 20 sera allumée pour les 20 premières boucles puis éteinte.

Je cherche une bonne fonction qui va mélanger autour de ces nombres, donc au lieu de boucler par 0, 1, 2, 3 ... ma boucle pourrait échantillonner semi-aléatoirement à partir du pool de possibilités. La luminosité cumulée dans le temps est la même, mais une lumière à une valeur de luminosité de 20 peut s'allumer et s'éteindre une douzaine de fois réparties sur 256 boucles au lieu de s'allumer une seule fois puis de s'éteindre pendant la majeure partie de la boucle. Cela réduit l'effet de scintillement même si la boucle est légèrement plus lente.

Une bonne fonction de dithering devrait retourner chaque nombre dans la gamme de 8 bits quand il est appelé avec chaque nombre de 8 bits. Il aurait donc également besoin de produire pas de numéros en double - pas aléatoire, juste mélangé. Il est préférable de ne pas mettre ensemble des nombres semblables en séquence - la différence entre chaque chiffre pouvant être élevé - idéalement d'environ 64-127.

Les limitations sont également intéressantes - c'est une application critique dans le temps. Les opérations d'addition, de soustraction et de bits coûtent 1 unité de temps arbitraire, la multiplication coûte 2 unités et la division coûte 4 unités. Les flotteurs sont hors des questions, et les coûts doublent à peu près pour chaque multiple de 8 bits utilisé dans un nombre intermédiaire. Les tables de recherche sont possibles, mais utiliseraient à peu près la moitié de la capacité totale de l'appareil. Les algorithmes rapides sont donc les meilleurs pour la réutilisabilité, mais les algorithmes lents de bonne qualité sont également très utiles lorsqu'il y a de la place.

Merci de m'avoir aidé avec vos idées ou vos réflexions. :)

+0

Étiquette de devoirs manquante ... ;-) Désolé, mais l'avant-dernier paragraphe avec les coûts unitaires de temps imbéciles vous a donné. –

+0

@R haha ​​bon point. Je serais curieux de savoir quelle école donne des problèmes ouverts comme ça. Si aux États-Unis, peut-être un programme d'EE. Ne sent pas comme un devoir CS. –

+1

En fait, pas les devoirs. Je ne suis pas sûr exactement combien de cycles ces opérations prennent dans avr-libc. C'est juste ma compréhension générale du fonctionnement du chronométrage. Il me semblait préférable de ne pas être plus précis que de croire que quelqu'un critique l'inexactitude. :) – Blixxy

Répondre

4

Pas 100% sûr Je comprends bien, mais fondamentalement, je pense que tout nombre qui ne divise pas 256 va générer le groupe de nombres 0..255 si vous continuez à l'ajouter à lui-même modulo 256. flash-back de la classe d'algèbre abstraite ...

comme ceci:

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) 

EDIT: remplacé petit générateur avec une plus grande pour rendre la distribution plus « au hasard ».

+1

Aw man vous gagnez totalement! Cette chose ressemble à juste le billet. Plus d'ornements de bureau flickery pour moi! : D – Blixxy

+1

@ blixxy Chaque fois que j'utilise réellement les maths dont je me souviens, ça me rend si incroyablement heureux. –

4

Exemple: Utilisation d'un accumulateur de phase pour 5 bits tramage dans un registre à 8 bits, où service = 1 à 31% [= droit/(1 < < des bits)].

// 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 
} 

Les motifs de tramage ressemblent:

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 

FRQ faudra peut-être calculée dans une boucle un peu à la fois si vous ne disposez pas des entiers suffisamment larges (ou en assembleur quand il y a pas multiplier ni diviser).

En option, les motifs de tramage peuvent être précalculés et codés en tant que constantes dans une table de correspondance.

Seuls les motifs pour les puissances de deux n'ont aucun bruit; cela n'aura d'importance que si vous faites de la synthèse audio ou RF. Sinon, les autres motifs ont des birdies. Brouiller l'ordre des bits de motif après avoir sorti un motif une fois ajoute du bruit, mais supprime les birdies. Une fonction LFSR avec une longue période de répétition qui n'ajoute pas ou ne supprime pas de bits (le nombre de uns et de zéros reste le même, juste leurs changements d'ordre) pourrait être utilisée pour cela. Notez que pour émettre un motif complet à une fréquence d'images de 60 Hz, il faut utiliser une fréquence de vibration de 60 Hz * (1 < < bits) = 1,92 kHz. Probablement peut s'échapper avec une fréquence de tramage beaucoup plus faible pour LED sans scintillement, comme (1 < < bits) = 32 Hz. Expérience!

Questions connexes