Accessing parsim data in Matlab - matlab

Good evening, May I please get advice with the following Matlab code? Here it is:
%% CLEAR ALL
close all
clear all
clc
%% LOAD MODEL AND LHC FILE
tic %start the clock
idx=1;
model = 'PG_PN_basic_rev1'; %This is the simulink file you wish to run.
load_system(model);
load 'LHC_input.mat' %Call in the file created by LHC_Final.m
LHC = (LHC1_input);
k_dc = LHC((1:5),1);
k_r = LHC((1:5),2);
a_1 = LHC((1:5),3);
b_1 = LHC((1:5),4);
Kg_PG = LHC((1:5),5);
Kg_PN = LHC((1:5),6);
for i = length(k_dc):-1:1
in(i) = Simulink.SimulationInput('PG_PN_basic_rev1');
in(i) = in(i).setVariable('k_dc',k_dc(i));
for j = length(k_r):-1:1
in(j) = in(j).setVariable('k_r',k_r(j));
for k = length(a_1):-1:1
in(k) = in(k).setVariable('a_1',a_1(k));
for l = length(b_1):-1:1
in(l) = in(l).setVariable('b_1',b_1(l));
for m = length(Kg_PG):-1:1
in(m) = in(m).setVariable('Kg_PG',Kg_PG(m));
for n = length(Kg_PN):-1:1
in(n) = in(n).setVariable('Kg_PN',Kg_PN(n));
end
end
end
end
end
end
out = parsim(in, 'ShowProgress', 'on');
% eval(['PN_batch', int2str(idx),' =PN;']);
% data = eval(['PN_batch', int2str(idx)]);
% a{idx} = data;
% idx=idx+1;
% run = idx
timeElapsed = toc %How long did you code run for?
I wish to be able to generate an output file per parsim run (PN_batch1, PN_batch2,...etc.). However, the data often falls under just 1 output, and isn't divided up into readable workspace objects that I can read later with another script. Any advice would be greatly appreciated. Thank you.

out is a vector of length equal to the number of simulations with the data of a simulation stored in each entry. If you have to workspace blocks in your model, you can access that data per simulation using out(10).NameOftoWorkspaceData, in case you want to get the data of the 10th simulation. More info on the out variable can be found here on the Mathworks site.
Tip: run the model and check out the variable out, then you can explore its structure

Related

MATLAB time duration in milliseconds from an excel file

I am making a Matlab program that uses data from an excel file designated from an open file dialog.
[filename, pathname] = uigetfile({'*.xlsx','Excel Files(*.xlsx)'; '*.txt','Txt Files(*.txt)'}, 'Pick a file');
FilePath = append(pathname,filename);
opts = detectImportOptions(FilePath, "ReadVariableNames", false);
opts = setvartype(opts, 1, 'char');
data = readtable(FilePath, opts);
table = data(:,1);
Now the code is like this.
enter image description here
After that, as you see the date is saved as string.
But what I really want to find is time difference (duration) in milliseconds.
The raw data looks like this:
enter image description here
A column and C column has the same time, so I want to only use A column data.
Please help a newbie with this!! I appreciate!
Problem resolved.
I share my code to help other people suffering the same problem.
Please leave comments if things can be more simplified.
Importing an Excel file to analyze
% Clean the memory and the code previously running
clc;
clear all;
close all;
% Sampling frequency of the acquired data
fs = 1e2; % Sampling Frequency - this can be found on LabView code.
Ts = 1/fs; % Sampling Interval
%Importing data from an excel file
[filename, pathname] = uigetfile({'*.xlsx','Excel Files(*.xlsx)'; '*.txt','Txt Files(*.txt)'}, 'Pick a file');
FilePath = append(pathname,filename);
[fPath ,fName, fExt] = fileparts(FilePath);
a. To find "Time duration" from the file
opts = spreadsheetImportOptions("NumVariables", 1);
% Specify sheet and range
opts.Sheet = "sheet1";
opts.DataRange = "A2";
% Specify column names and types
opts.VariableNames = "Time";
opts.VariableTypes = "datetime";
% Specify file level properties
opts.ImportErrorRule = "omitrow";
opts.MissingRule = "omitrow";
% Specify variable properties
opts = setvaropts(opts, "Time", "InputFormat", 'mm:ss.SSS');
tTable = readtable(FilePath, opts, "UseExcel", false);
tArray = table2array(tTable);
% Calculating time duration
tArray = tArray - tArray(1);
% Coverting to seconds
time = milliseconds(tArray)*1e-3;
% Clear temporary variables
clear opts;
% Discarding data if time difference is too big
ii = size(time(:,1));
k = 0;
disp('Now removing error data elements');
for i = 1:1:ii(1)-1
a = time(i);
b = time(i+1);
if (b-a)>0.5 && k==0
k=i+1;
fprintf('Elements from %d seconds will be removed. (%dth element)\n', time(k),k);
for j = ii(1):-1:k
if rem(j,10)==0
fprintf('%dth element is removed... \n',j);
end
time(j) = [];
end
break % Break the loop after removing error data
end
end
disp('Time table is set.');
clearvars -except filename FilePath fs pathname time k ii Ts fName
I created a similar excel file and I found the time columns are read as a char. So, what I did is get the index of those columns and convert it to datatime. After that, looks that it is working. Hopefully, this works.
% Define the excel file name (can be the path)
ExcelFile = 'demo_stackflow.xlsx';
% Get the options for that sheet and preserving the variable name
opts = detectImportOptions(ExcelFile,'Sheet','Sheet1',...
"VariableNamingRule","preserve")
% Get the idx where the variable is a char (In this case col 1 and 3)
CharVars = opts.VariableNames(contains(opts.VariableTypes,'char'));
% Convert the char columns to datetime
opts = setvaropts(opts,CharVars,'Type',"datetime");
% Get the data
data = readtable(ExcelFile, opts)
% Print the 1st column to see if the data type of the column is
% datetime
T = data(:,1)

