“Anàlisi multiescala de l’oferta de transport públic (TMB i FGC) mitjançant dades GTFS i demanda horària”

Descripció tècnica del model complet de transport públic de Barcelona, redactada:

Model integral d’anàlisi i optimització del transport públic de Barcelona (TMB i FGC)

Aquest model en MATLAB permet fusionar les dades del sistema GTFS amb la demanda horària real estimada per a cada línia de transport públic. Està dissenyat per a avaluar i optimitzar la capacitat operativa de les línies gestionades per TMB i FGC segons diferents franges horàries.

Components principals del model:

1. Paràmetres bàsics i freqüències horàries:

Defineix la capacitat dels vehicles (ex. 150 passatgers) i la freqüència mitjana per hora segons el dia i la franja (pico, vall, etc.).

2. Importació de dades GTFS:

Llegeix els fitxers routes.txt i trips.txt per identificar les línies actives i associar-les al seu nom llarg.

3. Importació de demanda horària:

Carrega un fitxer Excel amb la demanda estimada per línia i franja horària (demanda_horaria.xlsx).

4. Classificació per operador:

Assigna automàticament cada línia a TMB o FGC segons el seu nom.

5. Modelatge de recursos disponibles:

Defineix el nombre total de vehicles i conductors disponibles per operador, i distribueix proporcionalment la flota per línia.

6. Càlcul d’oferta actual, òptima per arrodoniment, i òptima per programació lineal:

Es compara la demanda real amb tres tipus d’oferta:

Oferta actual (basada en la freqüència fixa).

Oferta recomanada per arrodoniment (demanda / capacitat).

Oferta òptima resolta amb optimització (linprog), tenint en compte les limitacions reals de flota i màxims per línia.

7. Visualització automàtica:

Per a cada franja, es genera una gràfica comparativa de demanda vs oferta (actual, arrodonida i òptima) i la diferència entre elles.

8. Exportació automàtica:

Per cada franja horària, el model exporta:

Una gràfica PNG amb les comparacions.

Un fitxer Excel txt o csv amb totes les dades, diferències i ofertes calculades.

Aplicacions pràctiques:

Planificació operativa i assignació de recursos.

Identificació de desequilibris entre demanda i oferta.

Simulació d’escenaris de reforç o reducció de servei.

Suport a la presa de decisions per millorar l’eficiència i sostenibilitat del sistema.

clc; clear;


%% PARÁMETROS BÁSICOS


capacidad_vehiculo = 150; % pasajeros por vehículo


frecuencia.Lunes_Pico     = 6;

frecuencia.Lunes_Valle    = 3;

frecuencia.Sabado_Pico    = 4;

frecuencia.Sabado_Valle   = 2;

frecuencia.Domingo_Total  = 2;


franjas = fieldnames(frecuencia);


%% VALIDACIÓN DE ARCHIVOS


if ~exist('routes.txt', 'file') || ~exist('trips.txt', 'file') || ~exist('demanda_horaria.xlsx', 'file')

    error('Faltan uno o más archivos requeridos.');

end


%% CARGA DE DATOS GTFS


routes = readtable('routes.txt');

trips = readtable('trips.txt');


lineas_unicas = unique(trips.route_id);

n = length(lineas_unicas);

nombre_linea = strings(n,1);

nombre_linea_norm = strings(n,1);


for i = 1:n

    linea_id = lineas_unicas(i);

    nombre = routes.route_long_name(routes.route_id == linea_id);

    if isempty(nombre)

        nombre_linea(i) = "Línea " + string(linea_id);

    else

        nombre_linea(i) = nombre(1);

    end

    nombre_linea_norm(i) = lower(strtrim(nombre_linea(i)));

end


%% CARGA DE DEMANDA HORARIA


demanda_horaria = readtable('demanda_horaria.xlsx');

lineas_excel = lower(strtrim(string(demanda_horaria.Linea)));


%% RECURSOS POR OPERADOR


recursos.TMB.flota_total = 800;

recursos.TMB.conductores = 1200;

recursos.FGC.flota_total = 150;

recursos.FGC.conductores = 300;


operador_linea = strings(n,1);

for i = 1:n

    if contains(nombre_linea_norm(i), "metro") || contains(nombre_linea_norm(i), "bus")

        operador_linea(i) = "TMB";

    elseif contains(nombre_linea_norm(i), "fgc")

        operador_linea(i) = "FGC";

    else

        operador_linea(i) = "TMB";

    end

