venerdì 23 gennaio 2026

Analisi MNF su spettri di riflettanza di plastica

Devo cerca di lavorare su spettri di riflettanza di plastica e la prima domanda e': quale sono le bande significative?

Sono partito dal dataset delle plastiche (36 in tutto) contenuti in USGS Spectral Library

Per estrarre le feature ho usato MNF Maximum Noise Fraction (al posto di PCA)  

Nel grafico sottostante sono plottate le prime 3 componenti MNF 

La terza componente (quella di solito in cui sono presenti i dati spettrali, la prima componente e' influenzata dalla ) e' stata utilizzata per addestrare un rete random tree per trovare quali siano le bande effettivamente significative




 Per finire un confronto tra gli spettri non elaborati e la selezione random forest 

 


 Le bande piu' significative estratte 

 ind           nm     peso

150          600     0.018671
1289        1739   0.018409
149          599     0.014763
143          593     0.013682
1998        2448   0.012601 

 

import numpy as np
import glob
import os
from scipy.signal import savgol_filter
from scipy.linalg import eigh

folder = "./plastica"
files = sorted(glob.glob(os.path.join(folder, "*.txt")))


arrays = []
for f in files:
    data = np.loadtxt(f, skiprows=1)
    if data.shape[0] > 2100:
        arrays.append(data[100:2100])
       

X = np.array(arrays)
X = np.where((X >= 0) & (X <= 1), X, 0)



print(f"Shape originale: {X.shape}")

# 1. Smoothing e calcolo rumore
X_smooth = savgol_filter(X, window_length=11, polyorder=2, axis=1)
noise_residue = X - X_smooth

# 2. Calcolo matrici di covarianza
noise_cov = np.cov(noise_residue, rowvar=False)
data_cov = np.cov(X, rowvar=False)

# Regolarizzazione (Ridge) alla diagonale della matrice di rumore.
# Questo garantisce che la matrice sia definita positiva.
eps = 1e-6 * np.trace(noise_cov) / noise_cov.shape[0]
noise_cov_reg = noise_cov + np.eye(noise_cov.shape[0]) * eps

# 3. Esecuzione MNF
eigenvalues, eigenvectors = eigh(data_cov, noise_cov_reg)

idx = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]

# 5. Proiezione
X_mnf = np.dot(X, eigenvectors)

print(f"Prime 5 componenti MNF (SNR più alto): {eigenvalues[:5]}")

import matplotlib.pyplot as plt

# L'indice 0 corrisponde alla prima colonna dopo l'ordinamento decrescente
first_mnf_loadings = eigenvectors[:, 0]

wavelengths = np.arange(350, 2500)
wl_tagliate = wavelengths[100:2100]

idx_max = np.argmax(np.abs(first_mnf_loadings))
print(f"La banda più importante è la numero {idx_max}, che corrisponde a {wl_tagliate[idx_max]} nm")

wls = np.arange(350, 2501)[100:2100]

fig, axs = plt.subplots(3, 1, figsize=(12, 15), sharex=True)
colors = ['#1f77b4', '#ff7f0e', '#2ca02c']

for i in range(3):
    # Estraiamo i loadings per la componente i-esima
    loadings = eigenvectors[:, i]
   
    axs[i].plot(wls, loadings, color=colors[i], lw=1.5)
    axs[i].set_title(f"Loadings MNF Componente {i+1} (Autovalore: {eigenvalues[i]:.2e})")
    axs[i].set_ylabel("Peso")
    axs[i].grid(True, alpha=0.3)
   
    # Evidenziamo l'area diagnostica dei carbonati (2300-2350 nm)
    axs[i].axvspan(2300, 2350, color='red', alpha=0.1, label='Zona Carbonati')

axs[2].set_xlabel("Lunghezza d'onda (nm)")
plt.tight_layout()
plt.show()



from sklearn.ensemble import RandomForestRegressor
import pandas as pd


y = X_mnf[:, 2]

rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X, y)

importances = rf.feature_importances_

wls = np.arange(350, 2501)[100:2100]
feature_results = pd.DataFrame({'Wavelength': wls, 'Importance': importances})

# Ordiniamo per importanza decrescente
top_features = feature_results.sort_values(by='Importance', ascending=False).head(10)

print("Le 10 lunghezze d'onda più influenti (Feature Importance):")
print(top_features)

