Search code examples
matlabplottime-seriesdatetime-conversion

Convert milliseconds into hours and plot


I'm trying to convert an array of milliseconds and its respective data. However I want to do so in hours and minutes.

Millis = [60000 120000 180000 240000....]
Power = [ 12 14 12 13 14 ...]

I've set it up so the data records every minute, hence the 60000 millis (= 1 minimte). I am trying to plot time on the x axis and power on the y. I would like to have the x axis displayed in hours and minutes with each respective power data corresponding to its respective time.

I've tried this

for i=2:length(Millis)
Conv2Min(i) = Millis(i) / 60000;
Time(i) = startTime + Conv2Min(i);
if (Time(i-1) > Time(i) + 60)
Time(i) + 100;
end

end
s = num2str(Time);

This in attempt to turn the milliseconds into hours starting at 08:00 and once 60 minutes have past going to 09:00, the problem is plotting this. I get a gap between 08:59 and 09:00. I also cannot maintain the 0=initial 0.


Solution

  • In this scenario it is preferable to work with datenum values and then use datetick to set the format of the tick labels of your plot to 'HH:MM'.

    Let's suppose that you started taking measurements at t_1 = [HH_1, MM_1] and stopped taking measurements at t_2 = [HH_2, MM_2].

    A cool trick to generate the array of datenum values is to use the following expression:

    time_datenums = HH_1/24 + MM_1/1440 : 1/1440 : HH_2/24 + MM_2/1440;
    

    Explanation:

    We are creating a regularly-spaced vector time_datenums = A:B:C using the colon (:) operator, where A is the starting datenum value, B is the increment between datenum values and C is the ending datenum value.

    Since your measurements have been taken every minute (60000 milliseconds), then the increment between datenum values should be of 1 minute too. As a day has 24 hours, that makes 1440 minutes a day, so use B = 1/1440 as the increment between vector elements, to get 1 minute increments.

    For A and C we simply need to divide the hour digits by 24 and the minute digits by 1440 and sum them up like this:

    • A = HH_1/24 + MM_1/1440
    • C = HH_2/24 + MM_2/1440

    So for example, if t_1 = [08, 00], then A = 08/24 + 00/1440. As simple as that.

    Notice that this procedure doesn't use the datenum function at all, and still, it manages to generate a valid array of datenum values only taking into consideration the time of the datenum, without needing to bother about the date of the datenum. You can learn more about this here and here.


    Going back to your original problem, let's have a look at the code:

    time_millisec = 0:60000:9e6;             % Time array in milliseconds.
    power = 10*rand(size(time_millisec));    % Random power data.
    
    % Elapsed time in milliseconds.
    elapsed_millisec = time_millisec(end) - time_millisec(1); 
    % Integer part of elapsed hours.
    elapsed_hours_int = fix(elapsed_millisec/(1000*60*60));
    % Fractional part of elapsed hours.
    elapsed_hours_frac = (elapsed_millisec/(1000*60*60)) - elapsed_hours_int;
    
    t_1 = [08, 00]; % Start time 08:00
    t_2 = [t_1(1) + elapsed_hours_int, t_1(2) + elapsed_hours_frac*60]; % Compute End time.
    
    HH_1 = t_1(1); % Hour digits of t_1
    MM_1 = t_1(2); % Minute digits of t_1
    
    HH_2 = t_2(1); % Hour digits of t_2
    MM_2 = t_2(2); % Minute digits of t_2
    
    time_datenums = HH_1/24+MM_1/1440:1/1440:HH_2/24+MM_2/1440; % Array of datenums.
    
    plot(time_datenums, power);    % Plot data.
    datetick('x', 'HH:MM');        % Set 'HH:MM' datetick format for the x axis.
    

    This is the output:

    plot with dateticks in 'HH:MM? format