diff options
author | Paweł Redman <pawel.redman@gmail.com> | 2020-02-16 11:14:09 +0100 |
---|---|---|
committer | Paweł Redman <pawel.redman@gmail.com> | 2020-02-16 11:18:55 +0100 |
commit | 87eb67408f9230315494a8cf66fe264196a04ad0 (patch) | |
tree | 63ee9d8b92b7cffaa38d83b4222ffd1e391eb75b /src |
Diffstat (limited to 'src')
-rw-r--r-- | src/cmf_xyz_v_lms.py | 33 | ||||
-rw-r--r-- | src/d_spektra.py | 20 | ||||
-rw-r--r-- | src/d_wektory_wlasne.py | 16 | ||||
-rw-r--r-- | src/demo_gai.py | 29 | ||||
-rw-r--r-- | src/demo_ra.py | 13 | ||||
-rw-r--r-- | src/diagram_UVstar.py | 8 | ||||
-rw-r--r-- | src/diagram_uv.py | 8 | ||||
-rw-r--r-- | src/diagram_uv76.py | 8 | ||||
-rw-r--r-- | src/diagram_uv_zoom.py | 10 | ||||
-rw-r--r-- | src/diagram_xy.py | 8 | ||||
-rw-r--r-- | src/lab.py | 29 | ||||
-rw-r--r-- | src/pasek_cct.py | 14 | ||||
-rw-r--r-- | src/pasek_tecza.py | 14 | ||||
-rw-r--r-- | src/planck.py | 22 | ||||
-rw-r--r-- | src/rea2008.py | 32 | ||||
-rw-r--r-- | src/shared.py | 221 | ||||
-rw-r--r-- | src/tcs_ra.py | 30 | ||||
-rw-r--r-- | src/tests.py | 91 |
18 files changed, 606 insertions, 0 deletions
diff --git a/src/cmf_xyz_v_lms.py b/src/cmf_xyz_v_lms.py new file mode 100644 index 0000000..d05211c --- /dev/null +++ b/src/cmf_xyz_v_lms.py @@ -0,0 +1,33 @@ +from shared import * +import crl, crl.tables as tab +import matplotlib.pyplot as plt + +plot_setup(width=0.7) + +fig, axes = plt.subplots(2, sharex=True, sharey=False, gridspec_kw={'hspace': 0}) + +for i, name in enumerate(["l", "m", "s"]): + axes[0].plot(tab.cmf_lms[:, 0], tab.cmf_lms[:, 1 + i], \ + ["r", "g", "b"][i], \ + label=("$\\overline{%s}(\\lambda)$" % name)) + +for i, name in enumerate(["x", "y", "z"]): + axes[1].plot(tab.cmf[:, 0], tab.cmf[:, 1 + i], \ + ["r", "g", "b"][i], \ + label=("$\\overline{%s}(\\lambda)$" % name)) + +for i, name in enumerate(["x", "y", "z"]): + axes[1].plot(tab.cmf_1964[:, 0], tab.cmf_1964[:, 1 + i], \ + ["r:", "g:", "b:"][i], \ + label=("$\\overline{%s}_{10}(\\lambda)$" % name)) + +for ax in axes: + plot_grid(ax) + ax.label_outer() + ax.set_xlim([380, 780]) + +axes[0].legend() +axes[1].legend(fontsize="small") + +axes[1].set_xlabel("$\lambda$ [nm]") +plot_export() diff --git a/src/d_spektra.py b/src/d_spektra.py new file mode 100644 index 0000000..39ea719 --- /dev/null +++ b/src/d_spektra.py @@ -0,0 +1,20 @@ +import numpy as np +from shared import * +import crl, crl.tables + +plot_setup(width=0.7) + +for T in reversed([5000, 5500, 6500, 7500]): + wvl = np.linspace(380, 780, 100) + n = crl.CIEDaylightSpectrum(T).Yi(wvl) + + plt.plot(wvl, n, + label="$D_{%d}$" % (T // 100)) + +plt.xlabel("$\\lambda$ [nm]") +plt.ylabel("$n_\\lambda(\\lambda)$") +plt.xlim(380, 780) +plt.ylim(0, 200) +plt.legend() +plot_grid() +plot_export() diff --git a/src/d_wektory_wlasne.py b/src/d_wektory_wlasne.py new file mode 100644 index 0000000..4bcdd66 --- /dev/null +++ b/src/d_wektory_wlasne.py @@ -0,0 +1,16 @@ +from shared import * +import crl, crl.tables + +plot_setup(width=0.7) + +for i in range(3): + plt.plot(crl.tables.D_eigenvectors[:, 0], + crl.tables.D_eigenvectors[:, i + 1], + ["k", "b", "g"][i] , label="$S_%d(\\lambda)$" % i) + +plt.xlabel("$\\lambda$ [nm]") +plt.ylabel("$n_\\lambda(\\lambda)$") +plt.xlim(300, 830) +plt.legend() +plot_grid() +plot_export() diff --git a/src/demo_gai.py b/src/demo_gai.py new file mode 100644 index 0000000..5de4f5b --- /dev/null +++ b/src/demo_gai.py @@ -0,0 +1,29 @@ +import numpy as np +import matplotlib.pyplot as plt +import crl, crl.tables, crl.data +from shared import * + + + +plot_setup(width=0.65) +plot_grid(minor=False) + +spec = crl.data.load("lab/2 grudnia/E27/Jarzeniówka 2700/Z korekcją.txt") +J27 = crl.Spectrum(spec[:, 0], spec[:, 1]) +spec = crl.data.load("lab/2 grudnia/E27/Jarzeniówka 6500/Z korekcją.txt") +J65 = crl.Spectrum(spec[:, 0], spec[:, 1]) + +crl.chromaticity_diagram(crl.uvY76, locus=False) +for i, (label, spec) in enumerate([ + ["CDC 2700 K", crl.BlackBodySpectrum(2700)], + ["JA27", J27], + ["$\\mathrm{D}_{65}$", crl.CIEDaylightSpectrum(6500)], + ["JA65", J65]]): + GAI, points = crl.cri_GAI(spec) + plot_GAI(points, pattern=["v--", "v-", "o--", "o-"][i], + label=label, alpha=(0.3 if "JA" in label else 0)) + +plt.xlim(0.14, 0.33) +plt.ylim(0.39, 0.56) +plt.legend() +plot_export() diff --git a/src/demo_ra.py b/src/demo_ra.py new file mode 100644 index 0000000..3bab2dc --- /dev/null +++ b/src/demo_ra.py @@ -0,0 +1,13 @@ +import numpy as np +import matplotlib.pyplot as plt +import crl, crl.tables, crl.data +from shared import * + +spec = crl.data.load("lab/2 grudnia/E27/LED OSSO/Z korekcją.txt") +spec = crl.Spectrum(spec[:, 0], spec[:, 1]) + +plot_setup() +plot_grid(minor=False) +res = crl.cri_Ra(spec) +plot_Ra(res) +plot_export() diff --git a/src/diagram_UVstar.py b/src/diagram_UVstar.py new file mode 100644 index 0000000..8f75a83 --- /dev/null +++ b/src/diagram_UVstar.py @@ -0,0 +1,8 @@ +from shared import * +import crl + +plot_setup(width=0.6, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.UVstarNormed, locus=True, isotherms=True, isotherm_labels=True) +plot_sRGB(crl.UVstarNormed) +plot_export() diff --git a/src/diagram_uv.py b/src/diagram_uv.py new file mode 100644 index 0000000..39b9094 --- /dev/null +++ b/src/diagram_uv.py @@ -0,0 +1,8 @@ +from shared import * +import crl + +plot_setup(width=0.6, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.uvY, locus=True, isotherms=True, isotherm_labels=True) +plot_sRGB(crl.uvY) +plot_export() diff --git a/src/diagram_uv76.py b/src/diagram_uv76.py new file mode 100644 index 0000000..0de8821 --- /dev/null +++ b/src/diagram_uv76.py @@ -0,0 +1,8 @@ +from shared import * +import crl + +plot_setup(width=0.6, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.uvY76, locus=True, isotherms=True, isotherm_labels=True) +plot_sRGB(crl.uvY76) +plot_export() diff --git a/src/diagram_uv_zoom.py b/src/diagram_uv_zoom.py new file mode 100644 index 0000000..c21fcd9 --- /dev/null +++ b/src/diagram_uv_zoom.py @@ -0,0 +1,10 @@ +from shared import * +import crl, matplotlib.pyplot as plt + +plot_setup(width=0.4, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.uvY, locus=True, isotherms=True, pures_labels=False, + isotherm_labels=True, isotherm_label_scale=1) +plt.xlim(0.17, 0.35) +plt.ylim(0.28, 0.38) +plot_export() diff --git a/src/diagram_xy.py b/src/diagram_xy.py new file mode 100644 index 0000000..d9c35eb --- /dev/null +++ b/src/diagram_xy.py @@ -0,0 +1,8 @@ +from shared import * +import crl + +plot_setup(width=0.6, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.xyY, locus=True, isotherms=True, isotherm_labels=True) +plot_sRGB(crl.xyY) +plot_export() diff --git a/src/lab.py b/src/lab.py new file mode 100644 index 0000000..9c32467 --- /dev/null +++ b/src/lab.py @@ -0,0 +1,29 @@ +import numpy as np +import crl, crl.data +from matplotlib import pyplot as plt +from shared import * + +lamps = [Lamp(k, *v) for k, v in labdb.items()] + +with TexWriter(os.path.join(os.path.dirname(__file__), "../build/lab1.tex")) as fd: + for lamp in lamps: + fd.write("%s & %g & %g & %.4g & $%s$ & %.1f & %.1f & %.1f & %.1f & %.1f \\\\\n" + % (lamp.lid, lamp.CCT_spec, lamp.ref_2deg["CCT"], + lamp.CCT, lamp.Ra_spec, lamp.ref_2deg["CRI"], + lamp.Ra.CRI, lamp.Ra.ECRI, lamp.GAI, lamp.FSCI)) + +with TexWriter(os.path.join(os.path.dirname(__file__), "../build/lab2a.tex")) as fd: + for lamp in lamps: + fd.write("%s" % lamp.lid) + for i in range(8): + fd.write(" & %.1f & %.1f" + % (lamp.ref_2deg["SCRI"][i], lamp.Ra.SCRIs[i])) + fd.write("\\\\\n") + +with TexWriter(os.path.join(os.path.dirname(__file__), "../build/lab2b.tex")) as fd: + for lamp in lamps: + fd.write("%s" % lamp.lid) + for i in range(8, 14): + fd.write(" & %.1f & %.1f" + % (lamp.ref_2deg["SCRI"][i], lamp.Ra.SCRIs[i])) + fd.write("\\\\\n") diff --git a/src/pasek_cct.py b/src/pasek_cct.py new file mode 100644 index 0000000..1653afd --- /dev/null +++ b/src/pasek_cct.py @@ -0,0 +1,14 @@ +from shared import * +import crl, numpy as np, matplotlib.pyplot as plt + +Ts = np.logspace(np.log10(1000), np.log10(10000)) +colors = [] +for T in Ts: + x, y, _ = crl.xyY(crl.BlackBodySpectrum(T)) + colors.append([*crl.sRGB(crl.xyY(x, y, 0.5))]) +colors = np.array(colors) + +plot_setup() +plot_colorbar(Ts, colors) +plt.xlabel("$T~[\\mathrm{K}]$") +plot_export()
\ No newline at end of file diff --git a/src/pasek_tecza.py b/src/pasek_tecza.py new file mode 100644 index 0000000..f831503 --- /dev/null +++ b/src/pasek_tecza.py @@ -0,0 +1,14 @@ +from shared import * +import crl, numpy as np, matplotlib.pyplot as plt + +wvls = np.linspace(380, 780, 200) +colors = [] +for wvl in wvls: + x, y, Y = crl.xyY(crl.PointSpectrum(wvl)) + colors.append([*crl.sRGB(crl.xyY(x, y, Y / 2))]) +colors = np.array(colors) + +plot_setup() +plot_colorbar(wvls, colors) +plt.xlabel("$\\lambda~[\\mathrm{nm}]$") +plot_export()
\ No newline at end of file diff --git a/src/planck.py b/src/planck.py new file mode 100644 index 0000000..711a973 --- /dev/null +++ b/src/planck.py @@ -0,0 +1,22 @@ +import matplotlib.pyplot as plt +import numpy as np +from shared import * + +plot_setup(width=0.5) + +h = 6.62607015e-34 +c = 299792458 +k_B = 1.380649e-23 + +wvl = 1e-9 * np.linspace(10, 2000, 200) + +for T in [3000, 4000, 5000]: + L = 2 * h * c ** 2 / (wvl ** 5 * (np.exp(h * c / (wvl * k_B * T)) - 1)) + plt.plot(1e+6 * wvl, 1e-12 * L, label="$T$ = %d K" % T) + +plt.xlim(0, 2) +plt.xlabel("$\\lambda~[\\mu\\mathrm{m}]$") +plt.ylabel("$L_\\lambda~\\left[\\frac{\\mathrm{kW}}{\\mathrm{sr}\\cdot\\mathrm{m}^2\\cdot\\mathrm{nm}}\\right]$") +plt.legend() +plot_grid() +plot_export() diff --git a/src/rea2008.py b/src/rea2008.py new file mode 100644 index 0000000..0621068 --- /dev/null +++ b/src/rea2008.py @@ -0,0 +1,32 @@ +import numpy as np, os +import crl, crl.data +from matplotlib import pyplot as plt +from shared import * + +rea2008 = [ + # CCT Ra GAI FSCI + ["CW1", 5137, 75, 65, 60], + ["CW2", 6682, 78, 97, 74], + ["CW3", 6126, 71, 81, 64], + ["CW4", 5854, 94, 99, 74], + ["WW1", 3174, 95, 55, 67], + ["WW2", 3443, 80, 64, 68], + ["WW3b", 3732, 81, 74, 72], + ["WW4", 3261, 91, 93, 77] +] + + +with TexWriter(os.path.join(os.path.dirname(__file__), "../build/rea2008.tex")) as fd: + for name, CCT_ref, Ra_ref, GAI_ref, FSCI_ref in rea2008: + path = os.path.join(os.path.dirname(__file__), "../lab/Rea2008/", name + ".csv") + data = np.sort(crl.data.load(path)) + data = data[np.lexsort((data[:, 0], data[:, 1]))] + spec = crl.Spectrum(data[:, 1], data[:, 0]) + + res = crl.cri_Ra(spec) + GAI, _ = crl.cri_GAI(spec) + FSCI = crl.cri_FSCI(spec) + + fd.write("%s & %g & %.4g & %g & %.1f & %g & %.1f & %g & %.1f \\\\\n" + % (name, CCT_ref, res.CCT, Ra_ref, res.CRI, + GAI_ref, GAI, FSCI_ref, FSCI)) diff --git a/src/shared.py b/src/shared.py new file mode 100644 index 0000000..a2b2b35 --- /dev/null +++ b/src/shared.py @@ -0,0 +1,221 @@ +import sys, numpy as np, os, re +from matplotlib import pyplot as plt, rc, rcParams, ticker +import crl +from matplotlib.patches import Polygon +from matplotlib.collections import PatchCollection + +class Bounds: + def __init__(self): + self.xmin = 0 + self.xmax = 0 + self.ymin = 0 + self.ymax = 0 + + def point(self, x, y): + self.xmin = min(self.xmin, x) + self.xmax = max(self.xmax, x) + self.ymin = min(self.ymin, y) + self.ymax = max(self.ymax, y) + + def extents(self, margin=0): + dx = (self.xmax - self.xmin) * margin + dy = (self.ymax - self.ymin) * margin + + return [self.xmin - dx , self.xmax + dx, + self.ymin - dy, self.ymax + dy] + + def set(self, margin=0, ax=plt): + xmin, xmax, ymin, ymax = self.extents(margin) + plt.xlim(xmin, xmax) + plt.ylim(ymin, ymax) + +def plot_setup(width=1, color_plot=False): + rcParams["font.family"] = 'serif' + rcParams["font.serif"] = ["C059"] + rcParams["font.size"] = 15 + rc("text", usetex=True) + rc("text.latex", preamble=\ + """\\usepackage{polski}""") + rcParams["savefig.dpi"] = 200 + rcParams["savefig.bbox"] = "tight" + + figwidth = width * 10 + if color_plot: + figwidth *= 1.7 + + figheight = figwidth * 0.75 + rcParams['figure.figsize'] = figwidth, figheight + +def texformatter_func(x, pos): + return ("%g" % x).replace(".", "{,}") +texformatter = ticker.FuncFormatter(texformatter_func) + +def plot_grid(ax=plt, minor=True): + if minor: + ax.minorticks_on() + ax.grid(b=True, which='major', linestyle='-', linewidth=0.75, color=[0.8, 0.8, 0.8]) + ax.grid(b=True, which='minor', linestyle='--', linewidth=0.75, color=[0.9, 0.9, 0.9]) + + if ax is plt: + ax = plt.gca() + ax.xaxis.set_major_formatter(texformatter) + ax.yaxis.set_major_formatter(texformatter) + #ax.xaxis.set_minor_formatter(texformatter) + #ax.yaxis.set_minor_formatter(texformatter) + + +def plot_longline(x1, y1, x2, y2, fmt, **kwargs): + axes = plt.axis() + plt.plot((x1, x2), (y1, y2), fmt, **kwargs) + plt.xlim([axes[0], axes[1]]) + plt.ylim([axes[2], axes[3]]) + +def plot_sRGB(CS, D65=True): + V = [ + crl.sRGB(1, 0, 0), + crl.sRGB(0, 1, 0), + crl.sRGB(0, 0, 1) + ] + V.append(V[0]) + + V = np.array([[*v.to(CS)] for v in V]) + plt.plot(V[:, 0], V[:, 1], "k:", label="sRGB") + + if D65: + x, y, _ = CS(crl.Illuminants.D65) + plt.plot(x, y, "k^", label="$\\mathrm{D}_{65}$") + + plt.legend() + +def plot_export(): + if len(sys.argv) > 1: + plt.savefig(sys.argv[1]) + else: + plt.show() + +def plot_colorbar(X, C): + C = np.expand_dims(C, axis=0) + ar = 10 + plt.imshow(C, extent=[min(X), max(X), min(X) / ar, max(X) / ar]) + plt.gca().axes.get_yaxis().set_visible(False) + +def plot_Ra(res, extended=True): + crl.chromaticity_diagram(crl.UVstarNormedD65, locus=False) + + bounds = Bounds() + for i in range(14 if extended else 8): + u, v, _ = crl.UVstarNormed.from_UVWstar(res.tcs[i]) + u0, v0, _ = crl.UVstarNormed.from_UVWstar(res.tcs_ref[i]) + + if np.sqrt((u - u0)**2 + (v - v0)**2) > 0.07: + plt.arrow(u0, v0, u - u0, v - v0, width=0.004, + length_includes_head=True, ec=None, fc="k") + plt.plot(u, v, "ko", markersize=5, label="TCS" if not i else None) + plt.scatter(u0, v0, s=50, facecolors="none", edgecolors="k") + + bounds.point(u, v) + bounds.point(u0, v0) + + plt.plot(0, 0, "kx", label="Punkt bieli") + bounds.point(0, 0) + bounds.set(margin=0.1) + +def plot_GAI(points, color="k", pattern="o-", label="Gama", alpha=0.3): + poly = Polygon(points) + col = PatchCollection([poly], fc=color, ec=color, alpha=alpha) + plt.gca().add_collection(col) + + points = np.concatenate([points, np.array([points[0, :]])], axis=0) + plt.plot(points[:, 0], points[:, 1], pattern, color=color, markersize=3, label=label) + + +def prefix(path): + return os.path.join(os.path.dirname(__file__), "../lab/", path) + +class Lamp: + def load_ref(path): + data = dict() + + with open(path) as fd: + for line in fd: + k, v = line.split("\t") + v = v.replace(",", ".") + + match = re.match("CRI R(.*)", k) + if match: + v = v.split(" ")[0] + + if match.group(1) == "a": + data["CRI"] = float(v) + else: + if "SCRI" not in data: + data["SCRI"] = [0] * 15 + data["SCRI"][int(match.group(1)) - 1] = float(v) + elif k == "CCT": + data["CCT"] = float(v[:-2]) + elif k in ["x", "y", "z", "X", "Y", "Z"]: + data[k] = float(v) + else: + data[k] = v + + data["XYZ"] = crl.XYZ(data["X"], data["Y"], data["Z"]) + data["xyY"] = crl.xyY(data["x"], data["y"], data["Y"]) + + return data + + def __init__(self, lid, Ra_spec, CCT_spec, path): + self.lid = lid + self.Ra_spec = Ra_spec + self.CCT_spec = CCT_spec + + data = crl.data.load(prefix(path + "/Surowe.txt")) + self.raw = crl.Spectrum(data[:, 0], data[:, 1]) + data = crl.data.load(prefix(path + "/Z korekcją.txt")) + self.spec = crl.Spectrum(data[:, 0], data[:, 1]) + + self.ref_2deg = Lamp.load_ref(prefix(path + "/Kolor 2deg.txt")) + self.ref_10deg = Lamp.load_ref(prefix(path + "/Kolor 10deg.txt")) + + self.CCT, self.dE = crl.cct(self.spec) + self.Ra = crl.cri_Ra(self.spec) + self.GAI, _ = crl.cri_GAI(self.spec) + self.FSCI = crl.cri_FSCI(self.spec) + + def load_labdb(key): + return Lamp(key, *labdb[key]) + +labdb = { + "Ż": ["100", 2700, "2 grudnia/E27/Żarówka"], + "JA27": ["\geq 80", 2700, "2 grudnia/E27/Jarzeniówka 2700"], + "JA65": ["\geq 80", 6500, "2 grudnia/E27/Jarzeniówka 6500"], + "JB27": ["\geq 80", 2700, "2 grudnia/E27/Duża jarzeniówka 2700"], + "LA": ["\geq 80", 3000, "2 grudnia/E27/LED OSSO"], + "LB30": ["80", 3000, "2 grudnia/GU10/LED 3000"], + "LB40": ["80", 4000, "2 grudnia/GU10/LED 4000"], + "LB65": ["80", 6500, "2 grudnia/GU10/LED 6500"], + "LB97": ["97", 4000, "6 grudnia/OSRAM"], + "LC1": ["\geq 72", 4000, "2 grudnia/GU10/Chiński I"], + "LC2": ["\geq 72", 4000, "2 grudnia/GU10/Chiński II"], + "LC3": ["\geq 72", 4000, "2 grudnia/GU10/Chiński III"], + "LC4": ["\geq 72", 4000, "2 grudnia/GU10/Chiński IV"], + "LC5": ["\geq 72", 4000, "2 grudnia/GU10/Chiński V"], + "T28": ["95", 2800, "6 grudnia/L2 2800K CRI95"], + "T30": ["95", 3000, "6 grudnia/L2 3000K CRI95"], + #"T30b": ["95", 3000, "6 grudnia/L2 3000K CRI95 bez soczewki"], + "T32": ["95", 3200, "6 grudnia/B2 3200K CRI95"], + "T40": ["96", 4000, "6 grudnia/B2 4000K CRI96"] +} + +class TexWriter(): + def __init__(self, path): + self.path = path + + def __enter__(self): + self.fd = open(self.path, "w") + return self + + def __exit__(self, type, value, traceback): + self.fd.close() + + def write(self, text): + self.fd.write(text.replace(".", "{,}")) diff --git a/src/tcs_ra.py b/src/tcs_ra.py new file mode 100644 index 0000000..e69a177 --- /dev/null +++ b/src/tcs_ra.py @@ -0,0 +1,30 @@ +from shared import * +import crl, crl.tables + +bounds = Bounds() + +plot_setup(width=0.5, color_plot=True) +plot_grid() +crl.chromaticity_diagram(crl.UVstarNormedD65, locus=True, isotherms=True, + pures_labels=False) + + +for i in range(14): + S = crl.Spectrum(crl.tables.tcs_ra[:, 0], crl.tables.tcs_ra[:, 1 + i]) + S = crl.CombinedSpectrum(S, crl.Illuminants.D65) + + u, v, _ = crl.UVstarNormedD65(S) + label = "%d" % (i + 1) + + plt.plot(u, v, "k+", label="TCS" if not i else None) + plt.annotate(label, xy=(u, v), xytext=(10, 0), + textcoords="offset points", fontsize=11, + verticalalignment="center", + horizontalalignment="left", + bbox=dict(boxstyle="square,pad=0.2", fc="white")) + bounds.point(u, v) + + +plot_sRGB(crl.UVstarNormedD65) +bounds.set(margin=0.1) +plot_export() diff --git a/src/tests.py b/src/tests.py new file mode 100644 index 0000000..9f20b3b --- /dev/null +++ b/src/tests.py @@ -0,0 +1,91 @@ +from crl import * +import random + +def pg(name): + pt() + print("\t%s" % name.upper()) +first = True +def pt(name=None): + global first + if first: + first = False + else: + print("OK") + + if name: + print("%s%s" % (name, "." * (40 - len(name))), end="") + else: + first = True +def fail(): + print("FAILED") + +def relerr(x, y): + return np.abs(x - y) / y + + +pg("D series (SPD synthesis)") + + +for T, ref in [[5000, Illuminants.D50], + [5500, Illuminants.D55], + [6500, Illuminants.D65]]: + pt(f"D{T//100}") + spec = CIEDaylightSpectrum(T) + + wvl = np.linspace(380, 780, 1000) + Yspec = spec.Yi(wvl) + Yref = ref.Yi(wvl) + error = np.abs(Yspec - Yref) / Yref + if np.max(error) > 0.01: + fail() + exit(1) + +pg("Color space inversion tests") + +spaces = [sRGB, xyY, UVW, uvY, UVWstarD65, UVstarNormedD65, uvY76, LabstarD65, LuvstarD65] + +for CS in spaces: + pt(CS.full_name) + + for i in range(150): + X0 = XYZ(random.random(), random.random(), random.random()) + X = list(CS.from_XYZ(X0).to_XYZ()) + + for i in range(3): + if abs(X[i] - X0[i]) > 1e-9: + fail() + print(f" Input: {[*X0]}") + print(f"Output: {[*X]}") + exit(1) + +pg("F series (CCT, CRI Ra)") + +F_xs = [0.3131, 0.3721, 0.4091, 0.4402, 0.3138, 0.3779, 0.3129, 0.3458, 0.3741, 0.3458, 0.3805, 0.437] +F_ys = [0.3371, 0.3751, 0.3941, 0.4031, 0.3452, 0.3882, 0.3292, 0.3586, 0.3727, 0.3588, 0.3769, 0.4042] +F_CCTs = [6430, 4230, 3450, 2940, 6350, 4150, 6500, 5000, 4150, 5000, 4000, 3000] +F_Ras = [76, 64, 57, 51, 72, 59, 90, 95, 90, 81, 83, 83] + +for i in range(12): + pt(f"F{i + 1}") + + spec = Spectrum(tables.illuminants_F[:, 0], tables.illuminants_F[:, 1 + i]) + + x, y, _ = xyY(spec) + if relerr(x, F_xs[i]) > 0.01 or relerr(y, F_ys[i]) > 0.01: + fail() + print(f"Wrong chromaticity: {x}, {y} != {F_xs[i]}, {F_ys[i]}") + #exit(1) + + CCT, _ = cct(spec) + if relerr(CCT, F_CCTs[i]) > 0.01: + fail() + print(f"Wrong CCT: {CCT} != {F_CCTs[i]}") + #exit(1) + + res = cri_Ra(spec) + if round(res.CRI) != F_Ras[i]: + fail() + print(f"Wrong CRI Ra: {res.CRI} != {F_Ras[i]}") + #exit(1) + +pt() |