# 5. Visualizzazione
plt.figure(figsize=(10, 5))
plt.plot(wls, importances, color='purple', label='Feature Importance')
plt.fill_between(wls, importances, color='purple', alpha=0.3)
plt.title("Rilevanza delle Bande Spettrali (Random Forest)")
plt.xlabel("Lunghezza d'onda (nm)")
plt.ylabel("Importanza Relativa")
plt.grid(True, alpha=0.3)
plt.show()

plt.figure(figsize=(12, 7))

plt.plot(wls, X.T, color='steelblue', alpha=0.3)

plt.title(f"Spettri di Riflettanza del Dataset ({X.shape[0]} campioni)")
plt.xlabel("Lunghezza d'onda (nm)")
plt.ylabel("Riflettanza (0-1)")
plt.grid(True, linestyle='--', alpha=0.5)

# Per evitare legende infinite, ne mettiamo una generica
plt.plot([], [], color='steelblue', label='Spettri campioni')
plt.legend()

plt.show()

# --- GRAFICO 1: SPETTRI DI RIFLETTANZA ---
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12), sharex=True)

ax1.plot(wls, X.T, color='steelblue', alpha=0.2)

ax1.plot(wls, np.mean(X, axis=0), color='red', lw=2, label='Spettro Medio')

ax1.set_title("Spettri di Riflettanza (Dati Originali Puliti)")
ax1.set_ylabel("Riflettanza")
ax1.grid(True, alpha=0.3)
ax1.legend()

# --- GRAFICO 2: RILEVANZA DELLE BANDE (Feature Importance) ---

ax2.plot(wls, importances, color='darkgreen', lw=1.5)
ax2.fill_between(wls, importances, color='darkgreen', alpha=0.2)

ax2.set_title("Rilevanza delle Bande Spettrali (Random Forest Importance)")
ax2.set_ylabel("Importanza Relativa")
ax2.set_xlabel("Lunghezza d'onda (nm)")
ax2.grid(True, alpha=0.3)


plt.tight_layout()
plt.show()

mercoledì 14 gennaio 2026

Microfoni Kinect1

Ho trovato quasi per caso su Internet che il Kinect 1 ha un array di 4 microfoni che permettono di determinare la direzione del suono (ed essendo tutto integrato non ha problemi di jitter) 

Bus 001 Device 016: ID 045e:02b0 Microsoft Corp. Xbox NUI Motor
Bus 001 Device 018: ID 045e:02bb Microsoft Corp. Kinect Audio
Bus 001 Device 019: ID 045e:02ae Microsoft Corp. Xbox NUI Camera
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub

L'array di 4 microfoni e' indicato da 0 (lato destro) a 3 (lato sinistro) con una distanza tra 0 e 3 di 22.6 cm. I microfoni 0,1,2 sono molto ravvicinati tra di loro, solo il 3 e' distanziato alla sinistra


 

Una delle limitazione di kinect e' che il campionamento massimo e' di 16k il che limita la precisione a 2.14 cm ed 24 bit (anche se sono trasmessi come 32 bit)

arecord -l

 card 1: Audio [Kinect USB Audio], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0


arecord -D hw:1,0 -c 4 -r 16000 -f S32_LE -t raw kinect_array.raw 

ffmpeg -f s32le -ar 16000 -ac 4 -i kinect_array.raw kinect_output.wav 

 

import numpy as np
import subprocess
import math
from scipy.signal import correlate

# --- CONFIGURAZIONE ---
CHANNELS = 4
RATE = 16000
CHUNK_SIZE = 1024 * 4 # Dimensione del blocco da analizzare (circa 0.25 secondi)
v = 343 # Velocità del suono m/s
d = 0.226 # Distanza Mic 0 - Mic 3 (metri)

# Comando per avviare arecord e inviare i dati RAW alla stdout
cmd = [
'arecord', '-D', 'hw:1,0', '-c', str(CHANNELS), '-r', str(RATE),
'-f', 'S32_LE', '-t', 'raw', '-q'
]

# Avvio del processo
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

print("Ascolto in corso... Muoviti davanti al Kinect o schiocca le dita!")
print("Premi Ctrl+C per fermare.\n")

try:
while True:
# Leggi un blocco di dati (4 canali * 4 byte per campione * CHUNK_SIZE)
raw_bytes = proc.stdout.read(CHUNK_SIZE * CHANNELS * 4)
if not raw_bytes:
break

