Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
function varargout = showRecordsLive(varargin)
% SHOWRECORDSLIVE MATLAB code for showRecordsLive.fig
% SHOWRECORDSLIVE, by itself, creates a new SHOWRECORDSLIVE or raises the existing
% singleton*.
%
% H = SHOWRECORDSLIVE returns the handle to a new SHOWRECORDSLIVE or the handle to
% the existing singleton*.
%
% SHOWRECORDSLIVE('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in SHOWRECORDSLIVE.M with the given input arguments.
%
% SHOWRECORDSLIVE('Property','Value',...) creates a new SHOWRECORDSLIVE or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before showRecordsLive_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to showRecordsLive_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help showRecordsLive
% Last Modified by GUIDE v2.5 05-Nov-2015 13:42:19
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @showRecordsLive_OpeningFcn, ...
'gui_OutputFcn', @showRecordsLive_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before showRecordsLive is made visible.
function showRecordsLive_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to showRecordsLive (see VARARGIN)
% Choose default command line output for showRecordsLive
handles.output = hObject;
% UIWAIT makes showRecordsLive wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% A call to surf renders the peaks data in the axes, adding the surfaceplot
% handle to the handles structure:
handles.plot = plot(rand(1,1),rand(1,1),'-bo'); % "empty" x-y plot
set(handles.plot,'userdata',1);
% Get figure and axes handles
handles.guifig = gcf;
handles.axes = gca;
handles.pvName = 'not set';
% Define the timer function. The TimerFcn is automatically passed two inputs:
% a handle to the timer and some event data. When neither of the two inputs
% is needed, an anonymous function @(~,~) is used to absorb both.
handles.timer = timer(...
'ExecutionMode', 'fixedRate', ... % Run timer repeatedly
'Name', 'timer-1',... % ...
'Period', 1.0, ... % Initial period is 1 sec.
'TimerFcn', @(~,~)update_display(hObject, handles.guifig)); % Timer callback function
%Old version of declaring TimeFcn: 'TimerFcn', {@update_display, handles.guifig});
% Initialise y and x values, x axis tick labels and axis label
clearAndInitialisePlot (handles);
% Finally, a call to guidata saves the handles structure contents
guidata(hObject, handles);
% --- Outputs from this function are returned to the command line.
function varargout = showRecordsLive_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Edit functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% edit1 : name of PV/record variable
% edit2 : live view: time period for displaying data
% edit3 : historical view: period starting at
% edit4 : historical view: period ending at
function edit1_Callback(hObject, eventdata, handles)
% hObject handle to edit1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit1 as text
% str2double(get(hObject,'String')) returns contents of edit1 as a double
function edit1_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit2_Callback(hObject, eventdata, handles)
% hObject handle to edit2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit2 as text
% str2double(get(hObject,'String')) returns contents of edit2 as a double
function edit2_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit3_Callback(hObject, eventdata, handles)
% hObject handle to edit3 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit3 as text
% str2double(get(hObject,'String')) returns contents of edit3 as a double
function edit3_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit3 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function edit4_Callback(hObject, eventdata, handles)
% hObject handle to edit4 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: get(hObject,'String') returns contents of edit4 as text
% str2double(get(hObject,'String')) returns contents of edit4 as a double
function edit4_CreateFcn(hObject, eventdata, handles)
% hObject handle to edit4 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: edit controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Push button functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pushbutton1 : activate the live view
% pushbutton2 : activate the historical view
% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
if strcmp(get(handles.timer, 'Running'), 'off')
%set(handles.timer,'Period',tInterval);
clearAndInitialisePlot(handles);
start(handles.timer);
elseif strcmp(get(handles.timer, 'Running'), 'on')
%stop(handles.timer);
%set(handles.timer,'Period',1.0); % reset to default value
currentPV = handles.pvName;
newPV = get(handles.edit1,'string');
if strcmp(newPV, currentPV)
% The currently displayed PV is the same as after the button push.
% In this case, only the displayed time range is updated.
% Get the currently displayed data
y = get(handles.plot,'YData');
x = get(handles.plot,'XData');
% Calculate the NEW number of elements to be displayed
nElements = calcNumElements(handles);
% Reshape the data arrays according to the new number of elements
if ( nElements > size(y,2) )
% In case of a longer new period
yValues(size(y,2)+1:nElements) = nan;
yValues(1:size(y,2)) = y;
xValues = (1:nElements)';
elseif ( nElements < size(y,2) )
% In case of a shorter new period
yValues = y(1:nElements);
xValues = (1:nElements)';
else
% nothing changes
yValues = y;
xValues = x;
end
set(handles.plot,'YData',yValues,'XData',xValues);
% Adapt x axis to new time range
plottype = 'live';
setXaxis (plottype, nElements, xValues, handles);
%set(get(handles.axes,'YLabel'),'String','Was ist meine Einheit?');
else
% The currently displayed PV is different from the one after the button push.
clearAndInitialisePlot(handles);
end
end
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Check whether live view is on at the moment; if yes: switch it off before
% displaying data for a past period:
if strcmp(get(handles.timer, 'Running'), 'on')
stop(handles.timer);
end
% Plot data of a past/historical time period
plottype = 'historic';
meanOfWaveform = get(handles.checkbox1,'Value');
if meanOfWaveform==0
% No mean will be calculated
%plottype = 'historic';
calculateMeanOfWaveform = false;
else
% The mean of each waveform will be calculated
%plottype = 'waveform';
calculateMeanOfWaveform = true;
end
[x, y, nElements] = getDataFromArchiver (hObject, plottype, calculateMeanOfWaveform, handles);
set (handles.plot,'YData',y,'XData',x);
setXaxis (plottype, nElements, x, handles)
ylabel ('Was ist meine Einheit?')
% Um mehrere Waveforms übereinander plotten zu können, habe ich hier
% versucht das cell-Arrays zu speichern. Das funktioniert aber nicht, weil
% length(handles.plot) kleiner als size(yy) bzw. size(xx) ist. Eine Lösung
% könnte sein, dass man von vornherein z.B. 10000 Lineplots vorsehen
% müsste, die aber alle nicht geplottet werden, da die y-Werte NaNs sind.
% Dann müsste man, je nach Länge der darzustellenden Periode, die
% cell-Arrays xx und yy mit Waveform-Arrays erweitern bis das Limit von
% 10000 erreicht ist.
% (noch?) nicht:
% size(x)
% size(y)
% yy = cell(size(y,1),1);
% xx = cell(size(y,1),1);
% for i = 1 : size(y,1)
% yy{i} = y(i,:);
% xx{i} = 1:size(y,2);
% end
% size(xx)
% size(yy)
% disp('vorher');
% set(handles.plot,{'YData'},yy,'XData',xx);
% disp('nachher');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Pop-up menu functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% --- Executes on selection change in popupmenu2.
function popupmenu2_Callback(hObject, eventdata, handles)
% hObject handle to popupmenu2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: contents = cellstr(get(hObject,'String')) returns popupmenu2 contents as cell array
% contents{get(hObject,'Value')} returns selected item from popupmenu2
% --- Executes during object creation, after setting all properties.
function popupmenu2_CreateFcn(hObject, eventdata, handles)
% hObject handle to popupmenu2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles empty - handles not created until after all CreateFcns called
% Hint: popupmenu controls usually have a white background on Windows.
% See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
set(hObject, 'String', {'Select archiver','aa0', 'aa1'});
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Checkbox functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% --- Executes on button press in checkbox1.
function checkbox1_Callback(hObject, eventdata, handles)
% hObject handle to checkbox1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hint: get(hObject,'Value') returns toggle state of checkbox1
% 1 : box is checked
% 0 : box is NOT checked
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Close request functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function figure1_CloseRequestFcn
% Necessary to provide this function to prevent timer callback
% from causing an error after code stops executing.
% Before exiting, if the timer is running, stop it.
if strcmp(get(handles.timer, 'Running'), 'on')
stop(handles.timer);
end
% Destroy timer
delete(handles.timer)
% Destroy figure
delete(hObject);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Additional functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% update_display :
% timer callback function for updating the display in live view
% clearAndInitialisePlot :
% clear plot and initialise values and axes (tick) labels
% setXaxis :
% set x axis tick labels according to displayed time period
% numElements :
% calculate the number of elements to display
% getDataFromArchiver :
% get data from archiver for a specified period
% convertTimeToIsoformat :
% convert format of input time to a format required by the archiver
%function update_display (hObject, eventdata, handlesGuifig)
function update_display (hObject, handlesGuifig)
handles = guidata(handlesGuifig);
plottype = 'live';
meanOfWaveform = get(handles.checkbox1,'Value');
if meanOfWaveform==0
% No mean will be calculated
calculateMeanOfWaveform = false;
else
% The mean of each waveform will be calculated
calculateMeanOfWaveform = true;
end
[xValues, yValues, nElements] = getDataFromArchiver(hObject, plottype, calculateMeanOfWaveform, handles);
set(handles.plot,'YData',yValues,'XData',xValues);
function clearAndInitialisePlot (handles)
% Initialise x and y values
nElements = calcNumElements(handles);
yValues = nan(nElements,1);
xValues = (1:nElements)';
set(handles.plot,'YData',yValues,'XData',xValues);
% Initialise x axis tick labels and axis label
plottype = 'live';
setXaxis (plottype, nElements, xValues, handles);
set(get(handles.axes,'YLabel'),'String','Was ist meine Einheit?');
function setXaxis (plottype, numElem, x, handles)
switch plottype
case 'live'
nMinutes = numElem / 60;
set(gca, 'XTickMode', 'auto', 'XTickLabelMode', 'auto');
set(handles.axes,'XLim',[0 numElem]);
if ( nMinutes <= 2 )
set(handles.axes,'XTick', 0:10:120)
set(handles.axes,'XTickLabel', 0:10:120)
timeUnit = 'Seconds';
elseif ( nMinutes <= 20 )
set(handles.axes,'XTick', 0:120:1200)
set(handles.axes,'XTickLabel', 0:2:20)
timeUnit = 'Minutes';
elseif ( nMinutes <= 60 )
set(handles.axes,'XTick', 0:300:3600)
set(handles.axes,'XTickLabel', 0:5:60)
timeUnit = 'Minutes';
else
set(handles.axes,'XTick', 0:3600:86400)
set(handles.axes,'XTickLabel', 0:1:24)
timeUnit = 'Hours';
end
set(get(handles.axes,'XLabel'),'String',[timeUnit,' since now']);
case 'historic'
xFrom = date2seconds(convertTimeFormat(get(handles.edit3,'string')));
xTo = date2seconds(convertTimeFormat(get(handles.edit4,'string')));
xlim([xFrom xTo])
startDateTime = seconds2date(x(1));
period = xTo - xFrom; % period in seconds
if ( period <= 10 )
% period is shorter than 10 seconds
set(handles.axes,'XTick', xFrom:1:xFrom+10)
set(handles.axes,'XTickLabel', 0:1:10)
timeUnit = 'Seconds';
elseif ( period <= 60 )
% period is shorter than 1 minute
set(handles.axes,'XTick', xFrom:5:xFrom+60)
set(handles.axes,'XTickLabel', 0:5:60)
timeUnit = 'Seconds';
elseif ( period <= 600 )
% period is shorter than 10 minutes
set(handles.axes,'XTick', xFrom:60:xFrom+600)
set(handles.axes,'XTickLabel', 0:1:10)
timeUnit = 'Minutes';
elseif ( period <= 3600 )
% period is shorter than 1 hour
set(handles.axes,'XTick', xFrom:600:xFrom+3600)
set(handles.axes,'XTickLabel', 0:10:60)
timeUnit = 'Minutes';
elseif ( period > 3600 && period <= 86400 )
% 1 h < period < 24 hours
set(handles.axes,'XTick', xFrom:3600:xFrom+86400)
set(handles.axes,'XTickLabel', 0:1:24)
timeUnit = 'Hours';
elseif ( period > 86400 && period <= 2678400 )
% 1 day < period < 31 days
set(handles.axes,'XTick', xFrom:86400:xFrom+2678400)
set(handles.axes,'XTickLabel', 0:1:31)
timeUnit = 'Days';
elseif ( period > 2678400 && period <= 7257600 )
% 31 days < period < 12 weeks
set(handles.axes,'XTick', xFrom:604800:xFrom+7257600)
set(handles.axes,'XTickLabel', 0:1:12)
timeUnit = 'Weeks';
else
% period > 12 weeks
thirtyDaysInSeconds = 2592000;
set(handles.axes,'XTick', xFrom:thirtyDaysInSeconds:xFrom+period)
howManyMonthsInPeriod = period / thirtyDaysInSeconds;
set(handles.axes,'XTickLabel', 0:1:howManyMonthsInPeriod)
timeUnit = 'Months';
end
xlabel([timeUnit,' since ',startDateTime]);
%%% TO DO:
%case 'waveform'
% xlabel('Channels?');
end
function numElements = calcNumElements(handles)
updateFrequency = get(handles.timer,'Period'); % unit: seconds
liveViewPeriod = 60 * str2num(get(handles.edit2,'string')); % conversion from minutes to seconds
numElements = liveViewPeriod / updateFrequency; % number of elements/values to display
function [xValues, yValues, nElements] = getDataFromArchiver (hObject, plottype, calculateMeanOfWaveform, handles)
% Plot-type-specific part
switch plottype
case 'live'
% Get current time
currentTime = clock;
timeFrom = [num2str(currentTime(1)),'-',num2str(currentTime(2),'%02d'),'-',...
num2str(currentTime(3),'%02d'),'T',num2str(currentTime(4),'%02d'),':',...
num2str(currentTime(5),'%02d'),':',num2str(currentTime(6),'%6.3f'),'Z'];
timeTo = timeFrom;
yValues = get(handles.plot,'YData');
xValues = get(handles.plot,'XData');
nElements = calcNumElements(handles);
case {'historic', 'waveform'}
timeFrom = convertTimeFormat(get(handles.edit3,'string'));
timeTo = convertTimeFormat(get(handles.edit4,'string'));
otherwise
warning('Unexpected plot type. No plot created. Exiting now...')
return
end
% General part
pv = get(handles.edit1,'string');
handles.pvName = pv; % save the name of the PV for later usage
guidata(hObject, handles);
popup_sel_index = get(handles.popupmenu2,'Value');
switch popup_sel_index
case 1
disp('Error: Select "aao" or "aa1"');
return
case 2
archiver = 'aa0';
case 3
archiver = 'aa0s';
case 4
archiver = 'aa1';
end
url = ['http://',archiver,'.fhi-berlin.mpg.de:17668/retrieval/data/getData.mat'];
tempFile = 'temp.mat';
try
tStart = tic;
urlwrite(url,tempFile,'get',{'pv',pv,'from',timeFrom,'to',timeTo});
tElapsed = toc(tStart);
if ( strcmp(plottype,'historic')==1 || strcmp(plottype,'waveform')==1 )
% Print a message of how much time it took to retrieve the data from the archiver
timeMeasurement = ['Getting ',pv,' for period from ',get(handles.edit3,'string'),' to ',...
get(handles.edit4,'string'),' from archiver took ',num2str(tElapsed,'%8.3f'),' seconds'];
disp(timeMeasurement)
end
catch
disp('Error when executing urlwrite ...')
return
end
dat = load(tempFile);
%dat = load(tempFile,'-ascii');
delete(tempFile);
try
data = dat.data;
catch
disp('Could not get data from file ...');
return
end
% Error in case there is no data in the selected period
if ( isempty(data.values) )
warning('No data available in the selected period. Exiting now...')
return
end
% Distinguish between waveforms and one-value-per-timestep PVs
if ( size(data.values,2) > 1 )
%switch plottype
% case 'historic'
% % Calculate the mean (default)
% y = mean(data.values(:,1:end-2),2);
% case 'waveform'
% % Show whole waveform per time step
% y = data.values(:,1:end-2);
%end
if ( calculateMeanOfWaveform )
% Calculate the mean (default)
mi = min(data.values(:,1:end-2),2);
y = mean(data.values(:,1:end-2),2);
ma = max(data.values(:,1:end-2),2);
%disp(['min=',num2str(mi),' mean=',num2str(y),' max=',num2str(ma)])
else
% Show whole waveform per time step
y = data.values(:,1:end-2);
end
else
y = data.values;
end
%disp(['Number of samples retrieved from archiver: ',num2str(numel(y))])
switch plottype
case 'live'
%latestValue = y*rand(1,1); % Nur zum TESTEN
latestValue = y;
yValues(2:nElements) = yValues(1:nElements-1);
yValues(1) = latestValue;
case 'historic'
% Add seconds and nano seconds
x = double(data.epochSeconds)+double(data.nanos)*10^-9;
% trim and/or extend the time series so that it matches the specified
% length of the time period to be displayed
%if ( x(1) < date2seconds(timeFrom) )
% y = y(x>date2seconds(timeFrom));
% x = x(x>date2seconds(timeFrom));
%end
if ( x(1) > date2seconds(timeFrom) )
x = [date2seconds(timeFrom); x];
y = [y(1); y];
end
%if ( x(end) < date2seconds(timeTo) )
% x = [x; date2seconds(timeTo)];
% y = [y; y(end)];
%end
yValues = y;
xValues = x;
nElements = size(y,1);
case 'waveform'
yValues = y;
xValues = repmat(1:size(y,2),size(y,1),1);
nElements = size(y,1);
end
function formattedTime = convertTimeFormat (time)
% Check whether input matches the expected format:
% ...
% Format the time
formattedTime = [time(1:4),'-',time(6:7),'-',time(9:10),'T',time(12:16),':',time(18:19),'.000Z'];