function GXTXT_analisi_impulsi_v1()

    clc;
    close all;
    more off;

    % ============================================================
    % GX-TXT-v3
    % ANALISI GLOBALE DELLA RISPOSTA AL NUMERO DI IMPULSI
    %
    % VERSIONE 1
    %
    % Legge il risultati_batch.csv prodotto da:
    %
    % GXTXT_batch_impulsi_v8.m
    %
    % e genera:
    %
    % 1) V_HOLD,max = f(numero impulsi)
    % 2) T_LED      = f(numero impulsi)
    %
    % Le condizioni LED OFF vengono rappresentate con T_LED = 0.
    %
    % ============================================================

    % ============================================================
    % CONFIGURAZIONE
    %
    % MODIFICARE SOLO batchDir
    % ============================================================

    batchDir = ...
        fullfile( ...
            'calibrazione script', ...
            'batch_impulsi_YYYYMMDD_HHMMSS');

    masterFile = ...
        fullfile( ...
            batchDir, ...
            'risultati_batch.csv');

    outputDir = ...
        fullfile( ...
            batchDir, ...
            'analisi_impulsi');

    pngDPI = 200;

    % ============================================================
    % CREAZIONE OUTPUT
    % ============================================================

    if (exist(masterFile,'file') != 2)
        error('Master CSV non trovato: %s', masterFile);
    endif

    if (exist(outputDir,'dir') != 7)
        mkdir(outputDir);
    endif

    % ============================================================
    % LOG
    % ============================================================

    logFile = ...
        fullfile( ...
            outputDir, ...
            'analisi_impulsi.log');

    diary(logFile);
    diary on;

    fprintf('\n');
    fprintf('============================================================\n');
    fprintf('GX-TXT-v3 - ANALISI NUMERO DI IMPULSI\n');
    fprintf('============================================================\n\n');

    fprintf('Batch  : %s\n', batchDir);
    fprintf('Master : %s\n', masterFile);
    fprintf('Output : %s\n\n', outputDir);

    % ============================================================
    % LETTURA MASTER
    % ============================================================

    fprintf('------------------------------------------------------------\n');
    fprintf('1. LETTURA DEL MASTER CSV\n');
    fprintf('------------------------------------------------------------\n');

    M = leggi_master_impulsi(masterFile);

    N = length(M.numeroImpulsi);

    fprintf('Condizioni lette: %d\n\n', N);

    if (N == 0)

        diary off;
        error('Nessuna condizione disponibile nel master.');

    endif

    % ============================================================
    % NORMALIZZAZIONE
    % ============================================================

    M.VholdMax(M.VholdMax < 0) = 0;

    M.Tled = zeros(N,1);

    for k = 1:N

        if ( ...
            M.ledValid(k) > 0.5 && ...
            isfinite(M.tempoLed(k)) ...
        )

            M.Tled(k) = ...
                max(0,M.tempoLed(k));

        else

            % LED non acceso:
            % risultato sperimentale valido
            M.Tled(k) = 0;

        endif

    endfor

    % ============================================================
    % ORDINAMENTO PER NUMERO DI IMPULSI
    % ============================================================

    [M.numeroImpulsi, idx] = ...
        sort(M.numeroImpulsi);

    M.p_gain = M.p_gain(idx);
    M.p_sens = M.p_sens(idx);

    M.vgen = M.vgen(idx);
    M.vrsense = M.vrsense(idx);
    M.isense = M.isense(idx);

    M.durataBurst_ms = M.durataBurst_ms(idx);

    M.VholdMax = M.VholdMax(idx);

    M.ledValid = M.ledValid(idx);
    M.tempoLed = M.tempoLed(idx);
    M.Tled = M.Tled(idx);

    % ============================================================
    % TABELLA A VIDEO
    % ============================================================

    fprintf('------------------------------------------------------------\n');
    fprintf('2. DATI DELLA SERIE\n');
    fprintf('------------------------------------------------------------\n\n');

    fprintf( ...
        '%8s %12s %12s %12s %12s %12s\n', ...
        'Nimp', ...
        'Tburst[ms]', ...
        'Vrsense[V]', ...
        'Isense[uA]', ...
        'VholdMax[V]', ...
        'Tled[s]');

    fprintf( ...
        '-------------------------------------------------------------------------------\n');

    for k = 1:N

        fprintf( ...
            '%8d %12.4f %12.4f %12.3f %12.4f %12.4f\n', ...
            M.numeroImpulsi(k), ...
            M.durataBurst_ms(k), ...
            M.vrsense(k), ...
            M.isense(k), ...
            M.VholdMax(k), ...
            M.Tled(k));

    endfor

    % ============================================================
    % CONTROLLO DELLA STABILITA' DI I_SENSE
    % ============================================================

    validI = isfinite(M.isense);

    fprintf('\n');
    fprintf('------------------------------------------------------------\n');
    fprintf('3. CONTROLLO I_SENSE\n');
    fprintf('------------------------------------------------------------\n\n');

    if (any(validI))

        fprintf('I_SENSE media   : %.3f uA\n', ...
            mean(M.isense(validI)));

        fprintf('I_SENSE minima  : %.3f uA\n', ...
            min(M.isense(validI)));

        fprintf('I_SENSE massima : %.3f uA\n', ...
            max(M.isense(validI)));

        if (sum(validI) >= 2)

            fprintf('Deviazione std  : %.3f uA\n', ...
                std(M.isense(validI)));

        else

            fprintf('Deviazione std  : non disponibile\n');

        endif

    else

        fprintf('Nessun valore I_SENSE valido.\n');

    endif

    % ============================================================
    % PRIMA ACCENSIONE RICONOSCIUTA
    % ============================================================

    idxOn = find(M.Tled > 0, 1, 'first');

    fprintf('\n');
    fprintf('------------------------------------------------------------\n');
    fprintf('4. PRIMA ACCENSIONE LED RICONOSCIUTA\n');
    fprintf('------------------------------------------------------------\n\n');

    if (!isempty(idxOn))

        fprintf('Numero impulsi  : %d\n', ...
            M.numeroImpulsi(idxOn));

        fprintf('Durata burst    : %.4f ms\n', ...
            M.durataBurst_ms(idxOn));

        fprintf('V_HOLD,max      : %.4f V\n', ...
            M.VholdMax(idxOn));

        fprintf('T_LED           : %.4f s\n', ...
            M.Tled(idxOn));

    else

        fprintf('Nessuna accensione LED nella serie.\n');

    endif

    % ============================================================
    % CSV DI OUTPUT
    % ============================================================

    outCSV = ...
        fullfile( ...
            outputDir, ...
            'dati_impulsi.csv');

    fid = fopen(outCSV,'w');

    fprintf(fid, ...
        ['numero_impulsi,' ...
         'durata_burst_ms,' ...
         'P_GAIN_ohm,' ...
         'P_SENS_ohm,' ...
         'VGEN_Vpp,' ...
         'V_RSENSE_Vpp,' ...
         'I_SENSE_uA,' ...
         'V_HOLD_max_V,' ...
         'LED_ON,' ...
         'T_LED_s\n']);

    for k = 1:N

        fprintf(fid, ...
            '%d,%.9f,%.6f,%.6f,%.6f,%.6f,%.6f,%.6f,%d,%.6f\n', ...
            M.numeroImpulsi(k), ...
            M.durataBurst_ms(k), ...
            M.p_gain(k), ...
            M.p_sens(k), ...
            M.vgen(k), ...
            M.vrsense(k), ...
            M.isense(k), ...
            M.VholdMax(k), ...
            M.ledValid(k) > 0.5, ...
            M.Tled(k));

    endfor

    fclose(fid);

    % ============================================================
    % FIGURA 1
    %
    % V_HOLD,max = f(numero impulsi)
    % ============================================================

    fprintf('\n');
    fprintf('Genero 01_vholdmax_vs_impulsi.png...\n');

    validVH = ...
        isfinite(M.numeroImpulsi) & ...
        isfinite(M.VholdMax);

    xVH = M.numeroImpulsi(validVH);
    yVH = M.VholdMax(validVH);

    f = figure('visible','off');

    plot( ...
        xVH, ...
        yVH, ...
        'o', ...
        'markersize', ...
        7);

    hold on;

    if (length(xVH) >= 3)

        [xUnique, ia] = unique(xVH);
        yUnique = yVH(ia);

        if (length(xUnique) >= 3)

            xx = linspace( ...
                min(xUnique), ...
                max(xUnique), ...
                500);

            yy = pchip( ...
                xUnique, ...
                yUnique, ...
                xx);

            yy(yy < 0) = 0;

            plot( ...
                xx, ...
                yy, ...
                '-', ...
                'linewidth', ...
                1.5);

            legend( ...
                'Punti sperimentali', ...
                'Interpolazione PCHIP', ...
                'location', ...
                'southeast');

        endif

    endif

    grid on;

    xlabel('Numero di impulsi');
    ylabel('V_{HOLD,max} [V]');

    title( ...
        ['GX-TXT-v3 - Massimo di HOLD ' ...
         'in funzione del numero di impulsi']);

    xmin = min([0; xVH]);
    xmax = max(xVH);

    if (xmax <= xmin)
        xmax = xmin + 1;
    endif

    xlim([xmin xmax + 0.07*(xmax-xmin)]);

    ymax = max(yVH);

    if ( ...
        isempty(ymax) || ...
        !isfinite(ymax) || ...
        ymax <= 0 ...
    )
        ymax = 1;
    endif

    ylim([0 ymax*1.10]);

    print( ...
        f, ...
        fullfile( ...
            outputDir, ...
            '01_vholdmax_vs_impulsi.png'), ...
        '-dpng', ...
        sprintf('-r%d',pngDPI));

    close(f);

    % ============================================================
    % FIGURA 2
    %
    % T_LED = f(numero impulsi)
    % ============================================================

    fprintf('Genero 02_tled_vs_impulsi.png...\n');

    validTL = ...
        isfinite(M.numeroImpulsi) & ...
        isfinite(M.Tled);

    xTL = M.numeroImpulsi(validTL);
    yTL = M.Tled(validTL);

    f = figure('visible','off');

    plot( ...
        xTL, ...
        yTL, ...
        'o', ...
        'markersize', ...
        7);

    hold on;

    if (length(xTL) >= 3)

        [xUnique, ia] = unique(xTL);
        yUnique = yTL(ia);

        if (length(xUnique) >= 3)

            xx = linspace( ...
                min(xUnique), ...
                max(xUnique), ...
                500);

            yy = pchip( ...
                xUnique, ...
                yUnique, ...
                xx);

            yy(yy < 0) = 0;

            plot( ...
                xx, ...
                yy, ...
                '-', ...
                'linewidth', ...
                1.5);

            legend( ...
                'Punti sperimentali', ...
                'Interpolazione PCHIP', ...
                'location', ...
                'southeast');

        endif

    endif

    grid on;

    xlabel('Numero di impulsi');
    ylabel('T_{LED} [s]');

    title( ...
        ['GX-TXT-v3 - Tempo di accensione del LED ' ...
         'in funzione del numero di impulsi']);

    xmin = min([0; xTL]);
    xmax = max(xTL);

    if (xmax <= xmin)
        xmax = xmin + 1;
    endif

    xlim([xmin xmax + 0.07*(xmax-xmin)]);

    ymax = max(yTL);

    if ( ...
        isempty(ymax) || ...
        !isfinite(ymax) || ...
        ymax <= 0 ...
    )
        ymax = 1;
    endif

    ylim([0 ymax*1.10]);

    print( ...
        f, ...
        fullfile( ...
            outputDir, ...
            '02_tled_vs_impulsi.png'), ...
        '-dpng', ...
        sprintf('-r%d',pngDPI));

    close(f);

    % ============================================================
    % RIEPILOGO TXT
    % ============================================================

    summaryFile = ...
        fullfile( ...
            outputDir, ...
            'analisi_impulsi.txt');

    fid = fopen(summaryFile,'w');

    fprintf(fid,'GX-TXT-v3 - ANALISI NUMERO DI IMPULSI\n');
    fprintf(fid,'============================================\n\n');

    fprintf(fid,'Batch:\n%s\n\n', batchDir);
    fprintf(fid,'Condizioni: %d\n\n', N);

    if (any(validI))

        fprintf(fid,'I_SENSE media   : %.6f uA\n', ...
            mean(M.isense(validI)));

        fprintf(fid,'I_SENSE minima  : %.6f uA\n', ...
            min(M.isense(validI)));

        fprintf(fid,'I_SENSE massima : %.6f uA\n', ...
            max(M.isense(validI)));

        if (sum(validI) >= 2)

            fprintf(fid,'I_SENSE std     : %.6f uA\n', ...
                std(M.isense(validI)));

        endif

    endif

    fprintf(fid,'\n');

    fprintf(fid, ...
        '%8s %12s %12s %12s %12s\n', ...
        'Nimp', ...
        'Tburst[ms]', ...
        'Isense[uA]', ...
        'VholdMax[V]', ...
        'Tled[s]');

    fprintf(fid, ...
        '-----------------------------------------------------------------\n');

    for k = 1:N

        fprintf(fid, ...
            '%8d %12.4f %12.3f %12.4f %12.4f\n', ...
            M.numeroImpulsi(k), ...
            M.durataBurst_ms(k), ...
            M.isense(k), ...
            M.VholdMax(k), ...
            M.Tled(k));

    endfor

    if (!isempty(idxOn))

        fprintf(fid,'\nPrima accensione LED riconosciuta:\n');
        fprintf(fid,'Numero impulsi : %d\n', ...
            M.numeroImpulsi(idxOn));
        fprintf(fid,'V_HOLD,max     : %.6f V\n', ...
            M.VholdMax(idxOn));
        fprintf(fid,'T_LED          : %.6f s\n', ...
            M.Tled(idxOn));

    endif

    fclose(fid);

    % ============================================================
    % FINE
    % ============================================================

    fprintf('\n');
    fprintf('============================================================\n');
    fprintf('ANALISI COMPLETATA\n');
    fprintf('============================================================\n\n');

    fprintf('File creati:\n\n');
    fprintf('analisi_impulsi.log\n');
    fprintf('analisi_impulsi.txt\n');
    fprintf('dati_impulsi.csv\n');
    fprintf('01_vholdmax_vs_impulsi.png\n');
    fprintf('02_tled_vs_impulsi.png\n');

    fprintf('\n');

    diary off;