# Converti byte in array numpy
data = np.frombuffer(raw_bytes, dtype=np.int32).reshape(-1, CHANNELS)

# Prendi Mic 0 e Mic 3
mic_0 = data[:, 0].astype(np.float32)
mic_3 = data[:, 3].astype(np.float32)

# Calcola correlazione
corr = correlate(mic_0, mic_3, mode='full')
lag = np.argmax(corr) - (len(mic_0) - 1)
# Calcolo tempo e angolo
dt = lag / RATE
# Limita l'argomento di arcsin tra -1 e 1 per evitare errori
sin_argument = (v * dt) / d
if abs(sin_argument) <= 1.0:
angle_rad = math.asin(sin_argument)
angle_deg = math.degrees(angle_rad)
# Visualizzazione a barre dinamica
bar_position = int(angle_deg / 10) + 9
display = ["-"] * 19
display[bar_position] = "O"
print(f"[{''.join(display)}] Angolo: {angle_deg:6.1f}°", end="\r")

except KeyboardInterrupt:
print("\nFermato dall'utente.")
finally:
proc.terminate()

 

mercoledì 31 dicembre 2025

Chiavetta ALIA

Sono maledettamente distratto e stavo cercando di vedere se riesco a replicare la chiavetta dei cassonetti di Firenze senza dover per forza andare alla ditta che gestisce la raccolta

Sostanzialmente si tratta di una chiavetta Rfid che si puo' leggere tramite IPhone ed apposita applicazione 

 

Di seguito il contenuto della chiavetta...ed e' decisamente piu' complicato di come mi aspettavo

Nella chiavetta c'e' un coppia di valori Field Value con con un UID che coincide con il codice esadecimale  dell'utente stampato sulla chiavetta

Il problema sono i memory block...probabilmente nei memory block i dati sono calcolati incrociando il mio UID con qualche master key del gestore creando un dato crittografato...soltanto se l'UID ed il memory block calcolato matchano si apre il cassonetto

Non conoscendo la master key e la crittografia si potrebbe sempre fare una copia 1:1 (tanto non voglio creare nuove chiavi, solo clonare la mia) ma non sembra che esistano in vendita degli rfid scrivibili di questa catergoria 

 

Field,Value
UID,"E0:04:01:50:XX:XX:XX:XX"
Technology,"ISO15693"
Type,"ISO15693 Vicinity Card"
Scan Date,"26 dic 2025, 11:36:41"
Timestamp,"1766745401.7287521"

Additional Data,Value
"AFI (Application Family Identifier)","0x07 (7)"
"Block Size","4 bytes"
"Chip Capabilities","Basic security"
"Chip Series","NXP ICODE family"
"DSFID (Data Storage Format Identifier)","0x00 (0)"
"EAS Alarm","Disabled"
"Features","ISO15693 standard"
"Generation","Generation 1 (Standard)"
"IC Manufacturer Code","0x04"
"IC Reference","0x01"
"Identifier Length","8 bytes"
"Identifier Structure","8-byte ISO15693 standard"
"Manufacturer","NXP Semiconductors (0x04)"
"Manufacturer ID","0xE0"
"Memory","1024 bits (28 blocks × 4 bytes)"
"Memory Reading Result","28/28 blocks read"
"Memory Size (from System Info)","112 bytes (28 blocks × 4 bytes)"
"Memory Success Rate","100.0%"
"Model Series","ICODE SLI"
"Operating Frequency","13.56 MHz"
"Product Code","0x04"
"Product Family","Standard ICODE Family"
"Serial (Decimal)","95495875022849"
"Serial Number","01:50:B5:5D:DA:56"
"Tag Protocol","ISO15693 (ISO/IEC 15693)"
"Wafer/Lot","50B5"

Additional Info,Value
"Blocks Read","28"
"Reading Method","Stable Sequential"
"Success Rate","100.0%"
"Total Blocks","28"

Memory Blocks,
Block Number,Hex Data,ASCII Data
"0","FE D5 14 B4","...."
"1","02 73 9D 5A",".s.Z"
"2","46 CB 3C 1E","F.<."
"3","A5 7E AE 4B",".~.K"
"4","B1 7F 82 FB","...."
"5","16 24 51 D1",".$Q."
"6","88 8E BB 6E","...n"
"7","A1 5D 97 41",".].A"
"8","75 06 6D FB","u.m."
"9","C0 52 49 17",".RI."
"10","10 E1 38 0A","..8."
"11","55 D0 2D 05","U.-."

