% BTM  Example: Creating a struct

clear all, close all, clc;

% Make a single array of data and store in a structure (struct)

% Check out linspace, ' operator, and random in the manual

times  = linspace(1,10,10)';   
values = random('norm', 65, 20, length(times), 1);

%% Define a struct 'data' that will hold 2 arrays (temperature data
% and times when measured) and 3 scalars

data = struct('t', [], 'temp', [], 'max', 0, 'min', 0, 'mean', 0);

% Populate the struct

data.t    = times;
data.temp = values;

% Store the maximum, minimum, and average temperatures of the dataset 

data.max  = max(data.temp);     
data.min  = min(data.temp);
data.mean = mean(data.temp);

%% Now let's assume we collected data at multiple sites. Would be nice to
%  store all of this in a single data structure, wouldn't it? Well, you can
%  use a cell array or an array of structs.

% First let's do it using a cell array

cell_stations = cell(5, 1);

% Let us assume you know what a for loop is, we're creating artificial 
% data for 5 'stations' in a cell array of structs

temporary = ...    % '...' == command continues next line. 
    struct('t', [], 'temp', [], 'max', 0, 'min', 0, 'mean', 0); 

for i = 1:5,
    temporary = ...    % '...' == command continues next line. 
           struct('t', [], 'temp', [], 'max', 0, 'min', 0, 'mean', 0); 

    temporary.t    = times;                                        %populate array of structs at index i
    temporary.temp = random('norm', 65, 20, length(times), 1);     %note that it's already defined 
    temporary.max  = max(temporary.temp);                 %before the loop.
    temporary.min  = min(temporary.temp);
    temporary.mean = mean(temporary.temp);

    cell_stations{i}        = temporary;                           %store this struct in cell array too...
end

% Now do the same using a struct array

struct_stations(1:5) = ...    % '...' == command continues next line. 
    struct('t', [], 'temp', [], 'max', 0, 'min', 0, 'mean', 0); 
                              % this defines an array of structs of size 5
for i = 1:5,
    struct_stations(i).t    = times;                                        %populate array of structs at index i
    struct_stations(i).temp = random('norm', 65, 20, length(times), 1);     %note that it's already defined 
    struct_stations(i).max  = max(struct_stations(i).temp);                 %before the loop.
    struct_stations(i).min  = min(struct_stations(i).temp);
    struct_stations(i).mean = mean(struct_stations(i).temp);
end


%%  Access the arrays so we can see what we made

cell_array_3_max = cell_stations{3}.max 
struct_array_3_max = struct_stations(3).max

% Calculate average maximum temperature over all stations using struct
% array ... note that you have to create an array on the fly:

means_struct_array = mean([struct_stations(:).max])

% that does not work with cell arrays. The following will fail:
%means = mean(cell_stations{:}.max)

%% SIDE TRACKS -- for advanced users

%% SIDE TRACK START - STRUCT TO CELL AND CELL 2 STRUCT CONVERSIONS

%we can convert this to a cell array (we loose the fieldnames):
data_cell = struct2cell(data);

%accessing the maximum temperature field for struct:
data_max = data.max

%... and for the cell _array_
cell_3 = data_cell{3}

% Hence, for a cell array, you've gotta know what is in which field, then 
% you can convert back:
fieldnames = {'t', 'temp', 'max', 'min', 'mean'};  %notice: it must be a cell array, 
                                                   %because the strings are of different lengths
data_struct = cell2struct(data_cell, fieldnames, 1);

%% SIDE TRACK END


%% SIDE TRACK START

% work around: create array of structs from cell array treat accordingly,
% keep in mind though that this will only work when ALL fields in the cell
% array of structs are the same! USUALLY you use a cell array to organize
% data of different types and then this method will fail!

tmp_struct_array = [cell_stations{:}];
means_complicated = mean([tmp_struct_array(:).max])

%% SIDE TRACK END

