pythonmatlab

convert arrival and departure dates into power requirement profile


I have the arrival and departure dates of ships arriving at ports consuming power while berthing. I just want to accumulate their power requirement to know the total consumed power at port per minute.

For example:

Ship1 arrives 1/1/2019 at 02:10 and departs at 1/1/2019 at 22:25 and needs 100 kW.

Ship2 arrives 1/1/2019 at 16:35 and departs at 2/1/2019 at 08:10 and needs 150 kW. and so on.

I want to know the required power to be supplied by the port to them with time in minutes for example. So, I can have the total supplied power by the port to ships on y-axis in kW and time in minutes on the y-axis. Is there a smart way to do this in MATLAB or Python ? Many thanks in advance


Solution

  • Regardless of the programming language, the idea is simply to convert the difference array to the original array.

    To be specific, assume the data is structured in Python like

    data = [
        (datetime(2019, 1, 1, 2, 10), datetime(2019, 1, 1, 22, 25), 100),
        (datetime(2019, 1, 1, 16, 35), datetime(2019, 1, 2, 8, 10), 150)
    ]
    

    The following codes get the time and power when a ship arrives or leaves,

    from itertools import accumulate
    from collections import defaultdict
    import matplotlib.pyplot as plt
    
    # Compute changes of power
    dic = defaultdict(int)
    for arrive, depart, power in data:
        dic[arrive] += power
        dic[depart] -= power
    
    # Sort by date
    x, y = zip(*sorted(dic.items(), key=lambda i: i[0]))
    
    # Convert to original power
    y = accumulate((0,) + y)
    
    # Plot
    plt.plot(
        [t for t in x for _ in range(2)],
        [p for p in y for _ in range(2)][1:-1],
        'o-'
    )
    

    ... or in Matlab (duplicated timestamps are not removed for simplicity):

    % Changes of power
    x = [T.arrive; T.depart];
    y = [T.power; -T.power];
    
    % Sort by date
    [x,I] = sort(x);
    y = y(I);
    
    % Convert to original power
    y = cumsum(y);
    
    % Plot
    stairs(x, y, 'o-');
    

    result:

    result1

    Alternatively, if you need the power of every minute, do

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.DataFrame(data, columns=('arrive', 'depart', 'power'))
    xmin = df.arrive.min() - np.timedelta64(4, 'h')
    xmax = df.depart.max() + np.timedelta64(4, 'h')
    x = np.arange(xmin, xmax, np.timedelta64(1, 'm'))
    
    y = np.zeros(x.shape)
    np.add.at(y, (df.arrive - xmin).to_numpy().astype('timedelta64[m]').astype(int), +df.power)
    np.add.at(y, (df.depart - xmin).to_numpy().astype('timedelta64[m]').astype(int), -df.power)
    
    y = np.cumsum(y)
    
    plt.plot(x, y, 'o-')
    

    ... or in Matlab:

    xmin = min(T.arrive) - hours(4);
    xmax = max(T.depart) + hours(4);
    x = xmin:minutes(1):xmax;
    
    y = zeros(size(x));
    arrive_inds = minutes(T.arrive - xmin) + 1;
    depart_inds = minutes(T.depart - xmin) + 1;
    for i = 1:height(T)
        y(arrive_inds(i)) = y(arrive_inds(i)) + T.power(i);
        y(depart_inds(i)) = y(depart_inds(i)) - T.power(i);
    end
    
    y = cumsum(y);
    
    plot(x, y, 'o-');
    

    result:

    result2