.......................
"20","DF 33 C5 99",".3.."
"21","29 6D 3E D1",")m>."
"22","80 2C E7 AD",".,.."
"23","27 E0 EF 44","'..D"
"24","2B 11 EF 91","+..."
"25","2C 55 7A 90",",Uz."
"26","28 A5 9C CC","(..."
"27","A0 78 6B 94",".xk." 

martedì 23 dicembre 2025

Algoritmo Reed Solomon

 Sto progettando una trasmissione radio di immagini ed uno dei vincoli e' che non e' garantita la perfetta qualita' della trasmissione con previsione di errori nella fase aerea e cercado una soluzione mi sono imbattuto nell'algoritmo Reed Solomon che peraltro ha una storia affascinante che riguarda le sonde Voyager 


In pratica quando Voyager hanno  superato Saturno il segnale era diventato cosi' debole che anche una ridondanza del 100% non permetteva di ricevere in modo affidabile. Quindi da terra i computer di bordo sono stati riprogrammati per utilizzare una codifica a correzione di errore Reed Solomon...questo algoritmo e' anche alla base della correzione degli errori nella lettura delle tracce dei CD audio rigati

 A differenza di CRC algoritmo che individua se il dato e' corrotto o meno ma non dice come riparare il flusso di dati, Reed Solomon e' un algoritmo FEC  (Forward Error Correction) che permette di correggere i bit errati dove presenti 


Reed Solomon permette di correggere uno o piu' errore in un pacchetto dati usando dati aggiuntivi di controllo (tipicamente in un pacchetto di 255 bytes 223 bytes sono del messaggio ed i rimanenti coefficienti per l'algoritmo  si possono correggere fino a 11 bytes trasmessi erroneamente.

 Questo un video sulla spiegazione dal punto di vista matematico del funzionamento

 https://www.youtube.com/watch?v=fBRMaEAFLE0

Il programma sottostante, usando una libreria Python, prende una immagine jpeg, la codifica con Reed Solomon, introduce degli errori e poi la ricostruisce. Visto che si tratta di un jpg e quindi compresso l'immagine con gli errori casuali non risultera' leggibile da un comune programma di gestione immagini

import reedsolo as rs
import random

# 1. Setup
n, k = 255, 223
codec = rs.RSCodec(n - k)

with open("image.jpg", "rb") as f:
    original_data = f.read()

# 2. Encode
encoded_data = bytearray()
for i in range(0, len(original_data), k):
    chunk = original_data[i : i + k]
    encoded_data.extend(codec.encode(chunk))

# 3. Corrupt (The "Stress Test")
# We will randomly corrupt 5% of the file
corrupted_data = bytearray(encoded_data)
num_errors = int(len(corrupted_data) * 0.05)
indices = random.sample(range(len(corrupted_data)), num_errors)

for idx in indices:
    corrupted_data[idx] = random.randint(0, 255)

# --- NEW STEP: Save the Corrupted Version ---
# Note: This file will likely be "broken" and might not open in
# standard viewers because the RS parity bytes are mixed in.
with open("corrupted_with_parity.bin", "wb") as f:
    f.write(corrupted_data)
# ---------------------------------------------

# 4. Decode & Repair
decoded_data = bytearray()
for i in range(0, len(corrupted_data), n):
    chunk = corrupted_data[i : i + n]
    try:
        # The magic happens here: errors are removed
        corrected_chunk = codec.decode(chunk)[0]
        decoded_data.extend(corrected_chunk)
    except rs.ReedSolomonError:
        # If a block has > 16 errors, we just take the corrupted data
        # so the file stays the same size (though it will be glitchy)
        decoded_data.extend(chunk[:k])

# 5. Save the Clean Result
with open("recovered_final.jpg", "wb") as f:
    f.write(decoded_data)

print(f"Done! Processed {len(indices)} errors.")

 

venerdì 12 dicembre 2025

Frattalita' in misure di spessore (2)

Aggiornamento bibliografico (che mi ero completamente saltato all'Universita')

Sediment Accumulation Rates and the Completeness of Stratigraphic Sections
 Peter M. Sadler
The Journal of Geology, Vol. 89, No. 5 (Sep., 1981), pp. 569-584

