Initial import of Microtracking project
This commit is contained in:
commit
60720c388c
2265 files changed
+1464696
No files matched your search
@@ -0,0 +1,139 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Heatmap de posicion solar real (MicrotrackingFer 2026-10-15).
|
||||
Mapeo de adc_manager.cpp: C=canal1(fotocorriente), P=canal2(piranometro), V=canal3(Voc).
|
||||
Calibracion parse_log.py, ADS122C04 24-bit, Vref 2.048 V.
|
||||
P del log es 24-bit 2's complement sin signo; de noche ~16.7M => se extiende signo y se apoda <0 a 0.
|
||||
"""
|
||||
import re
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import Normalize
|
||||
|
||||
LOG = r"C:\Users\fdavalos\OneDrive - up.edu.mx\microtracking\MicrotrackingFer\logs_nuevos\log_2026-10-15.txt"
|
||||
OUT_PNG = r"C:\Users\fdavalos\OneDrive - up.edu.mx\microtracking\MicrotrackingFer\heatmap_2026-10-15.png"
|
||||
|
||||
ADC_MAX = 8388607.0
|
||||
GAIN_SHUNT = 20.0
|
||||
R_SHUNT = 0.075
|
||||
|
||||
|
||||
def isc_ma(c_raw):
|
||||
vsh_mV = c_raw / ADC_MAX * 2048.0 / GAIN_SHUNT
|
||||
return (vsh_mV / 1000.0) / R_SHUNT * 1000.0
|
||||
|
||||
|
||||
def g_wm2(p_signed):
|
||||
return p_signed / ADC_MAX * 2048.0 / 2.0
|
||||
|
||||
|
||||
def sign24(raw):
|
||||
raw &= 0xFFFFFF
|
||||
if raw & 0x00800000:
|
||||
raw -= 0x1000000
|
||||
return raw
|
||||
|
||||
|
||||
RE = re.compile(
|
||||
r"LOG:\[(?P<t>[^\]]+)\]\s*"
|
||||
r"X:(?P<x>-?\d+),Y:(?P<y>-?\d+),C:(?P<c>-?\d+),V:(?P<v>-?\d+),"
|
||||
r"P:(?P<p>-?\d+),S:(?P<s>-?\d+),er:(?P<er>-?\d+)"
|
||||
)
|
||||
|
||||
ts, xs, ys, cs, ps = [], [], [], [], []
|
||||
with open(LOG, "r", encoding="utf-8", errors="replace") as f:
|
||||
for line in f:
|
||||
m = RE.search(line)
|
||||
if m:
|
||||
ts.append(m.group("t"))
|
||||
xs.append(int(m.group("x")))
|
||||
ys.append(int(m.group("y")))
|
||||
cs.append(int(m.group("c")))
|
||||
ps.append(sign24(int(m.group("p"))))
|
||||
|
||||
xs = np.array(xs); ys = np.array(ys); cs = np.array(cs, dtype=float)
|
||||
ps = np.array(ps, dtype=float)
|
||||
p_irr = np.maximum(0.0, ps)
|
||||
c_mA = isc_ma(cs)
|
||||
g_w = g_wm2(p_irr)
|
||||
|
||||
print("Muestras:", len(xs))
|
||||
print("Rango X: %d..%d Rango Y: %d..%d" % (xs.min(), xs.max(), ys.min(), ys.max()))
|
||||
print("Pico C : X=%d Y=%d C=%d (Isc=%.1f mA)" %
|
||||
(xs[np.argmax(c_mA)], ys[np.argmax(c_mA)], cs.max(), c_mA.max()))
|
||||
print("Pico P : X=%d Y=%d P=%d (G=%.1f W/m2)" %
|
||||
(xs[np.argmax(p_irr)], ys[np.argmax(p_irr)], int(p_irr.max()), g_w.max()))
|
||||
xbins = np.linspace(0, 115000, 61)
|
||||
ybins = np.linspace(35000, 80000, 46)
|
||||
|
||||
|
||||
def bin_max(x, y, vals):
|
||||
xi = np.clip(np.searchsorted(xbins, x, side="right") - 1, 0, len(xbins) - 2)
|
||||
yi = np.clip(np.searchsorted(ybins, y, side="right") - 1, 0, len(ybins) - 2)
|
||||
grid = np.full((len(ybins) - 1, len(xbins) - 1), -np.inf)
|
||||
np.maximum.at(grid, (yi, xi), vals)
|
||||
grid[grid == -np.inf] = np.nan # celdas vacias -> NaN
|
||||
return grid
|
||||
|
||||
|
||||
maxC = bin_max(xs, ys, c_mA)
|
||||
maxP = bin_max(xs, ys, g_w)
|
||||
nC = np.nan_to_num(maxC / np.nanmax(maxC))
|
||||
nP = np.nan_to_num(maxP / np.nanmax(maxP))
|
||||
co = np.ma.masked_invalid(np.minimum(nC, nP))
|
||||
|
||||
xc = (xbins[:-1] + xbins[1:]) / 2
|
||||
yc = (ybins[:-1] + ybins[1:]) / 2
|
||||
|
||||
w = np.where(co > 0.5 * np.nanmax(co), co, 0.0)
|
||||
if w.sum() > 0:
|
||||
com_x = np.nansum(w * xc[None, :]) / np.nansum(w)
|
||||
com_y = np.nansum(w * yc[:, None]) / np.nansum(w)
|
||||
else:
|
||||
com_x = com_y = np.nan
|
||||
pi, pj = np.unravel_index(np.nanargmax(co), co.shape)
|
||||
co_peak_x, co_peak_y = xc[pj], yc[pi]
|
||||
|
||||
print("Co-pico (C & P) celda: X~%.0f Y~%.0f" % (co_peak_x, co_peak_y))
|
||||
print("Centro de masa (co>0.5max): X~%.0f Y~%.0f" % (com_x, com_y))
|
||||
|
||||
fig, axes = plt.subplots(1, 3, figsize=(20, 6.2), sharex=True, sharey=True)
|
||||
cmap = "inferno"
|
||||
|
||||
|
||||
def draw_heat(ax, grid, title, cunit):
|
||||
im = ax.imshow(np.ma.masked_invalid(grid),
|
||||
extent=[xbins[0], xbins[-1], ybins[0], ybins[-1]],
|
||||
origin="lower", aspect="auto", cmap=cmap,
|
||||
norm=Normalize(vmin=0, vmax=np.nanmax(grid)))
|
||||
ax.set_title(title)
|
||||
ax.set_xlabel("X (paso)")
|
||||
ax.set_ylabel("Y (paso)")
|
||||
fig.colorbar(im, ax=ax, label=cunit)
|
||||
|
||||
|
||||
draw_heat(axes[0], maxC, "Fotocorriente C (max por celda)", "Isc [mA]")
|
||||
draw_heat(axes[1], maxP, "Piranometro P (max por celda)", "G [W/m$^2$]")
|
||||
draw_heat(axes[2], co, "Co-pico min(C*,P*) -> pos. solar real", "normalizado")
|
||||
|
||||
ci, cj = np.unravel_index(np.nanargmax(maxC), maxC.shape)
|
||||
axes[0].plot(xc[cj], yc[ci], "w*", ms=16, mec="white", mew=1.2, zorder=5)
|
||||
pi_, pj_ = np.unravel_index(np.nanargmax(maxP), maxP.shape)
|
||||
axes[1].plot(xc[pj_], yc[pi_], "w*", ms=16, mec="white", mew=1.2, zorder=5)
|
||||
|
||||
axes[2].plot(xs, ys, "-", color="cyan", lw=0.25, alpha=0.35, zorder=2,
|
||||
label="trayectoria (t)")
|
||||
axes[2].plot(co_peak_x, co_peak_y, "o", ms=16, mfc="none", mec="lime",
|
||||
mew=2.2, zorder=6, label="co-pico (sol real)")
|
||||
axes[2].plot(com_x, com_y, "x", ms=14, color="yellow", mew=2.4, zorder=7,
|
||||
label="centro de masa")
|
||||
axes[2].plot(xc[cj], yc[ci], "+", ms=14, color="red", mew=2.0, zorder=7, label="pico C")
|
||||
axes[2].plot(xc[pj_], yc[pi_], "+", ms=14, color="orange", mew=2.0, zorder=7, label="pico P")
|
||||
axes[2].legend(loc="upper left", fontsize=8, framealpha=0.8)
|
||||
|
||||
fig.suptitle("Heatmap de posicion solar real - MicrotrackingFer 2026-10-15 "
|
||||
"(9584 muestras, 11:35-23:59)", fontsize=13, y=1.00)
|
||||
fig.tight_layout()
|
||||
fig.savefig(OUT_PNG, dpi=150, bbox_inches="tight")
|
||||
print("PNG guardado:", OUT_PNG)
|
||||
Reference in new issue
Block a user