0e73fd1348
* Resolved an issue with the ESP8266 where gamma correction would be performed twice. Changed GAMMA_CORRECTION to SOFTWARE_GAMMA_CORRECTION to make a distinction between software and firmware gamma correction. The ESP8266 does firmware gamma correction and dithering, while the Raspberry Pi uses slightly more inferior software gamma correction. Changed the software gamma table to match the gamma table used in the ESP8266 firmware. * Improved the spectrum visualization by using one of the color channels to visualize the absolute value of the temporal derivative of the spectrum. Also added a feature to reject the "common mode" spectral components, which is analogous to the spectral DC component. * Signficantly improved the GUI and added a frequency adjustment slider. Adjusting the frequency range has a big impact on the visualization output. Recommend using a high frequency range (something like 4 kHz - 10 kHz) when running the scrol visualization.
116 lines
3.9 KiB
Python
116 lines
3.9 KiB
Python
from __future__ import print_function
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import numpy as np
|
|
import config
|
|
|
|
# ESP8266 uses WiFi communication
|
|
if config.DEVICE == 'esp8266':
|
|
import socket
|
|
_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
# Raspberry Pi controls the LED strip directly
|
|
elif config.DEVICE == 'pi':
|
|
import neopixel
|
|
strip = neopixel.Adafruit_NeoPixel(config.N_PIXELS, config.LED_PIN,
|
|
config.LED_FREQ_HZ, config.LED_DMA,
|
|
config.LED_INVERT, config.BRIGHTNESS)
|
|
strip.begin()
|
|
|
|
_gamma = np.load(config.GAMMA_TABLE_PATH)
|
|
"""Gamma lookup table used for nonlinear brightness correction"""
|
|
|
|
_prev_pixels = np.tile(253, (3, config.N_PIXELS))
|
|
"""Pixel values that were most recently displayed on the LED strip"""
|
|
|
|
pixels = np.tile(1, (3, config.N_PIXELS))
|
|
"""Pixel values for the LED strip"""
|
|
|
|
|
|
def _update_esp8266():
|
|
"""Sends UDP packets to ESP8266 to update LED strip values
|
|
|
|
The ESP8266 will receive and decode the packets to determine what values
|
|
to display on the LED strip. The communication protocol supports LED strips
|
|
with a maximum of 256 LEDs.
|
|
|
|
The packet encoding scheme is:
|
|
|i|r|g|b|
|
|
where
|
|
i (0 to 255): Index of LED to change (zero-based)
|
|
r (0 to 255): Red value of LED
|
|
g (0 to 255): Green value of LED
|
|
b (0 to 255): Blue value of LED
|
|
"""
|
|
global pixels, _prev_pixels
|
|
# Truncate values and cast to integer
|
|
pixels = np.clip(pixels, 0, 255).astype(int)
|
|
# Optionally apply gamma correctio
|
|
p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
|
|
# Send UDP packets when using ESP8266
|
|
m = []
|
|
for i in range(config.N_PIXELS):
|
|
# Ignore pixels if they haven't changed (saves bandwidth)
|
|
if np.array_equal(p[:, i], _prev_pixels[:, i]):
|
|
continue
|
|
# Byte
|
|
m.append(i) # Index of pixel to change
|
|
m.append(p[0][i]) # Pixel red value
|
|
m.append(p[1][i]) # Pixel green value
|
|
m.append(p[2][i]) # Pixel blue value
|
|
_prev_pixels = np.copy(p)
|
|
_sock.sendto(bytes(m), (config.UDP_IP, config.UDP_PORT))
|
|
|
|
|
|
def _update_pi():
|
|
"""Writes new LED values to the Raspberry Pi's LED strip
|
|
|
|
Raspberry Pi uses the rpi_ws281x to control the LED strip directly.
|
|
This function updates the LED strip with new values.
|
|
"""
|
|
global pixels, _prev_pixels
|
|
# Truncate values and cast to integer
|
|
pixels = np.clip(pixels, 0, 255).astype(long)
|
|
# Optional gamma correction
|
|
p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
|
|
# Encode 24-bit LED values in 32 bit integers
|
|
r = np.left_shift(p[0][:].astype(int), 8)
|
|
g = np.left_shift(p[1][:].astype(int), 16)
|
|
b = p[2][:].astype(int)
|
|
rgb = np.bitwise_or(np.bitwise_or(r, g), b)
|
|
# Update the pixels
|
|
for i in range(config.N_PIXELS):
|
|
# Ignore pixels if they haven't changed (saves bandwidth)
|
|
if np.array_equal(p[:, i], _prev_pixels[:, i]):
|
|
continue
|
|
strip._led_data[i] = rgb[i]
|
|
_prev_pixels = np.copy(p)
|
|
strip.show()
|
|
|
|
|
|
def update():
|
|
"""Updates the LED strip values"""
|
|
if config.DEVICE == 'esp8266':
|
|
_update_esp8266()
|
|
elif config.DEVICE == 'pi':
|
|
_update_pi()
|
|
else:
|
|
raise ValueError('Invalid device selected')
|
|
|
|
|
|
# Execute this file to run a LED strand test
|
|
# If everything is working, you should see a red, green, and blue pixel scroll
|
|
# across the LED strip continously
|
|
if __name__ == '__main__':
|
|
import time
|
|
# Turn all pixels off
|
|
pixels *= 0
|
|
pixels[0, 0] = 255 # Set 1st pixel red
|
|
pixels[1, 1] = 255 # Set 2nd pixel green
|
|
pixels[2, 2] = 255 # Set 3rd pixel blue
|
|
print('Starting LED strand test')
|
|
while True:
|
|
pixels = np.roll(pixels, 1, axis=1)
|
|
update()
|
|
time.sleep(0.01)
|