Estimation of completeness of stratigraphical sections using
empirical data and theoretical models 
 
Peter M.Sadler & David J. Strauss 
Journal of the Geological Society, London, Vol. 147, 1990,pp. 471-485
 
The nature of stratigraphical record (3 ed) 
D. Ager (1993) 
Wiley and Sons 
capitolo 3 More gaps than records pag.43 
 
Fractals models in Earth Sciences
Korvin Gabor (1992)
Elsevier Science Ltd
cap.2 Fractals in Flatland : a romance in <2 dimensions 
 ----------------------------------------------------------------------------- 

 

Seconda puntata dell'esperimento iniziato qui

 Su suggerimento di uno degli autori ho provato ad utilizzare i dati di questo articolo in cui sono presenti dettagliate stratigrafie del Scaglia Toscana

The Scaglia Toscana Formation of the Monti del Chianti:
new lithostratigraphic and biostratigraphic data
Enrico Pandeli (*, **), Milvio Fazzuoli (*), Fabio Sandrelli (***), Roberto Mazzei (***),
Simonetta Monechi (*), Marisa Nocchi (****), Ivan Martini (***) & Gigliola Valleri (*) Ital. J. Geosci., Vol. 137, No. 1 (2018), pp. 38-61, 12 figs., 1 tab., 1 plate, 2 extrapl. (doi: 10.3301/IJG.2017.16)
© Società Geologica Italiana, Roma 2018

 


 
Sono state considerati considerati gli affioramenti Sugame (48 dati Middle Eocene-Lower Oligocene) , Castello di Brolio (251 dati Upper Cretaceous-Lower Oligocene) , Cintoia West (150 dati Upper Cretaceous-Middle Upper Eocene ) , Montegrossi (208 dati) e Lucolena North (Upper Cretaceous--Lower Oligocene 63 dati). Come si vede non tutte le serie ricoprono esattamente lo stesso periodo temporale e le stess formazioni. Si evidenzia che alcune serie non presentano una serie deposizionale continua







In generale tutti i grafici mostrano una curva spezzata con valori di D>1 sulle scale di maggiori dimensioni e valori nettamente inferiori a 1 per le scale di dettaglio. Alle scale maggiori emerge quindi una tendenza alla frattalita' ed autosomiglianza che si perde alle piccola scala

Il motivo di questo andamento e' perche' i cicli tettonici e climatici influenzano solo le scali maggiori (ma potrebbe essere anche un problema di sotto campionamento degli strati meno potenti)

Questo e' il codice gentilmente fornito da Gemini 

 

import numpy as np
import matplotlib.pyplot as plt
import os

def box_counting_dimension_1d(data, max_box_size=None, plot=True):
    """
    Calcola la dimensione frattale di una serie di dati 1D utilizzando il metodo del box-counting.

    Args:
        data (np.array): La serie di dati 1D (spessore di strato) come array NumPy.
        max_box_size (int, optional): La dimensione massima delle scatole da testare.
        plot (bool): Se True, visualizza il log-log plot.

    Returns:
        float: La dimensione frattale calcolata (pendenza del log-log plot).
    """
    # 1. Preparazione dei dati (la logica rimane la stessa)
    data = np.asarray(data)
   
    # Rimuovi eventuali valori non finiti (NaN, Inf) che potrebbero derivare dal caricamento
    data = data[np.isfinite(data)]

    if len(data) < 2:
        print("Errore: Il set di dati è troppo piccolo o vuoto dopo la pulizia.")
        return np.nan

    min_val = np.min(data)
    max_val = np.max(data)
   
    if max_val == min_val:
        return 1.0

    L = len(data)
   
    if max_box_size is None:
        max_box_size = L // 4
   
    # Raccogli le dimensioni delle scatole (epsilon) da testare
    r_values = 2**np.arange(1, int(np.log2(max_box_size)) + 1)
   
    # Scalatura dell'asse Y per mappare i punti in uno spazio 2D approssimativamente quadrato
    y_scaled = (data - min_val) / (max_val - min_val) * (L - 1)
    points = np.column_stack((np.arange(L), y_scaled))

    log_r = []
    log_N = []
   
    # 3. Box-Counting
    for r in r_values:
        # Calcola le coordinate delle scatole
        box_coords = np.floor(points / r).astype(int)
       
        # Conta le scatole uniche
        N_r = len(np.unique(box_coords, axis=0))
       
        if N_r > 0:
            log_r.append(np.log(1/r))
            log_N.append(np.log(N_r))
           
    log_r = np.array(log_r)
    log_N = np.array(log_N)
   
    if len(log_r) < 2:
        print("Errore: Non abbastanza punti per calcolare la pendenza. Prova con una serie di dati più lunga.")
        return np.nan
       