end


lineas_TMB = operador_linea == "TMB";

lineas_FGC = operador_linea == "FGC";


vehiculos_TMB = floor(recursos.TMB.flota_total / sum(lineas_TMB)) * ones(sum(lineas_TMB),1);

vehiculos_FGC = floor(recursos.FGC.flota_total / sum(lineas_FGC)) * ones(sum(lineas_FGC),1);


vehiculos_disponibles = zeros(n,1);

vehiculos_disponibles(lineas_TMB) = vehiculos_TMB;

vehiculos_disponibles(lineas_FGC) = vehiculos_FGC;


oferta_maxima = vehiculos_disponibles * capacidad_vehiculo;


fprintf('\n--- OFERTA TEÓRICA POR LÍNEA ---\n');

for i = 1:n

    fprintf('%s (%s): Máx Vehículos = %d | Máx Oferta = %d pas/h\n', ...

        nombre_linea(i), operador_linea(i), vehiculos_disponibles(i), oferta_maxima(i));

end


%% BUCLE POR FRANJAS HORARIAS


for f = 1:length(franjas)

    

    franja = franjas{f};

    freq = frecuencia.(franja);

    

    demanda_franja = zeros(n,1);

    oferta_franja = freq * capacidad_vehiculo * ones(n,1);


    for i = 1:n

        match = strcmp(lineas_excel, nombre_linea_norm(i));

        if any(match)

            demanda_franja(i) = demanda_horaria{match, franja};

        else

            demanda_franja(i) = 0;

        end

    end


    diferencia = demanda_franja - oferta_franja;

    x_opt_round = round(demanda_franja / capacidad_vehiculo);

    oferta_opt_round = x_opt_round * capacidad_vehiculo;

    diferencia_round = demanda_franja - oferta_opt_round;


    %% OPTIMIZACIÓN AVANZADA CON LINPROG


    f_lp = abs(demanda_franja / capacidad_vehiculo - 1);

    A = [

        double(lineas_TMB)';

        double(lineas_FGC)';

        eye(n)

    ];

    b = [

        recursos.TMB.flota_total;

        recursos.FGC.flota_total;

        vehiculos_disponibles

    ];


    lb = zeros(n,1);

    ub = vehiculos_disponibles;


    options = optimoptions('linprog','Display','none');

    [x_lin, ~] = linprog(f_lp, A, b, [], [], lb, ub, options);

    x_opt_lin = round(x_lin);

    oferta_opt_lin = x_opt_lin * capacidad_vehiculo;

    diferencia_opt = demanda_franja - oferta_opt_lin;


    %% VISUALIZACIÓN Y GUARDADO


    figure('Name', franja, 'NumberTitle', 'off');

    bar([demanda_franja oferta_franja oferta_opt_round oferta_opt_lin diferencia_round diferencia_opt]);

    legend('Demanda','Oferta Actual','Oferta Round','Oferta LP','Dif Round','Dif LP');

    xticklabels(nombre_linea);

    xtickangle(45);

    ylabel('Pasajeros por hora');

    title(['Oferta vs Demanda - ' strrep(franja,'_',' ')]);

    grid on;

    saveas(gcf, ['oferta_vs_demanda_' franja '.png']);


    %% EXPORTAR EXCEL


    resumen = table(nombre_linea, operador_linea, demanda_franja, ...

        oferta_franja, oferta_opt_round, oferta_opt_lin, ...

        diferencia_round, diferencia_opt, ...

        'VariableNames', {'Linea','Operador','Demanda','Oferta_Actual','Oferta_Round','Oferta_LP','Dif_Round','Dif_LP'});


    writetable(resumen, ['resumen_' franja '.xlsx']);


    %% INFORME CONSOLA


    fprintf('\n=== %s ===\n', strrep(franja, '_', ' '));

    for i = 1:n

        fprintf('%s (%s): Demanda = %d | Actual = %d | Round = %d | LP = %d | DifLP = %+d\n', ...

            nombre_linea(i), operador_linea(i), demanda_franja(i), ...

            oferta_franja(i), oferta_opt_round(i), oferta_opt_lin(i), diferencia_opt(i));

    end

end


Comments

Popular posts from this blog

Intelligence, STT Speech to text, AI, and SIGINT

BIOMEDICAL ENGINEERING AND MAINTENANCE

European Intelligence: Theoretical Foundations and Strategic Challenges