How to do an animate plot in MATLAB from a sequence of matrices

I have code that uses Wolff's Algorithm to simulate the XY Model in MATLAB and I want to implement a pcolor/color map to demonstrate each spin according to their angles across the system. But I want it to be live and changing as the angles change.
Any idea how to do this?
This is an example of how I want it to look https://i.stack.imgur.com/aSp7s.png
If you save each snapshot of the lattice in a cell array A{t}, you can use the following function to view and save it as a video (if fileName is not empty, the function saves an mp4 video).
Another option is to adapt the function view_lattice to run your simulation (which, honestly, I wouldn't recommend, for performance issues). I will mark where you should edit for doing a "live" simulation
This is at least MATLAB R2019b (although it may be compatible with earlier versions, but no guarantee).
File view_lattice.m
function view_lattice(A,fileName)
% for a 'live' simulation, you will have to remove A from the input
% parameters and add the ones you need for the XY Wolff algorithm,
% which will be used to calculate each configuration A in the time loop below
% you will also need to remove the assert statements for 'live' simulation
%
% otherwise, you save snapshots from your simulation
% and use this function as is
%
% A -> A{k}[m,n] snapshot k containing the angles of spins in lattice site at row m and col n
% fileName -> if contains string, then records a video with the snapshots and name it with this string
assert(iscell(A) && all(cellfun(#(a)isnumeric(a) && ismatrix(a),A)),'A must be cell of numeric matrices');
assert(ischar(fileName),'fileName must be either an empty char or contain a file name');
recordVideo = ~isempty(fileName);
if recordVideo
vw = setup_video(fileName);
else
vw = [];
end
% setting some default axis properties to speed-up plotting
set(0,'DefaultAxesPlotBoxAspectRatio',[1 1 1],'DefaultAxesDataAspectRatioMode','manual','DefaultAxesDataAspectRatio',[1,1,1],'DefaultAxesNextPlot','replace');
fh = figure;
ax=axes;
for t = 1:numel(A) % for 'live' simulation, this loop should be the time loop
% here you calculate the new configuration A
% and call the function below with A instead of A{t}
vw = record_frame(vw,fh,ax,A{t},t,recordVideo);
end
% any video to close?
if recordVideo
vw.close();
end
end
function vw = record_frame(vw,fh,ax,A,t,recordVideo)
imagesc(ax,A);
title(ax,sprintf('snapshot %g',t)); % if you want, y
axis(ax,'square');
daspect(ax,[1,1,1]);
pause(0.01);
if recordVideo
vframe = getframe(fh);
vw.writeVideo(vframe);
end
end
function vw = setup_video(fileName)
vid_id = num2str(rand,'%.16g');
vid_id = vid_id(3:6);
vid_id = [fileName,'_',vid_id];
% Initialize video
vw = VideoWriter([vid_id,'.mp4'], 'MPEG-4'); %open video file
vw.Quality = 100;
vw.FrameRate = 16;
vw.open();
end
Test script: test.m
clearvars
close all
A = cell(1,30);
for t = 1:numel(A)
% creating a sequence of random snapshots only for illustration
A{t} = rand(20,20);
end
% viewing the animation and saving it as a video with name test
view_lattice(A,'test');
Output

How to add standrad deviation and moving average

What I want to is:
I got folder with 32 txt files and 1 excle file, each file contain some data in two columns: time, level.
I already managed to pull the data from the folder and open each file in Matlab and get the data from it. What I need to do is create plot for each data file.
each of the 32 plots should have:
Change in average over time
Standard deviation
With both of this things I am straggling can't make it work.
also I need to make another plot this time the plot should have the average over each minute from all the 32 files.
here is my code until now:
clc,clear;
myDir = 'my path';
dirInfo = dir([myDir,'*.txt']);
filenames = {dirInfo.name};
N = numel(filenames);
data=cell(N,1);
for i=1:N
fid = fopen([myDir,filenames{i}] );
data{i} = textscan(fid,'%f %f','headerlines',2);
fclose(fid);
temp1=data{i,1};
time=temp1{1};
level=temp1{2};
Average(i)=mean(level(1:find(time>60)));
AverageVec=ones(length(time),1).*Average(i);
Standard=std(level);
figure(i);
plot(time,level);
xlim([0 60]);
hold on
plot(time, AverageVec);
hold on
plot(time, Standard);
legend('Level','Average','Standard Deviation')
end
the main problam with this code is that i get only average over all the 60 sec not moving average, and the standard deviation returns nothing.
few things you need to know:
*temp1 is 1x2 cell
*time and level are 22973x1 double.
Apperently you need an alternative to movmean and movstd since they where introduced in 2016a. I combined the suggestion from #bla with two loops that correct for the edge effects.
function [movmean,movstd] = moving_ms(vec,k)
if mod(k,2)==0,k=k+1;end
L = length(vec);
movmean=conv(vec,ones(k,1)./k,'same');
% correct edges
n=(k-1)/2;
movmean(1) = mean(vec(1:n+1));
N=n;
for ct = 2:n
movmean(ct) = movmean(ct-1) + (vec(ct+n) - movmean(ct-1))/N;
N=N+1;
end
movmean(L) = mean(vec((L-n):L));
N=n;
for ct = (L-1):-1:(L-n)
movmean(ct) = movmean(ct+1) + (vec(ct-n) - movmean(ct+1))/N;
N=N+1;
end
%mov variance
movstd = nan(size(vec));
for ct = 1:n
movstd(ct) = sum((vec(1:n+ct)-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(n+ct-1);
end
for ct = n+1:(L-n)
movstd(ct) = sum((vec((ct-n):(ct+n))-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(k-1);
end
for ct = (L-n):L
movstd(ct) = sum((vec((ct-n):L)-movmean(ct)).^2);
movstd(ct) = movstd(ct)/(L-ct+n);
end
movstd=sqrt(movstd);
Someone with matlab >=2016a can compare them using:
v=rand(1,1E3);m1 = movmean(v,101);s1=movstd(v,101);
[m2,s2] = moving_ms(v,101);
x=1:1E3;figure(1);clf;
subplot(1,2,1);plot(x,m1,x,m2);
subplot(1,2,2);plot(x,s1,x,s2);
It should show a single red line since the blue line is overlapped.

Matlab: Working for-loop breaks in parfor while fitting curves

Hoping you may be able to assist me with this error. I am running some code to fit curves to ages using a cross validation regime. I iterate the curve fitting 1000 times to assess the best fit.
I define my models as:
linear_ft = fittype({'x', '1'});
monotonic_ft= fittype({'-1/x', '1'});
quadratic_ft = fittype('poly2');
I then run the following to iterate through different selections of data splitting, recording the residuals following the curve fit...
Data = randn(4,300,10,10);
Ages = randn(300,1);
for thisDim1 = 1:4
for thisDim2 = 1:10
for thisDim3 = 1:10
for nIts = 1:1000
RandomOrder = randperm(300,300);
Fit_Subs = RandomOrder(1:length(Ages)/2); % Take random subs to fit to
Test_Subs = RandomOrder(length(Ages)/2+1:300); % Take random subs to test fit to
Fit_Data = squeeze(Data(thisDim1,Fit_Subs,thisDim2,thisDim3)); % Take data to fit to
Test_Data = squeeze(Data(thisDim1,Test_Subs,thisDim2,thisDim3)); % Take data to test fit
Fit_Ages = Ages;
Fit_Ages(Fit_Subs) = []; %Take ages of Fit Subs only
Test_Ages = Ages;
Test_Ages(Test_Subs) = []; % Take ages of Test Subs only
Nsubs = (length(Ages)/2);
% Model Data using Curves
fFit_Lin = fit(Fit_Ages,Fit_Data',linear_ft);
fFit_Mon = fit(Fit_Ages,Fit_Data',monotonic_ft);
fFit_Quad = fit(Fit_Ages,Fit_Data',quadratic_ft);
% Fit Modelled Data to Test Data
tFit_Lin = fFit_Lin(Test_Ages);
tFit_Mon = fFit_Mon(Test_Ages);
tFit_Quad = fFit_Quad(Test_Ages);
% Calculate Median Residual
Lin_Med_Resid(nIts) = median(tFit_Lin - Test_Data');
Mon_Med_Resid(nIts) = median(tFit_Mon - Test_Data');
Quad_Med_Resid(nIts) = median(tFit_Quad - Test_Data');
end
end
end
end
If you run this with the fourth loop (nIts) as a for-loop it will run. If you run it as a parfor-loop it won't stating the error:
Error using fit>iFit (line 264)
The name 'lower' is not an accessible property for an instance of class
'llsqoptions'.
Error in fit (line 108) [fitobj, goodness, output, convmsg] = iFit(
xdatain, ydatain, fittypeobj, ...
Does anyone have any idea how to fix this? I would be most grateful for any advice!!
Thanks,
Ben
Try restarting MATLAB or typing clear all to see if it clears things up for you.
Your code works for me, but the parallel toolbox can be a bit finicky in my experience.

Read multiple files with for loop

My code is below. In the code, I am evaluating only the data in the 'fb2010' file. I want to add other files" 'fb2020', 'fb2030', and 'fb2040' and evaluate their data by the same code. My question is how to apply a for loop and include the other data files. I tried, but I got confused by the for loop.
load('fb2010'); % loading the data
x = fb2010(3:1:1502,:);
% y_filt = filter(b,a,x); % filtering the received signal
y_filt= filter(b,a,x,[],2);
%%%%%%% fourier transform
nfft = length(y_filt);
res = fft(y_filt,nfft,2)/nfft;
res2 = res(:,1:nfft/2+1); %%%% taking single sided spectrum
res3 = fft(res2,[],2);
for i = 3:1:1500 %%%% dividing each row by first row.
resd(i,:) = res3(i,:)./res3(1,:);
end
I'm assuming that your files are MAT-files, not ASCII. You can do this by having load return a struct and using dynamic field referencing:
n = 4;
for i = 1:n
vname = ['fb20' int2str(i) '0']; % Create file/variable name based on index
s = load(vname); % Load data as struct (overwriting previous s)
x = s.(vname)(3:1:1502,:); % Access struct with dynamic field reference
% Rest of your code
...
end
If you're using a plain ASCII file, load won't produce a struct. However, such files are much simpler (see documentation for load/save). The following code would probably work:
n = 4;
for i = 1:n
vname = ['fb20' int2str(i) '0']; % Create file/variable name based on index
s = load(vname); % Load data as matrix (overwriting previous s)
x = s(3:1:1502,:); % Directly index matrix
% Rest of your code
...
end
It would be a good idea to add the file extension to your load command to make your code more readable.