# Nuova sezione: Selezione dei primi 4 punti
    num_punti_fit = 3

    if len(log_r) < num_punti_fit:
        print(f"Attenzione: Trovati solo {len(log_r)} punti. Eseguo la regressione su tutti i punti disponibili.")
        log_r_fit = log_r
        log_N_fit = log_N
    else:
        # Seleziona i primi 'num_punti_fit' punti (corrispondenti alle scale più piccole/fini)
        #log_r_fit = log_r[-num_punti_fit:]
        #log_N_fit = log_N[-num_punti_fit:]
        log_r_fit = log_r[:num_punti_fit]
        log_N_fit = log_N[:num_punti_fit]
   
    # Esegue la regressione lineare solo sui punti selezionati
    coeffs, residuals, rank, singular_values, rcond = np.polyfit(log_r_fit, log_N_fit, 1, full=True)
    fractal_dimension = coeffs[0]
    # ----------------------------------------------------
   
    # 5. Plot (Opzionale)
    if plot:
        plt.figure(figsize=(10, 6))
        # Plot di TUTTI i punti
        plt.plot(log_r, log_N, 'bo', label='Punti Dati Totali')
       
        # Plot della linea di regressione utilizzando solo l'intervallo di punti selezionato
        p = np.poly1d(coeffs)
       
        # Plot della linea SOLO sul range dei punti usati per il fit (opzionale, per chiarezza)
        plt.plot(log_r_fit, p(log_r_fit), 'r-',
                 label=f'Fit (Primi {len(log_r_fit)} punti): D = {fractal_dimension:.4f}')

        # Evidenzia i punti usati per il fit
        plt.plot(log_r_fit, log_N_fit, 'ro', markerfacecolor='none', markersize=10,
                 label=f'Punti usati per la regressione')

        plt.title('Sugame')
        plt.xlabel(r'$\log(1/\epsilon)$')
        plt.ylabel(r'$\log(N(\epsilon))$')
        plt.legend()
        plt.grid(True, which="both", linestyle="--")
        plt.show()

    return fractal_dimension

# --- Esempio di Utilizzo AGGIORNATO ---

NOME_FILE_CSV = "sugame.csv"

print("--- Calcolo della Dimensione Frattale ---")

if not os.path.exists(NOME_FILE_CSV):
    print(f"ERRORE: File '{NOME_FILE_CSV}' non trovato.")
    print("Assicurati che il file esista nella stessa directory dello script.")
else:
    try:
        # Carica i dati dal file CSV
        # usecols=0 specifica di usare solo la prima colonna
        # dtype=int assicura che i dati vengano letti come interi
        spessore_strato_dati = np.genfromtxt(
            NOME_FILE_CSV,
            delimiter=',',
            dtype=int,
            skip_header=0,
            filling_values=np.nan # Sostituisce i valori mancanti con NaN (che puliremo dopo)
        )
       
        if spessore_strato_dati.ndim > 1:
            # Se per qualche motivo numpy legge più colonne, forziamo solo la prima
            spessore_strato_dati = spessore_strato_dati[:, 0]
       
        print(f"Dati caricati con successo da '{NOME_FILE_CSV}'.")
        print(f"Numero di punti dati: {len(spessore_strato_dati)}")

        # Calcola e stampa il risultato
        D = box_counting_dimension_1d(spessore_strato_dati, plot=True)

        print(f"\nRisultato:")
        print(f"Dimensione Frattale (D) calcolata: {D:.4f}")

    except Exception as e:
        print(f"Si è verificato un errore durante il caricamento o l'analisi dei dati: {e}")

 Ben sapendo che non e' propriamente corretto ho provato a vedere cosa succedeva sommando tutti i dati di tutte le serie

 



 

 

Analisi MNF su spettri di riflettanza di plastica

Devo cerca di lavorare su spettri di riflettanza di plastica e la prima domanda e': quale sono le bande significative? Sono partito dal ...