summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2020-02-16 11:14:09 +0100
committerPaweł Redman <pawel.redman@gmail.com>2020-02-16 11:18:55 +0100
commit87eb67408f9230315494a8cf66fe264196a04ad0 (patch)
tree63ee9d8b92b7cffaa38d83b4222ffd1e391eb75b /src
Ostateczna wersja pracy dyplomowejHEADmaster
Diffstat (limited to 'src')
-rw-r--r--src/cmf_xyz_v_lms.py33
-rw-r--r--src/d_spektra.py20
-rw-r--r--src/d_wektory_wlasne.py16
-rw-r--r--src/demo_gai.py29
-rw-r--r--src/demo_ra.py13
-rw-r--r--src/diagram_UVstar.py8
-rw-r--r--src/diagram_uv.py8
-rw-r--r--src/diagram_uv76.py8
-rw-r--r--src/diagram_uv_zoom.py10
-rw-r--r--src/diagram_xy.py8
-rw-r--r--src/lab.py29
-rw-r--r--src/pasek_cct.py14
-rw-r--r--src/pasek_tecza.py14
-rw-r--r--src/planck.py22
-rw-r--r--src/rea2008.py32
-rw-r--r--src/shared.py221
-rw-r--r--src/tcs_ra.py30
-rw-r--r--src/tests.py91
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()