endfunction


% ==============================================================
% LETTURA risultati_batch.csv
% ==============================================================

function M = leggi_master_impulsi(filename)

    fid = fopen(filename,'r');

    if (fid < 0)
        error('Impossibile aprire %s',filename);
    endif

    headerLine = fgetl(fid);

    if (!ischar(headerLine))

        fclose(fid);
        error('CSV master vuoto.');

    endif

    headers = strsplit(headerLine,',');

    for k = 1:length(headers)

        headers{k} = ...
            pulisci_stringa_csv(headers{k});

    endfor

    iGain = trova_colonna(headers,'p_gain_ohm');
    iSens = trova_colonna(headers,'p_sens_ohm');

    iVgen = trova_colonna(headers,'vgen_vpp');
    iVrs = trova_colonna(headers,'v_rsense_vpp');
    iIs = trova_colonna(headers,'isense_uA');

    iNimp = trova_colonna(headers,'numero_impulsi');
    iTburst = trova_colonna(headers,'durata_burst_ms');

    iVhold = trova_colonna(headers,'VholdMax_V');

    iLedValid = ...
        trova_colonna(headers,'ledTransitionValid');

    iTled = ...
        trova_colonna(headers,'tempoLedAcceso_s');

    M.p_gain = [];
    M.p_sens = [];

    M.vgen = [];
    M.vrsense = [];
    M.isense = [];

    M.numeroImpulsi = [];
    M.durataBurst_ms = [];

    M.VholdMax = [];

    M.ledValid = [];
    M.tempoLed = [];

    n = 0;

    while (true)

        line = fgetl(fid);

        if (!ischar(line))
            break;
        endif

        line = strtrim(line);

        if (isempty(line))
            continue;
        endif

        fields = strsplit(line,',');

        for k = 1:length(fields)

            fields{k} = ...
                pulisci_stringa_csv(fields{k});

        endfor

        if (length(fields) < length(headers))
            continue;
        endif

        n = n+1;

        M.p_gain(n,1) = ...
            str2double(fields{iGain});

        M.p_sens(n,1) = ...
            str2double(fields{iSens});

        M.vgen(n,1) = ...
            str2double(fields{iVgen});

        M.vrsense(n,1) = ...
            str2double(fields{iVrs});

        M.isense(n,1) = ...
            str2double(fields{iIs});

        M.numeroImpulsi(n,1) = ...
            str2double(fields{iNimp});

        M.durataBurst_ms(n,1) = ...
            str2double(fields{iTburst});

        M.VholdMax(n,1) = ...
            str2double(fields{iVhold});

        M.ledValid(n,1) = ...
            str2double(fields{iLedValid});

        M.tempoLed(n,1) = ...
            str2double(fields{iTled});

    endwhile

    fclose(fid);

endfunction


% ==============================================================
% TROVA COLONNA
% ==============================================================

function idx = trova_colonna(headers,name)

    idx = find(strcmp(headers,name),1);

    if (isempty(idx))

        error( ...
            'Colonna "%s" non trovata nel CSV.', ...
            name);

    endif

endfunction


% ==============================================================
% PULIZIA STRINGA CSV
% ==============================================================

function s = pulisci_stringa_csv(s)

    s = strtrim(s);

    if (length(s) >= 2)

        if (s(1) == '"' && s(end) == '"')
            s = s(2:end-1);
        endif

    endif

endfunction
