Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: KL25Z_HSI2RGBW_PWM KL25Z_HSI2RGBW_PWM_local KL25Z_FFT_Demo FFT_BUENA ... more
hsi2rgbw_pwm.cpp@2:d164d60999c4, 2013-12-24 (annotated)
- Committer:
- frankvnk
- Date:
- Tue Dec 24 06:29:38 2013 +0000
- Revision:
- 2:d164d60999c4
- Parent:
- 0:dd0e7a8a4572
- Child:
- 3:dda6914d713f
added GPL license info
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
frankvnk | 2:d164d60999c4 | 1 | /************************************************************************************************************** |
frankvnk | 2:d164d60999c4 | 2 | ***** ***** |
frankvnk | 2:d164d60999c4 | 3 | ***** Name: hsi2rgbw.cpp ***** |
frankvnk | 2:d164d60999c4 | 4 | ***** Date: 22/12/2013 ***** |
frankvnk | 2:d164d60999c4 | 5 | ***** Auth: Frank Vannieuwkerke ***** |
frankvnk | 2:d164d60999c4 | 6 | ***** Func: library for converting HSI color space values to RGBW ***** |
frankvnk | 2:d164d60999c4 | 7 | ***** ***** |
frankvnk | 2:d164d60999c4 | 8 | ***** Code ported from http://saikoled.com - Copyright 2013, Brian Neltner ***** |
frankvnk | 2:d164d60999c4 | 9 | ***** http://blog.saikoled.com/post/44677718712/how-to-convert-from-hsi-to-rgb-white ***** |
frankvnk | 2:d164d60999c4 | 10 | ***** http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi-colorspace ***** |
frankvnk | 2:d164d60999c4 | 11 | ***** https://github.com/saikoLED/MyKi/blob/master/myki_16_bit_random_fade/myki_16_bit_random_fade.ino ***** |
frankvnk | 2:d164d60999c4 | 12 | ***** https://github.com/saikoLED/MyKi/blob/master/myki_16_bit_fade/myki_16_bit_fade.ino ***** |
frankvnk | 2:d164d60999c4 | 13 | ***** ***** |
frankvnk | 2:d164d60999c4 | 14 | ***** This program is free software: you can redistribute it and/or modify ***** |
frankvnk | 2:d164d60999c4 | 15 | ***** it under the terms of the GNU General Public License as published by ***** |
frankvnk | 2:d164d60999c4 | 16 | ***** the Free Software Foundation, version 3 of the License. ***** |
frankvnk | 2:d164d60999c4 | 17 | ***** ***** |
frankvnk | 2:d164d60999c4 | 18 | ***** This program is distributed in the hope that it will be useful, ***** |
frankvnk | 2:d164d60999c4 | 19 | ***** but WITHOUT ANY WARRANTY; without even the implied warranty of ***** |
frankvnk | 2:d164d60999c4 | 20 | ***** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ***** |
frankvnk | 2:d164d60999c4 | 21 | ***** GNU General Public License for more details. ***** |
frankvnk | 2:d164d60999c4 | 22 | ***** ***** |
frankvnk | 2:d164d60999c4 | 23 | ***** A copy of the GNU General Public License can be found at ***** |
frankvnk | 2:d164d60999c4 | 24 | ***** http://www.gnu.org/licenses/gpl.html ***** |
frankvnk | 2:d164d60999c4 | 25 | **************************************************************************************************************/ |
frankvnk | 2:d164d60999c4 | 26 | |
frankvnk | 0:dd0e7a8a4572 | 27 | #include "hsi2rgbw_pwm.h" |
frankvnk | 0:dd0e7a8a4572 | 28 | |
frankvnk | 0:dd0e7a8a4572 | 29 | #define PI 3.14159265 |
frankvnk | 0:dd0e7a8a4572 | 30 | |
frankvnk | 0:dd0e7a8a4572 | 31 | hsi2rgbw_pwm::hsi2rgbw_pwm(PinName red, PinName green, PinName blue, PinName white) : _red(red), _green(green), _blue(blue), _white(white) |
frankvnk | 0:dd0e7a8a4572 | 32 | { |
frankvnk | 0:dd0e7a8a4572 | 33 | parabol = 1; |
frankvnk | 0:dd0e7a8a4572 | 34 | use_rgbw = RGBW; |
frankvnk | 0:dd0e7a8a4572 | 35 | if(_red == NC && _green == NC && _blue == NC) |
frankvnk | 0:dd0e7a8a4572 | 36 | { |
frankvnk | 0:dd0e7a8a4572 | 37 | use_pwm = 0; |
frankvnk | 0:dd0e7a8a4572 | 38 | } |
frankvnk | 0:dd0e7a8a4572 | 39 | else |
frankvnk | 0:dd0e7a8a4572 | 40 | { |
frankvnk | 0:dd0e7a8a4572 | 41 | use_pwm = 1; |
frankvnk | 0:dd0e7a8a4572 | 42 | //Setup PWM channels - default period = 4 ms (250Hz) |
frankvnk | 0:dd0e7a8a4572 | 43 | _red.period_ms(4); |
frankvnk | 0:dd0e7a8a4572 | 44 | _green.period_ms(4); |
frankvnk | 0:dd0e7a8a4572 | 45 | _blue.period_ms(4); |
frankvnk | 0:dd0e7a8a4572 | 46 | if(_white != NC) |
frankvnk | 0:dd0e7a8a4572 | 47 | _white.period_ms(4); |
frankvnk | 0:dd0e7a8a4572 | 48 | |
frankvnk | 0:dd0e7a8a4572 | 49 | // Initial RGB values. |
frankvnk | 0:dd0e7a8a4572 | 50 | _red = 0.0f; |
frankvnk | 0:dd0e7a8a4572 | 51 | _green = 0.0f; |
frankvnk | 0:dd0e7a8a4572 | 52 | _blue = 0.0f; |
frankvnk | 0:dd0e7a8a4572 | 53 | if(_white != NC) |
frankvnk | 0:dd0e7a8a4572 | 54 | _white = 0.0f; |
frankvnk | 0:dd0e7a8a4572 | 55 | } |
frankvnk | 0:dd0e7a8a4572 | 56 | } |
frankvnk | 0:dd0e7a8a4572 | 57 | |
frankvnk | 0:dd0e7a8a4572 | 58 | void hsi2rgbw_pwm::hsi2rgbw(float H, float S, float I, float* rgbw) { |
frankvnk | 0:dd0e7a8a4572 | 59 | float _rgbw[4]; |
frankvnk | 0:dd0e7a8a4572 | 60 | if(rgbw == NULL) |
frankvnk | 0:dd0e7a8a4572 | 61 | rgbw = _rgbw; |
frankvnk | 0:dd0e7a8a4572 | 62 | float cos_h, Srgb; |
frankvnk | 0:dd0e7a8a4572 | 63 | H = fmod(H,360); // cycle H around to 0-360 degrees |
frankvnk | 0:dd0e7a8a4572 | 64 | H = PI*H/(float)180; // Convert to radians. |
frankvnk | 0:dd0e7a8a4572 | 65 | S = S>0?(S<1?S:1):0; // clamp S and I to interval [0,1] |
frankvnk | 0:dd0e7a8a4572 | 66 | I = I>0?(I<1?I:1):0; |
frankvnk | 0:dd0e7a8a4572 | 67 | if(use_rgbw) |
frankvnk | 0:dd0e7a8a4572 | 68 | Srgb = 1; |
frankvnk | 0:dd0e7a8a4572 | 69 | else |
frankvnk | 0:dd0e7a8a4572 | 70 | { |
frankvnk | 0:dd0e7a8a4572 | 71 | Srgb = S; |
frankvnk | 0:dd0e7a8a4572 | 72 | S = 1; |
frankvnk | 0:dd0e7a8a4572 | 73 | } |
frankvnk | 0:dd0e7a8a4572 | 74 | // This section is modified by the addition of white so that it assumes |
frankvnk | 0:dd0e7a8a4572 | 75 | // fully saturated colors, and then scales with white to lower saturation. |
frankvnk | 0:dd0e7a8a4572 | 76 | // |
frankvnk | 0:dd0e7a8a4572 | 77 | // Next, scale appropriately the pure color by mixing with the white channel. |
frankvnk | 0:dd0e7a8a4572 | 78 | // Saturation is defined as "the ratio of colorfulness to brightness" so we will |
frankvnk | 0:dd0e7a8a4572 | 79 | // do this by a simple ratio wherein the color values are scaled down by (1-S) |
frankvnk | 0:dd0e7a8a4572 | 80 | // while the white LED is placed at S. |
frankvnk | 0:dd0e7a8a4572 | 81 | |
frankvnk | 0:dd0e7a8a4572 | 82 | // This will maintain constant brightness because in HSI, R+B+G = I. Thus, |
frankvnk | 0:dd0e7a8a4572 | 83 | // S*(R+B+G) = S*I. If we add to this (1-S)*I, where I is the total intensity, |
frankvnk | 0:dd0e7a8a4572 | 84 | // the sum intensity stays constant while the ratio of colorfulness to brightness |
frankvnk | 0:dd0e7a8a4572 | 85 | // goes down by S linearly relative to total Intensity, which is constant. |
frankvnk | 0:dd0e7a8a4572 | 86 | |
frankvnk | 0:dd0e7a8a4572 | 87 | if(H < 2.09439) { |
frankvnk | 0:dd0e7a8a4572 | 88 | cos_h = cos(H) / cos(1.047196667-H); |
frankvnk | 0:dd0e7a8a4572 | 89 | rgbw[0] = S*I/3*(1+Srgb*cos_h); |
frankvnk | 0:dd0e7a8a4572 | 90 | rgbw[1] = S*I/3*(1+Srgb*(1-cos_h)); |
frankvnk | 0:dd0e7a8a4572 | 91 | if(use_rgbw) |
frankvnk | 0:dd0e7a8a4572 | 92 | { |
frankvnk | 0:dd0e7a8a4572 | 93 | rgbw[2] = 0; |
frankvnk | 0:dd0e7a8a4572 | 94 | rgbw[3] = (1-S)*I; |
frankvnk | 0:dd0e7a8a4572 | 95 | } |
frankvnk | 0:dd0e7a8a4572 | 96 | else |
frankvnk | 0:dd0e7a8a4572 | 97 | rgbw[2] = I/3*(1-Srgb); |
frankvnk | 0:dd0e7a8a4572 | 98 | } else if(H < 4.188787) { |
frankvnk | 0:dd0e7a8a4572 | 99 | H = H - 2.09439; |
frankvnk | 0:dd0e7a8a4572 | 100 | cos_h = cos(H) / cos(1.047196667-H); |
frankvnk | 0:dd0e7a8a4572 | 101 | rgbw[1] = S*I/3*(1+Srgb*cos_h); |
frankvnk | 0:dd0e7a8a4572 | 102 | rgbw[2] = S*I/3*(1+Srgb*(1-cos_h)); |
frankvnk | 0:dd0e7a8a4572 | 103 | if(use_rgbw) |
frankvnk | 0:dd0e7a8a4572 | 104 | { |
frankvnk | 0:dd0e7a8a4572 | 105 | rgbw[0] = 0; |
frankvnk | 0:dd0e7a8a4572 | 106 | rgbw[3] = (1-S)*I; |
frankvnk | 0:dd0e7a8a4572 | 107 | } |
frankvnk | 0:dd0e7a8a4572 | 108 | else |
frankvnk | 0:dd0e7a8a4572 | 109 | rgbw[0] = I/3*(1-Srgb); |
frankvnk | 0:dd0e7a8a4572 | 110 | } else { |
frankvnk | 0:dd0e7a8a4572 | 111 | H = H - 4.188787; |
frankvnk | 0:dd0e7a8a4572 | 112 | cos_h = cos(H) / cos(1.047196667-H); |
frankvnk | 0:dd0e7a8a4572 | 113 | rgbw[2] = S*I/3*(1+Srgb*cos_h); |
frankvnk | 0:dd0e7a8a4572 | 114 | rgbw[0] = S*I/3*(1+Srgb*(1-cos_h)); |
frankvnk | 0:dd0e7a8a4572 | 115 | if(use_rgbw) |
frankvnk | 0:dd0e7a8a4572 | 116 | { |
frankvnk | 0:dd0e7a8a4572 | 117 | rgbw[1] = 0; |
frankvnk | 0:dd0e7a8a4572 | 118 | rgbw[3] = (1-S)*I; |
frankvnk | 0:dd0e7a8a4572 | 119 | } |
frankvnk | 0:dd0e7a8a4572 | 120 | else |
frankvnk | 0:dd0e7a8a4572 | 121 | rgbw[1] = I/3*(1-Srgb); |
frankvnk | 0:dd0e7a8a4572 | 122 | } |
frankvnk | 0:dd0e7a8a4572 | 123 | |
frankvnk | 0:dd0e7a8a4572 | 124 | // parabolic mapping. |
frankvnk | 0:dd0e7a8a4572 | 125 | if(parabol) { |
frankvnk | 0:dd0e7a8a4572 | 126 | rgbw[0] *= rgbw[0]; // RED |
frankvnk | 0:dd0e7a8a4572 | 127 | rgbw[1] *= rgbw[1]; // GREEN |
frankvnk | 0:dd0e7a8a4572 | 128 | rgbw[2] *= rgbw[2]; // BLUE |
frankvnk | 0:dd0e7a8a4572 | 129 | if(use_rgbw) |
frankvnk | 0:dd0e7a8a4572 | 130 | rgbw[3] *= rgbw[3]; // WHITE |
frankvnk | 0:dd0e7a8a4572 | 131 | } |
frankvnk | 0:dd0e7a8a4572 | 132 | if(use_pwm) |
frankvnk | 0:dd0e7a8a4572 | 133 | { |
frankvnk | 0:dd0e7a8a4572 | 134 | _red = rgbw[0]; |
frankvnk | 0:dd0e7a8a4572 | 135 | _green = rgbw[1]; |
frankvnk | 0:dd0e7a8a4572 | 136 | _blue = rgbw[2]; |
frankvnk | 0:dd0e7a8a4572 | 137 | if(_white != NC) |
frankvnk | 0:dd0e7a8a4572 | 138 | _white = rgbw[3]; |
frankvnk | 0:dd0e7a8a4572 | 139 | } |
frankvnk | 0:dd0e7a8a4572 | 140 | } |
frankvnk | 0:dd0e7a8a4572 | 141 | |
frankvnk | 0:dd0e7a8a4572 | 142 | void hsi2rgbw_pwm::period(uint32_t per) |
frankvnk | 0:dd0e7a8a4572 | 143 | { |
frankvnk | 0:dd0e7a8a4572 | 144 | if(use_pwm) |
frankvnk | 0:dd0e7a8a4572 | 145 | { |
frankvnk | 0:dd0e7a8a4572 | 146 | _red.period_ms(per); |
frankvnk | 0:dd0e7a8a4572 | 147 | _green.period_ms(per); |
frankvnk | 0:dd0e7a8a4572 | 148 | _blue.period_ms(per); |
frankvnk | 0:dd0e7a8a4572 | 149 | if(_white != NC) |
frankvnk | 0:dd0e7a8a4572 | 150 | _white.period_ms(per); |
frankvnk | 0:dd0e7a8a4572 | 151 | } |
frankvnk | 0:dd0e7a8a4572 | 152 | } |
frankvnk | 0:dd0e7a8a4572 | 153 | |
frankvnk | 0:dd0e7a8a4572 | 154 | void hsi2rgbw_pwm::pwm(float* rgbw) |
frankvnk | 0:dd0e7a8a4572 | 155 | { |
frankvnk | 0:dd0e7a8a4572 | 156 | if(use_pwm) |
frankvnk | 0:dd0e7a8a4572 | 157 | { |
frankvnk | 0:dd0e7a8a4572 | 158 | _red = rgbw[0]; |
frankvnk | 0:dd0e7a8a4572 | 159 | _green = rgbw[1]; |
frankvnk | 0:dd0e7a8a4572 | 160 | _blue = rgbw[2]; |
frankvnk | 0:dd0e7a8a4572 | 161 | if(_white != NC) |
frankvnk | 0:dd0e7a8a4572 | 162 | _white = rgbw[3]; |
frankvnk | 0:dd0e7a8a4572 | 163 | } |
frankvnk | 0:dd0e7a8a4572 | 164 | } |
frankvnk | 0:dd0e7a8a4572 | 165 | |
frankvnk | 0:dd0e7a8a4572 | 166 | void hsi2rgbw_pwm::parabolic(bool para) |
frankvnk | 0:dd0e7a8a4572 | 167 | { |
frankvnk | 0:dd0e7a8a4572 | 168 | parabol = para; |
frankvnk | 0:dd0e7a8a4572 | 169 | } |
frankvnk | 0:dd0e7a8a4572 | 170 | |
frankvnk | 0:dd0e7a8a4572 | 171 | void hsi2rgbw_pwm::colorMode(bool como) |
frankvnk | 0:dd0e7a8a4572 | 172 | { |
frankvnk | 0:dd0e7a8a4572 | 173 | use_rgbw = como; |
frankvnk | 0:dd0e7a8a4572 | 174 | } |